-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make possible for apps to define their own avatar types #24579
Make possible for apps to define their own avatar types #24579
Conversation
Until now requests always had "auth" headers either for an admin or a regular user, depending on the value of "currentUser". Now, if "currentUser" starts by "anonymous" no "auth" header is sent, which makes possible to also test requests with users not logged in. Signed-off-by: Daniel Calviño Sánchez <[email protected]>
"sendingAToWithRequesttoken" needs to be used to test some non OCS endpoints which require the request token to be sent in the request. Now it is possible to specify the body (or, rather, additional contents beside the cookies and the request token) for those requests, as it will be needed for example to upload an avatar. Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Even on solid color images the resizing can cause some small artifacts that slightly modify the color of certain pixels. Due to this now the color comparison is no longer strict but fuzzy. Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
"sendingToWith" is used to test OCS endpoints. Now it is possible to specify the body (or, rather, additional contents beside the cookies and the request token) for those requests, as it will be needed for example to upload an avatar. Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this a lot because we can also use this to unify/replace https://github.com/nextcloud/mail/blob/master/lib/Controller/AvatarsController.php
* @return DataResponse|FileDisplayResponse | ||
*/ | ||
public function getAvatar(string $avatarType, string $avatarId, int $size): Response { | ||
// min/max size |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can even use the min
/max
functions for this 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but not for <= 0 use 64.
On the other side @rullzer always wanted to limit the formats anyway.
I would suggest to only allow: 64, 128, 256 and 512 as sizes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I have realized that this (which is a shameless copy/paste from the old controller :-P ) does not allow to use -1 to get an avatar with the original size (which is documented in IAvatar
). Should we allow that in the new controller?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only 64, 128, 256, 512 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no real preference on the set of sizes, although limiting it to only a specific set sounds like a good idea to prevent an unneeded use of disk space if a "funny" user does something like for i in {64..512}; do curl .../avatar/user0/$i; done
. Thus I have added a commit for that.
I still wonder about the "-1" to get the original size; it could be used for example if a user wants to check her current avatar exactly like it was uploaded.
'X-NC-IsCustomAvatar' => (int)$avatar->isCustomAvatar() | ||
] | ||
); | ||
} catch (\Exception $e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- This is a bit generic – is it possible to catch a more specific exception?
- If catching that generic I would highly recommend logging the exception to help our futures selves debug any issues with this code :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit generic – is it possible to catch a more specific exception?
We could catch OCP\Files\NotFoundException
as it is thrown by getFile(), InvalidArgumentException
as it is thrown by IAvatarManager
and whatever is thrown by IAvatarProvider::getAvatar()
. I wonder whether other exceptions should be catched or just left to bubble up and generate an error 500 (maybe even the exception thrown by IAvatarProvider::getAvatar()
if it ends being just a generic Exception
).
If catching that generic I would highly recommend logging the exception to help our futures selves debug any issues with this code :)
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of AvatarException
I named it AvatarProviderException
, as that is more specific and gives room to add in the future an AvatarException
for avatar specific errors if needed.
In the end I removed the log, as now a generic exception is no longer caught, but an AvatarProviderException
, which would be thrown if the provider can not get an avatar for the given id. I think that belongs to the realm of expected errors that do not need to be logged (but if I am wrong it can be added back, of course ;-) ).
lib/private/Avatar/AvatarManager.php
Outdated
|
||
if ($context === null) { | ||
// Too early, nothing to do yet | ||
throw new \InvalidArgumentException('Unknown avatar type: ' . $type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd argue that we are lying here. The argument isn't invalid, but the code can't handle the request. Another exception would be more appropriate IMO.
Of course this is highly unlikely to happen because we do the registration before anything else. Hence failing hard here could be an option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd argue that we are lying here. The argument isn't invalid, but the code can't handle the request. Another exception would be more appropriate IMO.
I agree, although I used InvalidArgumentException
because I did not find any suitable exception and adding a new exception just for this seemed unnecessary (given that in practice it will not happen). So exception suggestions welcome :-)
Of course this is highly unlikely to happen because we do the registration before anything else. Hence failing hard here could be an option.
Failing hard as in exit()
? Having an exit there would feel very out of place in my opinion. Or do you mean throw new Error()
? Or something else? :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, although I used
InvalidArgumentException
because I did not find any suitable exception and adding a new exception just for this seemed unnecessary (given that in practice it will not happen). So exception suggestions welcome :-)
In https://github.com/nextcloud/server/pull/24702/files#diff-7bfcce99ae84563547086798084d75003c7099fedeabb795d2c01962293b33fcR88 I went with \RuntimeException
.
Failing hard as in
exit()
? Having an exit there would feel very out of place in my opinion. Or do you meanthrow new Error()
? Or something else? :-)
I meant letting the exception bubble up, without any explicit handling :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In https://github.com/nextcloud/server/pull/24702/files#diff-7bfcce99ae84563547086798084d75003c7099fedeabb795d2c01962293b33fcR88 I went with \RuntimeException.
\RuntimeException
it is then.
Failing hard as in exit()? Having an exit there would feel very out of place in my opinion. Or do you mean throw new Error()? Or something else? :-)
I meant letting the exception bubble up, without any explicit handling :)
Ok, that makes a lot more sense :-P
lib/public/IAvatarManager.php
Outdated
* @return IAvatar | ||
* @throws \InvalidArgumentException if the type is not known or the id is | ||
* not valid | ||
* @throws \Exception if getting the avatar failed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see a more specific exception thrown here. If this is just about any possible error that we didn't expect then I wouldn't document the exception
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be the same exception thrown by IAvatarProvider::getAvatar()
. Should AvatarException
be introduced to wrap other specific exceptions that could be thrown by providers? For example, in the case of Talk, the avatar provider could throw RoomNotFoundException
if the avatar id does not match any room token, but of course that exception makes little sense in a generic context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should
AvatarException
be introduced to wrap other specific exceptions
Sounds good to me! Then we can transport any more specific exception as previous
.
lib/public/IAvatarProvider.php
Outdated
interface IAvatarProvider { | ||
|
||
/** | ||
* Returns an IAvatar instance for the given id. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no .
at the end of phpdoc lines :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove all them, except at the end of It is allowed to register more than one provider per app.
(IRegistrationContext::registerAvatarProvider
), as:
- I guess the rule does not apply to the "body" of a documentation block (but if it does please let me know ;-) )
- it is consistent with the rest of the documentation in
IRegistrationContext
But if that should be removed too let me know ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no hard rule, I guess. For the body it seems fine. The first line (title?) is a bit strange.
But this is just nitpicking. You may also just ignore my remark ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may also just ignore my remark ;)
Too late ;-)
We could also make this part of the new avatar provider, right? And then the controller asks the avatar service, which delegates to the provider (or falls back to But now I'm also thinking about whether a avatar is just identified by Alternatively we don't even ask for permission but just let the providers throw a dedicated exception when the operation isn't allowed. But again we will likely need the UID as context.
A Therefore I'm more in favor of the |
Wouldn't it be possible to inject the current user in the avatar provider constructor? Or that is possible only for controllers? In that case the extra parameter would be unneeded, as the IAvatarProvider subclass would define everything it needs to know if the current user can modify (or even get) an avatar or not. Even if the current user is not a real user, but for example a guest (in Talk currently only moderators would be able to set the avatar of a conversation, but technically that could be possible also for a guest moderator).
Fully agree, except maybe in the name. Personally I prefer to avoid abbreviatures in API names (or in code names in general), so I would call it |
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
As this sounds like a nice feature, the requests for this are quite low. Currently there a no plans to implement such a feature. Thus I will close this ticket for now. This does not mean we don't want this feature, but it is simply not on our roadmap for the near future. |
Requires #24578
I am really sorry to come with this change so late in the cycle. It is perfectly fine if it is deferred to Nextcloud 22 :-) (or if it is a bad idea and it is never merged ;-) ). However, while working on the Group conversation picture feature for Talk I thought that it would be good to generalize the avatars and use them for that. This would make possible, for example, to show the avatar of a room in the list of shares without needing to use a Talk endpoint.
I guess it could be used too for unifying the avatars between clients or differentiating user and group avatars (although that would not be something to be done for Nextcloud 21).
Before this pull request the avatars were limited to users and guests, and there was no OCS endpoint for getting and setting the avatars. Now, besides the default user and guest types, an app can register its own avatar type(s), and any avatar can be got or set using a OCS endpoint (and the old ones are still available, of course).
In order to set an avatar with the old endpoints a temporary image needs to be posted, and then a request to crop that temporary image is needed to finally set the avatar. When using the OCS endpoint, on the other hand, the image needs to be uploaded already with the desired size (and it can not be selected from the internal files, the client setting the avatar needs to download it first, crop it as needed and then upload it again). If the avatar does not support the aspect ratio (for example, the user avatar must be squared) then the request fails.
Pending:
IAvatarProvider
(or something like that) and registration of providers toIAvatarManager
UserAvatar
? Or should be prevented only in the controller (for example, to allow an admin to modify the avatar from an OCC command, or something like that)? In case it needs to be done in the controller, how? Add something likecanAvatarBeModifiedByUser($userId)
toIAvatar
and check it from the controller?getCacheTimeToLive(IAvatar)
Future:
UserAvatarProvider
and move code specific to user avatars fromAvatarManager
toUserAvatarProvider
(not done yet to minimize the changes). -UserAvatarProvider
has been created already, as getting the cache will be done fromIAvatarProvider
, although the code specific to user avatars was not moved yet to the provider.