Skip to content

Commit 71be18d

Browse files
Merge pull request #55303 from nextcloud/backport/55134/stable32
2 parents 4700a54 + ed1282c commit 71be18d

File tree

7 files changed

+15
-372
lines changed

7 files changed

+15
-372
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
@@ -4,7 +4,6 @@
44
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
55
* SPDX-License-Identifier: AGPL-3.0-or-later
66
*/
7-
use Behat\Gherkin\Node\TableNode;
87
use PHPUnit\Framework\Assert;
98

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

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

9777
$this->sendingAToWithRequesttoken('POST', '/index.php/avatar',
@@ -107,40 +87,15 @@ public function loggedInUserPostsTemporaryAvatarFromFile(string $source) {
10787
}
10888

10989
/**
110-
* @When logged in user posts temporary avatar from internal path :path
90+
* @When logged in user posts avatar from internal path :path
11191
*
11292
* @param string $path
11393
*/
114-
public function loggedInUserPostsTemporaryAvatarFromInternalPath(string $path) {
94+
public function loggedInUserPostsAvatarFromInternalPath(string $path) {
11595
$this->sendingAToWithRequesttoken('POST', '/index.php/avatar?path=' . $path);
11696
$this->theHTTPStatusCodeShouldBe('200');
11797
}
11898

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

core/Controller/AvatarController.php

Lines changed: 2 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,20 @@
88
namespace OC\Core\Controller;
99

1010
use OC\AppFramework\Utility\TimeFactory;
11-
use OC\NotSquareException;
1211
use OCP\AppFramework\Controller;
1312
use OCP\AppFramework\Http;
1413
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
1514
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
1615
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
1716
use OCP\AppFramework\Http\Attribute\OpenAPI;
1817
use OCP\AppFramework\Http\Attribute\PublicPage;
19-
use OCP\AppFramework\Http\DataDisplayResponse;
2018
use OCP\AppFramework\Http\FileDisplayResponse;
2119
use OCP\AppFramework\Http\JSONResponse;
2220
use OCP\AppFramework\Http\Response;
2321
use OCP\Files\File;
2422
use OCP\Files\IRootFolder;
2523
use OCP\Files\NotPermittedException;
2624
use OCP\IAvatarManager;
27-
use OCP\ICache;
2825
use OCP\IL10N;
2926
use OCP\Image;
3027
use OCP\IRequest;
@@ -41,7 +38,6 @@ public function __construct(
4138
string $appName,
4239
IRequest $request,
4340
protected IAvatarManager $avatarManager,
44-
protected ICache $cache,
4541
protected IL10N $l10n,
4642
protected IUserManager $userManager,
4743
protected IRootFolder $rootFolder,
@@ -202,8 +198,7 @@ public function postAvatar(?string $path = null): JSONResponse {
202198
Http::STATUS_BAD_REQUEST
203199
);
204200
}
205-
$this->cache->set('avatar_upload', file_get_contents($files['tmp_name'][0]), 7200);
206-
$content = $this->cache->get('avatar_upload');
201+
$content = file_get_contents($files['tmp_name'][0]);
207202
unlink($files['tmp_name'][0]);
208203
} else {
209204
$phpFileUploadErrors = [
@@ -250,18 +245,15 @@ public function postAvatar(?string $path = null): JSONResponse {
250245
try {
251246
$avatar = $this->avatarManager->getAvatar($this->userId);
252247
$avatar->set($image);
253-
// Clean up
254-
$this->cache->remove('tmpAvatar');
255248
return new JSONResponse(['status' => 'success']);
256249
} catch (\Throwable $e) {
257250
$this->logger->error($e->getMessage(), ['exception' => $e, 'app' => 'core']);
258251
return new JSONResponse(['data' => ['message' => $this->l10n->t('An error occurred. Please contact your admin.')]], Http::STATUS_BAD_REQUEST);
259252
}
260253
}
261254

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

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)