Afrux Online Users Widget
- Edited
SychO there’s only one setting:
“Prefer loading all widgets data with initial page response.” which is enabled. I don’t remember exactly why I enabled it but maybe the widget was slow to load or didn’t always load or something and then I enabled it and all started working OK. Is that option the reason for restrictions not applying?
P.S. I disabled it and now I see that there are no online users which is suspicious since I always have at least 1-2 users that are online and I remembered that without that option the online users widget actually never worked even though I explicitly logged in with a test user. I think I’m seeing the same problem now.
I am giving this a second chance but I think something is not working as expected. I am an admin on my forum and I have all permissions. So, for instance I see 1-2 users online, then I see no users online for some time and in that time a new post appears by a user. He was not shown as online neither before, nor during, nor after his post.
I have the following option disabled:
“Prefer loading all widgets data with initial page response”
As I said, I’m admin and have permissions:
Always view user last seen time - admins and mods
Search users - admins, mods and members
Is there anything else that needs to be set? Is there any caching? Maybe the extension checks for online users each 10 minutes and will cache that for the next 10 minutes and will not refresh and miss members going on and off in the meantime?
- Edited
@SychO , I did some investigation and I can now confirm the following: those users that have chosen not to show their online status are not visible in the widget, however they are shown as online in the User Directory to me since I am an admin and I have the permission to see their online status.
Is that a bug or the intended behavior of this widget? I see that previously you said this:
SychO checked the code again, when disabled, make sure the two permissions you mentioned earlier are given to members
Do you mean that for the widget to work, all members should be given the permission to always see the online status of all members? If that's true, this defeats the purpose of the permission because members can't hide their online status anymore. I think the widget should show different online users, according to the permissions that are given to the user who is viewing the widget, e.g. the admin should be able too see all online users, even those who are hiding their online status, whereas a regular member (that should naturally not be given the permission to see everybody's online status) should only see those that are not hiding their status.
Can you confirm what is the actual behavior of this widget?
SychO , sure, no problem, I know you are busy with the 2.0, this is not really important. When you have time after the new release, it would be good to see if it's an easy fix though
Looking at the code (but I'm a Java developer and haven't worked with web frameworks and PHP, so might be missing something):
return User::query()
->select('id', 'preferences')
->whereVisibleTo($actor)
->where('last_seen_at', '>', $time)
->limit($limit + 1)
->get()
->filter(function ($user) {
return (bool)$user->getPreference('discloseOnline');
})
->pluck('id')
->toArray();
Seems that we filter only those users that disclose their online status. I think this filter should be kept but with another OR-ed condition checking if the actor has the permission to always see online status of other members.
@SychO , do you think the following code will fix the issue:
return $this->cache->remember('afrux-online-users-widget.users', 40, function () use ($actor, $time, $limit) {
return User::query()
->select('id', 'preferences')
->whereVisibleTo($actor)
->where('last_seen_at', '>', $time)
->limit($limit + 1)
->get()
->filter(function ($user, $actor) {
return (bool)$actor->hasPermission('user.viewLastSeenAt') or (bool)$user->getPreference('discloseOnline');
})
->pluck('id')
->toArray();
}) ?: [];
}
How can I test it easily? I checked out your code and put that change in a branch but I can't push it to the remote repository, I guess I have to be granted permissions. What's the easiest way for me to test that change without installing PHP, etc. on my computer? If I directly find that PHP file on my hosting server and edit it to include that change, will it work?
- Edited
SychO I made it working with the following change of the filter:
->filter(function ($user) use ($actor) {
return ($actor->hasPermission('user.viewLastSeenAt') or $user->getPreference('discloseOnline'))
and ($actor->id !== $user->id);
})
Tested on a copy of my Prod forum and now as an admin I can see users that are hiding their online status. Thanks for all the hints about how to clone the repo and make a release, that's what I'm going to try next.
@SychO , I forked your repository, made the filter update, changed the name in the composer.json to ekumanov/online-users-widget
, here's the repository:
https://github.com/ekumanov/online-users-widget
I then created a new v.1.0.0 release and published it on packagist.org. I then managed to install it on my forum, however what's odd is I don't see the setting for the max users on the extension page. And the core widgets doesn't detect the extension, so I can't place it visually on the screen. I don't see any errors in the logs and the forum works otherwise. Should something else be done? Are settings somehow linked to the original name of the extension in the DB, maybe I should also update some other place?
Apologies if taking your time too much, I know you're busy with the release
- Edited
Never mind, I experimented a little and one of the following apparently fixed the problem:
- I renamed the migration file
- I replaced the
afrux-online-users-widget
toekumanov-online-users-widget
everywhere
- Edited
@SychO, one final question. I see that there's a 40 seconds cache. Is that cache multithreaded and multi-user, i.e. having separate instance per-user or is it a shared global/singleton cache? I mean, is it possible that it's me, the admin, that refreshes the cache as an actor, and then lower-privileged users directly reading my version of the cache and see all online users (because I am an admin and can see everybody) instead of their own cached version with less users inside?
- Edited
CyberGene Yes. And I would guess that's why i didn't initially add a permission check, sorry didn't remember. It's a trade-off to be made between wanting to cache the results to not compute that every time and wanting per-actor results.
You could ofc cache it per-actor. I don't do that in the extension because with big enough traffic the cache grows way too large too quickly as you can imagine, and that can lead to challenges with certain communities so generally not recommended.
- Edited
SychO thanks, indeed it’s a tricky situation. Actually, now that I thought about it more, I believe the easiest way to workaround the situation is to have just two cache instances, one for the admins/mods (and those who have the permissions to always see online status) and one for the rest (the current one). When fetching the online users for a user request, the actor’s permissions will be determined and one of the two caches will be used. I’m pretty interested in implementing this, in my job I do exactly that type of stuff, however it’s Java backend and I’m not familiar with PHP and the frameworks that are used (I guess that’s Laravel?) but I may experiment a bit when I have more time. Thanks again for all your help with this extension and all you other dev so far and good luck with the forthcoming release
CyberGene oh that's smart. you would just need to change (at least smth like this)
$this->cache->remember('ekumanov-online-users-widget.users', ...
to
$suffix = $actor->hasPermission('user.viewLastSeenAt') ? '-permitted' : '-restricted';
$this->cache->remember('ekumanov-online-users-widget.users'.$suffix, ...
SychO that was really helpful! I implemented it and published it, now it is installed on my prod forum and seems to be working pretty fine. You’re great!
- Edited
@SychO, currently the widget with my latest changes works as I wanted it, however the widget is not visible for non-admin/mods. That's actually OK for me since I needed that widget only for admin users, but for the sake of correctness, I think the reason is the following code from registerWidget.ts
:
isDisabled: () => {
const loadWithInitialResponse = app.forum.attribute('afrux-forum-widgets-core.preferDataWithInitialLoad');
return (!loadWithInitialResponse && (!app.forum.attribute('canViewLastSeenAt') || !app.forum.attribute('canSearchUsers')))
||
(loadWithInitialResponse && !app.forum.onlineUsers().length);
}
The way I understand it is that the widget will be disabled unless a user has both canViewLastSeenAt
and canSearchUsers
. I think most people wont give the canViewLastSeenAt
to non-mod users hence regular users won't see the widget.
I think what will fix it is replacing the OR with AND:
!app.forum.attribute('canViewLastSeenAt') && !app.forum.attribute('canSearchUsers'))
I changed that, however I believe I should somehow compile it, so that it goes into forum.js
, right? How is that done? I tried directly editing forum.js
(I know that's wrong but I just replaced a ||
with &&
in order to test), however I got HTTP 400, so maybe I messed it up.
Any advice? Is that change above any good, in the first place? And if yes, what's the easiest way to transpile the TS into JS?
Again, feel free to respond only when you have time