Hello everyone, I hope I'm in the right section.
I find the behavior of Tags as counter-intuitive regarding permissions.

Let's say I have 2 tags: X and Y.
X has permission to be seen by a certain group only
Y is for everyone

If I tag a topic with both, I'd expect the permissions to sum, so the topic is visible to everyone. At the moment, it is only visible by the X group

This is a problem for many things. In my case for example, I use a forum with working groups and they sometimes want to release updates for the whole community. Every group has its own tag, but if it uses it the update becomes invisible to everyone else.

I can see many other use cases where this approach falls short

Is this working as intended?

Thanks!

Updates should be a primary tag that is visible to anyone, much like our meta tag. Tags indeed work based on open -> closed and that's possibly counter intuitive if you expect it otherwise. No programmer will ever be able to write features that suit all 100% of user needs.

Creating a primary tag that any of your groups can view and post into might be best right now.

If you really dislike how this works you can also fork the flarum/tags extension and modify it to your need, with the added weight of keeping it maintained.

Not sure this completely answers your question, I certainly hope it does.

2 years later

Yes, I'm afraid I cannot make sense of Flarum's permissions system at all. And it's currently the thing stopping me from migrating to it.

I think the most confusing factor is the terminology Global. Which suggests settings which apply to all topics. But I think should actually be called Default, as it can be overridden by tags.

I'm also confused about whether Restrict by Tag is a misnomer too, because it seems it can grant extra permissions, as well as revoking them from Global.

On the technical side, the "restricted" attribute on a tag means it will evaluate additional scoped permissions. An "unrestricted" tag will only consider global permissions.

I'm sure the naming could be improved, but that's how it is currently. The frontend uses that same word to describe the permission tag scoping feature.

Scoped permissions don't really override global permissions, they are evaluated together. The Tags extension has some custom logic that aggregates all scoped permissions before taking the most negative one, but otherwise it's the default Flarum gate priorities that sort out the permissions based on all inputs.

Do you have a particular use case you are unable to configure using the Flarum permission system we could look into?

    clarkwinkelmann The Tags extension has some custom logic that aggregates all scoped permissions before taking the most negative one

    Ahh, so in practice the "Global" permissions settings do in fact define the most permissive policy which can ever be applied to any discussion? And then a tag scope can only make the policy more restrictive? Or in other words: Tag scopes can only revoke permissions, never grant them?

    clarkwinkelmann Do you have a particular use case you are unable to configure using the Flarum permission system we could look into?

    I'm trying to divide the forum into a two sets of tags. A set of "public" tags which anyone can view, and any user can post to. And a set of "premium" tags which only club-members can view and post to.

    The problem I experienced is that permissions do not follow the hierarchy of primary tags. So I have to configure the entire permissions set for every tag separately.

    I will see if I can make it work now with your explanation of the permissions system. (Thank you!)

    I would also potentially be interested in contributing to a feature which allows scopes to be created containing multiple tags. Although I am completely unfamiliar with Laravel.

      andybrice the most permissive policy which can ever be applied to any discussion?

      No, it's not exactly that.

      I have checked the source code again to validate. Basically, it's in that order:

      • If an extension has custom logic that overrides the Tags extension, it might create a behavior that's different from below. But I'm not aware of any such extension. Most rely on the built-in priorities.
      • If the discussion has no "restricted" tags (no scoped column on the Permission page), then the global permissions are used (first column on the Permissions page).
      • If the discussion has any number of "restricted" tags, the most restrictive permission of all applied restricted tags will be used. The global permissions will be ignored.

      This means it is possible to apply a more liberal permission via scoped/restricted tags than the global. I believe it was intentionally designed like this, otherwise you would have to make a lot of tags restricted if you wanted to have a single more liberal tag, and it would be a nightmare to manage all the columns on the Permissions page.

      The relevant logic is about 20 lines of PHP in this file https://github.com/flarum/framework/blob/v1.4.0/extensions/tags/src/Access/DiscussionPolicy.php#L39-L63 which affects all the permissions that can be scoped per tag.

        clarkwinkelmann If the discussion has any number of "restricted" tags, the most restrictive permission of all applied restricted tags will be used. The global permissions will be ignored.

        Okay, so as I understand it now: A tag can be used to grant permissions which are not granted in Global. And a tag can also be used to revoke permissions which are granted in Global. But a tag cannot be used to grant permissions which are revoked via another tag. Because in order for a permission to be granted, it must be unanimously granted by every one of the discussion's restricted tags.

        I think this is beginning to make sense to me.

        clarkwinkelmann The relevant logic is about 20 lines of PHP in this fileā€¦

        So each ability is evaluated individually. The resulting "most restrictive" policy is essentially an AND of all the tags' policies. Rather than selecting the full set of permissions from the tag which is rated as "most restrictive" in some way.

        The only thing which I definitely don't understand about this function is that it is documented as returning bool. But appears to implicitly return null in several branches. Is null equivalent to false in this context? Or does null have some different meaning to the caller of can()?

          andybrice null implies that the gate will not take any action, it's up to the default or any other gate to decide whether access is granted by returning true or false. I haven't looked at the source as much as Clark has, but that's what I remember.

            luceos Ahh, right. From the Flarum Docs on Authorization:

            if all policies return null (or don't return anything), we check if the user is in a group that has a permission equal to the ability

            So yes, null seems to imply "I have no opinion on this request."

            In flarum/tags:src/Access/DiscussionPolicy.php, returning NULL essentially means falling back to the global permission, since it's extending the original ability with the same name.

            The gate is a bit more complex that true/false, there's also FORCE_ALLOW and FORCE_DENY, which extension can use to override the default priority. If any extension returns FORCE_ALLOW in a custom gate function, it'll override the logic seen in that file.

            andybrice in order for a permission to be granted, it must be unanimously granted by every one of the discussion's restricted tags.

            Yep, that's it.