Skip to content

Commit 379a3d4

Browse files
Merge pull request #55302 from nextcloud/backport/55134/stable31
2 parents a220a9e + 71d84c6 commit 379a3d4

File tree

7 files changed

+15
-371
lines changed

7 files changed

+15
-371
lines changed

apps/settings/src/components/PersonalInfo/AvatarSection.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,7 @@ export default {
182182
if (data.status === 'success') {
183183
this.handleAvatarUpdate(false)
184184
} else if (data.data === 'notsquare') {
185-
const tempAvatar = generateUrl('/avatar/tmp') + '?requesttoken=' + encodeURIComponent(OC.requestToken) + '#' + Math.floor(Math.random() * 1000)
186-
this.$refs.cropper.replace(tempAvatar)
185+
this.$refs.cropper.replace(data.image)
187186
this.showCropper = true
188187
} else {
189188
showError(data.data.message)

build/integration/features/avatar.feature

Lines changed: 5 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -21,32 +21,9 @@ Feature: avatar
2121
And last avatar is a square of size 512
2222
And last avatar is not a single color
2323

24-
25-
26-
Scenario: get temporary non-square user avatar before cropping it
27-
Given Logging in using web as "user0"
28-
And logged in user posts temporary avatar from file "data/coloured-pattern-non-square.png"
29-
When logged in user gets temporary avatar
30-
Then The following headers should be set
31-
| Content-Type | image/png |
32-
# "last avatar" also includes the last temporary avatar
33-
And last avatar is not a square
34-
And last avatar is not a single color
35-
36-
Scenario: get non-square user avatar before cropping it
37-
Given Logging in using web as "user0"
38-
And logged in user posts temporary avatar from file "data/coloured-pattern-non-square.png"
39-
# Avatar needs to be cropped to finish setting it
40-
When user "user0" gets avatar for user "user0"
41-
Then The following headers should be set
42-
| Content-Type | image/png |
43-
| X-NC-IsCustomAvatar | 0 |
44-
And last avatar is a square of size 512
45-
And last avatar is not a single color
46-
4724
Scenario: set square user avatar from file
4825
Given Logging in using web as "user0"
49-
When logged in user posts temporary avatar from file "data/green-square-256.png"
26+
When logged in user posts avatar from file "data/green-square-256.png"
5027
And user "user0" gets avatar for user "user0"
5128
And The following headers should be set
5229
| Content-Type | image/png |
@@ -64,7 +41,7 @@ Feature: avatar
6441
Scenario: set square user avatar from internal path
6542
Given user "user0" uploads file "data/green-square-256.png" to "/internal-green-square-256.png"
6643
And Logging in using web as "user0"
67-
When logged in user posts temporary avatar from internal path "internal-green-square-256.png"
44+
When logged in user posts avatar from internal path "internal-green-square-256.png"
6845
And user "user0" gets avatar for user "user0" with size "64"
6946
And The following headers should be set
7047
| Content-Type | image/png |
@@ -78,82 +55,21 @@ Feature: avatar
7855
And last avatar is a square of size 64
7956
And last avatar is a single "#00FF00" color
8057

81-
Scenario: set non-square user avatar from file
82-
Given Logging in using web as "user0"
83-
When logged in user posts temporary avatar from file "data/coloured-pattern-non-square.png"
84-
And logged in user crops temporary avatar
85-
| x | 384 |
86-
| y | 256 |
87-
| w | 128 |
88-
| h | 128 |
89-
Then logged in user gets temporary avatar with 404
90-
And user "user0" gets avatar for user "user0"
91-
And The following headers should be set
92-
| Content-Type | image/png |
93-
| X-NC-IsCustomAvatar | 1 |
94-
And last avatar is a square of size 512
95-
And last avatar is a single "#FF0000" color
96-
And user "anonymous" gets avatar for user "user0"
97-
And The following headers should be set
98-
| Content-Type | image/png |
99-
| X-NC-IsCustomAvatar | 1 |
100-
And last avatar is a square of size 512
101-
And last avatar is a single "#FF0000" color
102-
103-
Scenario: set non-square user avatar from internal path
104-
Given user "user0" uploads file "data/coloured-pattern-non-square.png" to "/internal-coloured-pattern-non-square.png"
105-
And Logging in using web as "user0"
106-
When logged in user posts temporary avatar from internal path "internal-coloured-pattern-non-square.png"
107-
And logged in user crops temporary avatar
108-
| x | 704 |
109-
| y | 320 |
110-
| w | 64 |
111-
| h | 64 |
112-
Then logged in user gets temporary avatar with 404
113-
And user "user0" gets avatar for user "user0" with size "64"
114-
And The following headers should be set
115-
| Content-Type | image/png |
116-
| X-NC-IsCustomAvatar | 1 |
117-
And last avatar is a square of size 64
118-
And last avatar is a single "#00FF00" color
119-
And user "anonymous" gets avatar for user "user0" with size "64"
120-
And The following headers should be set
121-
| Content-Type | image/png |
122-
| X-NC-IsCustomAvatar | 1 |
123-
And last avatar is a square of size 64
124-
And last avatar is a single "#00FF00" color
125-
126-
Scenario: cropped user avatar needs to be squared
127-
Given Logging in using web as "user0"
128-
And logged in user posts temporary avatar from file "data/coloured-pattern-non-square.png"
129-
When logged in user crops temporary avatar with 400
130-
| x | 384 |
131-
| y | 256 |
132-
| w | 192 |
133-
| h | 128 |
134-
135-
136-
13758
Scenario: delete user avatar
13859
Given Logging in using web as "user0"
139-
And logged in user posts temporary avatar from file "data/coloured-pattern-non-square.png"
140-
And logged in user crops temporary avatar
141-
| x | 384 |
142-
| y | 256 |
143-
| w | 128 |
144-
| h | 128 |
60+
And logged in user posts avatar from file "data/green-square-256.png"
14561
And user "user0" gets avatar for user "user0"
14662
And The following headers should be set
14763
| Content-Type | image/png |
14864
| X-NC-IsCustomAvatar | 1 |
14965
And last avatar is a square of size 512
150-
And last avatar is a single "#FF0000" color
66+
And last avatar is a single "#00FF00" color
15167
And user "anonymous" gets avatar for user "user0"
15268
And The following headers should be set
15369
| Content-Type | image/png |
15470
| X-NC-IsCustomAvatar | 1 |
15571
And last avatar is a square of size 512
156-
And last avatar is a single "#FF0000" color
72+
And last avatar is a single "#00FF00" color
15773
When logged in user deletes the user avatar
15874
Then user "user0" gets avatar for user "user0"
15975
And The following headers should be set
@@ -168,40 +84,6 @@ Feature: avatar
16884
And last avatar is a square of size 512
16985
And last avatar is not a single color
17086

171-
172-
173-
Scenario: get user avatar with a larger size than the original one
174-
Given Logging in using web as "user0"
175-
And logged in user posts temporary avatar from file "data/coloured-pattern-non-square.png"
176-
And logged in user crops temporary avatar
177-
| x | 384 |
178-
| y | 256 |
179-
| w | 128 |
180-
| h | 128 |
181-
When user "user0" gets avatar for user "user0" with size "192"
182-
Then The following headers should be set
183-
| Content-Type | image/png |
184-
| X-NC-IsCustomAvatar | 1 |
185-
And last avatar is a square of size 512
186-
And last avatar is a single "#FF0000" color
187-
188-
Scenario: get user avatar with a smaller size than the original one
189-
Given Logging in using web as "user0"
190-
And logged in user posts temporary avatar from file "data/coloured-pattern-non-square.png"
191-
And logged in user crops temporary avatar
192-
| x | 384 |
193-
| y | 256 |
194-
| w | 128 |
195-
| h | 128 |
196-
When user "user0" gets avatar for user "user0" with size "96"
197-
Then The following headers should be set
198-
| Content-Type | image/png |
199-
| X-NC-IsCustomAvatar | 1 |
200-
And last avatar is a square of size 512
201-
And last avatar is a single "#FF0000" color
202-
203-
204-
20587
Scenario: get default guest avatar
20688
When user "user0" gets avatar for guest "guest0"
20789
Then The following headers should be set

build/integration/features/bootstrap/Avatar.php

Lines changed: 4 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
44
* SPDX-License-Identifier: AGPL-3.0-or-later
55
*/
6-
use Behat\Gherkin\Node\TableNode;
76
use PHPUnit\Framework\Assert;
87

98
require __DIR__ . '/../../vendor/autoload.php';
@@ -67,30 +66,11 @@ public function userGetsAvatarForGuest(string $user, string $guestAvatar) {
6766
}
6867

6968
/**
70-
* @When logged in user gets temporary avatar
71-
*/
72-
public function loggedInUserGetsTemporaryAvatar() {
73-
$this->loggedInUserGetsTemporaryAvatarWith('200');
74-
}
75-
76-
/**
77-
* @When logged in user gets temporary avatar with :statusCode
78-
*
79-
* @param string $statusCode
80-
*/
81-
public function loggedInUserGetsTemporaryAvatarWith(string $statusCode) {
82-
$this->sendingAToWithRequesttoken('GET', '/index.php/avatar/tmp');
83-
$this->theHTTPStatusCodeShouldBe($statusCode);
84-
85-
$this->getLastAvatar();
86-
}
87-
88-
/**
89-
* @When logged in user posts temporary avatar from file :source
69+
* @When logged in user posts avatar from file :source
9070
*
9171
* @param string $source
9272
*/
93-
public function loggedInUserPostsTemporaryAvatarFromFile(string $source) {
73+
public function loggedInUserPostsAvatarFromFile(string $source) {
9474
$file = \GuzzleHttp\Psr7\Utils::streamFor(fopen($source, 'r'));
9575

9676
$this->sendingAToWithRequesttoken('POST', '/index.php/avatar',
@@ -106,40 +86,15 @@ public function loggedInUserPostsTemporaryAvatarFromFile(string $source) {
10686
}
10787

10888
/**
109-
* @When logged in user posts temporary avatar from internal path :path
89+
* @When logged in user posts avatar from internal path :path
11090
*
11191
* @param string $path
11292
*/
113-
public function loggedInUserPostsTemporaryAvatarFromInternalPath(string $path) {
93+
public function loggedInUserPostsAvatarFromInternalPath(string $path) {
11494
$this->sendingAToWithRequesttoken('POST', '/index.php/avatar?path=' . $path);
11595
$this->theHTTPStatusCodeShouldBe('200');
11696
}
11797

118-
/**
119-
* @When logged in user crops temporary avatar
120-
*
121-
* @param TableNode $crop
122-
*/
123-
public function loggedInUserCropsTemporaryAvatar(TableNode $crop) {
124-
$this->loggedInUserCropsTemporaryAvatarWith('200', $crop);
125-
}
126-
127-
/**
128-
* @When logged in user crops temporary avatar with :statusCode
129-
*
130-
* @param string $statusCode
131-
* @param TableNode $crop
132-
*/
133-
public function loggedInUserCropsTemporaryAvatarWith(string $statusCode, TableNode $crop) {
134-
$parameters = [];
135-
foreach ($crop->getRowsHash() as $key => $value) {
136-
$parameters[] = 'crop[' . $key . ']=' . $value;
137-
}
138-
139-
$this->sendingAToWithRequesttoken('POST', '/index.php/avatar/cropped?' . implode('&', $parameters));
140-
$this->theHTTPStatusCodeShouldBe($statusCode);
141-
}
142-
14398
/**
14499
* @When logged in user deletes the user avatar
145100
*/

core/Controller/AvatarController.php

Lines changed: 2 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,12 @@
1515
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
1616
use OCP\AppFramework\Http\Attribute\OpenAPI;
1717
use OCP\AppFramework\Http\Attribute\PublicPage;
18-
use OCP\AppFramework\Http\DataDisplayResponse;
1918
use OCP\AppFramework\Http\FileDisplayResponse;
2019
use OCP\AppFramework\Http\JSONResponse;
2120
use OCP\AppFramework\Http\Response;
2221
use OCP\Files\File;
2322
use OCP\Files\IRootFolder;
2423
use OCP\IAvatarManager;
25-
use OCP\ICache;
2624
use OCP\IL10N;
2725
use OCP\IRequest;
2826
use OCP\IUserManager;
@@ -38,7 +36,6 @@ public function __construct(
3836
string $appName,
3937
IRequest $request,
4038
protected IAvatarManager $avatarManager,
41-
protected ICache $cache,
4239
protected IL10N $l10n,
4340
protected IUserManager $userManager,
4441
protected IRootFolder $rootFolder,
@@ -199,8 +196,7 @@ public function postAvatar(?string $path = null): JSONResponse {
199196
Http::STATUS_BAD_REQUEST
200197
);
201198
}
202-
$this->cache->set('avatar_upload', file_get_contents($files['tmp_name'][0]), 7200);
203-
$content = $this->cache->get('avatar_upload');
199+
$content = file_get_contents($files['tmp_name'][0]);
204200
unlink($files['tmp_name'][0]);
205201
} else {
206202
$phpFileUploadErrors = [
@@ -247,18 +243,15 @@ public function postAvatar(?string $path = null): JSONResponse {
247243
try {
248244
$avatar = $this->avatarManager->getAvatar($this->userId);
249245
$avatar->set($image);
250-
// Clean up
251-
$this->cache->remove('tmpAvatar');
252246
return new JSONResponse(['status' => 'success']);
253247
} catch (\Throwable $e) {
254248
$this->logger->error($e->getMessage(), ['exception' => $e, 'app' => 'core']);
255249
return new JSONResponse(['data' => ['message' => $this->l10n->t('An error occurred. Please contact your admin.')]], Http::STATUS_BAD_REQUEST);
256250
}
257251
}
258252

259-
$this->cache->set('tmpAvatar', $image->data(), 7200);
260253
return new JSONResponse(
261-
['data' => 'notsquare'],
254+
['data' => 'notsquare', 'image' => 'data:' . $mimeType . ';base64,' . base64_encode($image->data())],
262255
Http::STATUS_OK
263256
);
264257
} else {
@@ -285,71 +278,4 @@ public function deleteAvatar(): JSONResponse {
285278
return new JSONResponse(['data' => ['message' => $this->l10n->t('An error occurred. Please contact your admin.')]], Http::STATUS_BAD_REQUEST);
286279
}
287280
}
288-
289-
/**
290-
* @return JSONResponse|DataDisplayResponse
291-
*/
292-
#[NoAdminRequired]
293-
#[FrontpageRoute(verb: 'GET', url: '/avatar/tmp')]
294-
public function getTmpAvatar() {
295-
$tmpAvatar = $this->cache->get('tmpAvatar');
296-
if (is_null($tmpAvatar)) {
297-
return new JSONResponse(['data' => [
298-
'message' => $this->l10n->t('No temporary profile picture available, try again')
299-
]],
300-
Http::STATUS_NOT_FOUND);
301-
}
302-
303-
$image = new \OCP\Image();
304-
$image->loadFromData($tmpAvatar);
305-
306-
$resp = new DataDisplayResponse(
307-
$image->data() ?? '',
308-
Http::STATUS_OK,
309-
['Content-Type' => $image->mimeType()]);
310-
311-
$resp->setETag((string)crc32($image->data() ?? ''));
312-
$resp->cacheFor(0);
313-
$resp->setLastModified(new \DateTime('now', new \DateTimeZone('GMT')));
314-
return $resp;
315-
}
316-
317-
#[NoAdminRequired]
318-
#[FrontpageRoute(verb: 'POST', url: '/avatar/cropped')]
319-
public function postCroppedAvatar(?array $crop = null): JSONResponse {
320-
if (is_null($crop)) {
321-
return new JSONResponse(['data' => ['message' => $this->l10n->t('No crop data provided')]],
322-
Http::STATUS_BAD_REQUEST);
323-
}
324-
325-
if (!isset($crop['x'], $crop['y'], $crop['w'], $crop['h'])) {
326-
return new JSONResponse(['data' => ['message' => $this->l10n->t('No valid crop data provided')]],
327-
Http::STATUS_BAD_REQUEST);
328-
}
329-
330-
$tmpAvatar = $this->cache->get('tmpAvatar');
331-
if (is_null($tmpAvatar)) {
332-
return new JSONResponse(['data' => [
333-
'message' => $this->l10n->t('No temporary profile picture available, try again')
334-
]],
335-
Http::STATUS_BAD_REQUEST);
336-
}
337-
338-
$image = new \OCP\Image();
339-
$image->loadFromData($tmpAvatar);
340-
$image->crop($crop['x'], $crop['y'], (int)round($crop['w']), (int)round($crop['h']));
341-
try {
342-
$avatar = $this->avatarManager->getAvatar($this->userId);
343-
$avatar->set($image);
344-
// Clean up
345-
$this->cache->remove('tmpAvatar');
346-
return new JSONResponse(['status' => 'success']);
347-
} catch (\OC\NotSquareException $e) {
348-
return new JSONResponse(['data' => ['message' => $this->l10n->t('Crop is not square')]],
349-
Http::STATUS_BAD_REQUEST);
350-
} catch (\Exception $e) {
351-
$this->logger->error($e->getMessage(), ['exception' => $e, 'app' => 'core']);
352-
return new JSONResponse(['data' => ['message' => $this->l10n->t('An error occurred. Please contact your admin.')]], Http::STATUS_BAD_REQUEST);
353-
}
354-
}
355281
}

dist/settings-vue-settings-personal-info.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/settings-vue-settings-personal-info.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)