Please upgrade here. These earlier versions are no longer being updated and have security issues.
HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.
Excluding discussion records from display without the use of css or custom views
rbrahmson
✭✭✭
I would like to develop a plugin that can exclude discussion records from display without the use of css or custom views. The exclusion controlled by the plugin should be total - namely the plugin could prevent the user from accessing excluded discussions regardless of whether he is reaching discussions from the discussion controller, categories controller, profile, activity, etc.
Appreciate any ideas, insights.
0
Comments
Use categories with custom permissions
OK, that may work for my purpose if there was a hook on the permission check so I could dynamically allow/disallow access to a specific user to the category.
Developers should use standard models to get data, but they do not have to. So in order to be really sure, you have to use the access restriction that is in place and that are category permissions and roles.
Permission is checked on different ways, too.
You could try to hook in very early events, but all in all this doesn't sound like a clean way. What do you try to achieve in detail?
I want to be able to send invites to specific discussions (through a "SHARE" button) without having to open the entire forum or discussions to the invited party.
So if categories are already tightly controlled, I could move the shared discussion to a "shared" category and then use the plugin to decide on a case-by-case basis access to the shared discussion. But using categories is a workaround. The best would be to be able to control access to the discussion regardless of which category it is.
You can modify the permissions a user has as soon as the session is started.
Yaga does exactly this to provide the perks functionality. Here is the relevant code: https://github.com/hgtonight/Application-Yaga/blob/4d99c42fd11ebf5b946d345b96438e9c59183882/settings/class.hooks.php#L447-L546
Search first
Check out the Documentation! We are always looking for new content and pull requests.
Click on insightful, awesome, and funny reactions to thank community volunteers for their valuable posts.
That's great. Clearly I can define specific permissions in my "share" plugin and with your example grant specific permission when the invitee logs on. That is a much better approach than the one I envisioned which was to manage permission for this function on my own.
But regardless of the method, the stumbling block is how to use that permission in the plugin to offer access to a specific discussion (rather than the category to which it belongs). Seems exceedingly "wrong" to create a category for each invited user (and move discussion in there). BTW (and I know this is for another discussion), if discussions could be assigned to multiple categories (a "shortcut"?) then the move step with all it's issues would not be necessary...
This is a clue that you should be using Tags rather than categories.
Categories is one to many discussions. Tags is many to many discussions.
Search first
Check out the Documentation! We are always looking for new content and pull requests.
Click on insightful, awesome, and funny reactions to thank community volunteers for their valuable posts.
So my problem is still finding a solution to exclude discussion records without custom views and css.
Am I getting closer to the solution???
Refocusing on the original issue - did I miss the answer or clue to it, or there really isn't any way to exclude discussion records from display through a plugin (that indicates yea/nay) for all the official Vanilla code? (I can live with other plugins going to these excluded discussions directly since I control which plugins I enable)
You can exclude discussions via a category permission, site wide.
You can exclude discussions via a base discussionModel_beforeGet_handler hook as well.
Search first
Check out the Documentation! We are always looking for new content and pull requests.
Click on insightful, awesome, and funny reactions to thank community volunteers for their valuable posts.
Thank you @hgtonight (and @R_J who hinted to that in another comment). I went further in research and found this discussion insightful.
I think that it leads me to believe that I can create a separate "Sharing" table and use the joining technique from that discussion to exclude discussions that are not shared (only for the Invitee user who is not yet a full member of the forum).
Any warning/insights before I start on the work?
I think you will have no success with this approach. It is quite easy to add something to the sql with the BeforeGet event, but the sql will also contain a
where d.Categrory in (allowed categoriess)
. I see no sql way to get a) all discussions from allowed categories b) together with the permitted discussions from a closed category because of that restriction.I've tried to find a solution but gave up.
Joining another table wouldn't work for the same reasons.
There is another way, though, but it requires you to "copy" a lot of code. When the discussionmodels function is called, you can fool Vanilla and temporarily change a config setting that no categories are used. This way, Vanilla would skip the category permission check altogether.
I've started to write such a plugin in order to see how much work it would be, but stopped when I realized that the copied code from both index methods would make the plugin not future proof. It would need a lot of code changes foreach update. I wouldn't want to publish such a plugin.
See it as a proof of concept...
https://github.com/R-J/leak/tree/master
But I really believe there must be a better way...
I'm not sure the where clause I'm considering is the one you were thinking of.
First step, the plugin will check that the user is an Invitee (a special Role for that). The sharing process will create an entry in a SharingTable with the Invitee ID as key and an array of discussion IDs he is allowed to participate in.
Once the Invited user logs in (having a special Sharing Role), their ability to access Discussions will be controlled through (1) Having the Category of the discussion accessible to the Sharing role -- that is standard and unchanged by the plugin, and (2) Through the additional Where set by the plugin. Here is a general way I was considering:
Would that work?
Is my SQL syntax correct?
If you open the index of the discussions controller (yourforum.com/discussions), the following sql is used to get all discussions (taken from my test install):
If you look at the sql when the BeforeGet event is fired
You'll see that it is "empty" at that time. So whatever you do with a cloned sql will not influence the result of the function that fires the event. The only EventArguments are sort criteria and a where array.
If you add anything to Gdn::sql(), it will be added to the sql that is created (example above).
Given that you have a discussion with id = 15 and category 5, where category 5 is a restricted category,
you would end up with a sql like the above and those lines:
where d.DiscussionID in (15, ...)
and d.CategoryID in (everything but not 5)
So the result would not contain discussion 15, because of the category restriction.
By the way: getting a discussion is only the first step. In order to be able to comment, react, etc. on a discussion, you have to tweek much more.
As @hgtonight said, you can change the permissions of a user on the fly. I wouldn't like to work like that, but if you only use your plugin in your own setup, you might consider to do a base_render_before function that adds the category permission and then try to restrict where it should be used.
Match
Gdn::controller()->ControllerName
andGdn::controller()->RequestMethod
against a white list (that you need find out with try and error) and do the the user/invited check in the second step.Only if a) category can be used for invitations, b) user is not allowed to view category, c) user has been invited to this discussion, change the users permissions for the restricted category.
$Sender->SQL->Where('where d.DiscussionID in', $SharedDicsussionIDs);
Gdn::sql()->whereIn('d.DiscussionID', $SharedDiscussionIDs);
If you do not restrict access to discussions by permissions, you have to set up your own security conception, never knowing which plugin/core function gives access to a discussion. Without further scanning or thinking, I would guess you have problems because:
And many, many more places to look at...
Maybe creating a conversation as a follow up to a discussion is simpler? You could focus your energy on a plugin that offers to base a conversation on a discussion, converting discussion and comments in messages. If the plugin offers to close the discussion, there is no risk of cluttered communication.
There is an additional problem : you restrict it to only include the shared discussions. You would have to exclude the not-shared discussions from that category
@R_J - Thanks for spending time on this. This is a bit discouraging... My thinking is that the Share function would be a vehicle to get unregistered users interested in joining in, not by scanning content (as is the case today) but by being invited to comment on a specific discussion by the author (or a commenter) who knows the invitee and think the subject would be of interest. So basically _this is a different mode_l of promoting a forum and engaging new users.
So my goal was to offer a relatively similar discussion/commenting experience and allow promotion from "Invitee" to full-member by request of either the invitee or the sharing person (Admin may or may not be required to further access the request to join - that is a separate issue).
So the discouraging part is the holes in the scheme. You clearly see why I initially wrote " The exclusion controlled by the plugin should be total..." - I was afraid of the holes you highlighted.
I am not sure what's the best way to proceed. I share your dislike of cloning code and be subjected to constant version revision updates,and I'm not crazy about dynamic permission setting either although it looks like the lesser evil.
You would have had a lot more problems:
Sending an invitation would have implied the automatic creation of a user or at least the automatic creation when that invitee first time uses the invitation link. Without user id, this person at least would never had the possibility to comment.
If you create a user, you need some minimum information: username and password. So if a person is invited to a discussion, he would have felt to be forced to register (which he in fact is)
I guess a combination of sending someone the user link together with a plugin like the CommentBeforeRegister (don't know if that is the correct name), would be better.
Only a promotion of the role could be done, but that's allow
You have to see it the other way around: you are the one who is creating a hole in the scheme. The permission conception is based on categories. You can break that if you try hard (but it is the security aspect, which should make it nearly unneded to really break it anyway), but you can only break it partially. If you do not need it, you can deactivate it. But if it is needed, it should work anywhere! So if you want to find a way around, you really have to work hard.
You should feel comfortable to see that the permission conception is deeply integrated.
You like to invite non-users to discussions that are in a category that also contains discussions the user should not be allowed to see?
This is abusing the user-idea as well as the permission-idea. I guess it would be hard work to accomplish that. I could think of ways for both, but the effort to do so is not worth the profit.