Sitecore Overriding Content Tree - events

Can't seem to to find this posted online anywhere - excuse me if it is!
I am looking for an event/pipeline that one can override for the main content tree in the CMS. I need to hide/disable items in the tree according to user roles so they will not be able to select or view them.
Thanks!
Dan

You should be using access rights for it. It would fit your needs.
You basically need to select the item you need to limit access, then got to the Security>Assign.
Break inheritance to Everyone, then set Allow Read for a specifc role you want to allow. That will hide the items in the tree for the users which are not in the specified role.

Yes, there are situations where access filtering might not be a very good solution, so you should probably go with a custom DataView instead. Override the default Sitecore.Web.UI.HtmlControls.MasterDataView class and override the GetChildItems like this:
protected override void GetChildItems (ItemCollection children, Item parent)
{
base.GetChildItems(children, parent);
YourFilteringMethod(children); // Let this method remove unwanted items
}
Then replace the master data view in your sitecore config file, such as using a patch file like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:x="http://www.sitecore.net/xmlconfig/">
<sitecore>
<dataviews>
<dataview name="Master">
<patch:attribute name="assembly">YourAssembly</patch:attribute>
<patch:attribute name="type">YourNamespace.MasterDataView</patch:attribute>
</dataview>
</dataviews>
</sitecore>
</configuration>
Here's a post about it where it's being used for language filtering (it goes a bit further as well), but you can implement it for doing access filtering that suits your needs instead:
http://mikael.com/2014/10/sitecore-dataviews/
/ Mikael

Related

How to access View Template Properties for Revit and compare them in Real Time?

I am trying to list the view template’s properties so we can compare them with another old template.
For example what model elements are hidden or have overrides in a given template or which Revit links have been hidden or overridden in a given template.
View Template
(https://www.google.com/search?q=view+template+revit&rlz=1C1GGRV_enUS770US770&source=lnms&tbm=isch&sa=X&ved=0ahUKEwjLndrd2cTbAhVESq0KHX1cAPwQ_AUICygC&biw=1536&bih=824#imgrc=Q0v-pV7Nxl4kfM:)
I’m looking to devise a View Template Compare tool and access to the owner and creator of them.
public void ApplyViewTemplateToActiveView()
{
Document doc = this.ActiveUIDocument.Document;
View viewTemplate = (from v in new FilteredElementCollector(doc)
.OfClass(typeof(View))
.Cast<View>()
where v.IsTemplate == true && v.Name == "MyViewTemplate"
select v)
.First();
using (Transaction t = new Transaction(doc,"Set View Template"))
{
t.Start();
doc.ActiveView.ViewTemplateId = viewTemplate.Id;
t.Commit();
}
}
With Revit API you can access with:
GetTemplateParameterIds Method / ViewTemplateId Property
The Revit API exposes almost all the ViewTemplate properties.
For instance this method returns all the Visibility/Graphic Overrides for a specific category:
https://apidocs.co/apps/revit/2019/ed267b82-56be-6e3b-0c6d-4de7df1ed312.htm
The only thing I couldn't get for a ViewTemplate are the "includes", but all the rest seems to be there.
Update:
The list or properties "not included" can be retrieved with GetNonControlledTemplateParameterIds().
Yes, and no.
Yes, I guess you can use Forge Model Derivative API to export RVT file and then build a dashboard around the View Templates data. That's assuming that View Templates data actually gets exported when the model is translated. That data is not attached to any geometry so I would not be surprised if it was skipped. The question here is why? This is like renting a 16-wheel truck to move a duffel bag across the street.
No, if your intention is to directly interact with the RVT model. Forge can view it, but to push anything back or request changes to the model, is not available yet. Then again, I am not even sure that the view template data is available via model derivative exports.
This brings me another alternative. Why not just collect the data using Revit API, the standard way and then push it out to a Database and build on top of that? There is no reason to employ Forge for any of that.
Thanks Jeremy, I had dig into your amazing website and also some solution that Konrad post in the Dynamo Forum about this. In Revit seems pretty achievable, you filter the View that is View Template and then extracts these properties, is it correct?.
I am wondering if someone can point me in the right direction with Forge.
Some amazing guys are developing a BQL https://www.retriever.works/.
BQL(Building Query Language) is a query language for buildings, similar to how SQL is a query language for databases. It is fast and flexible. BQL helps improve efficiency for QA/QC (quality assurance and quality control), and building data extraction without leaving Revit. I am also trying these and I would like to understand if there are some works where I could start with Forge next week about this.

How to specify composite action variables in magento dataflow xml profiles

I have created some custom actions to use inside a Magento Dataflow profile. I would like to pass in composite parameter values (arrays or dictionaries) to the action, similar to the map var you can pass to the default parser actions. I.e., I would like to do something like this:
<var name="attribute_map">
<map name="sColore"><![CDATA[colore]]></map>
<map name="sMarca"><![CDATA[marca]]></map>
<map name="sFornitore"><![CDATA[fornitore]]></map>
</var>
The variable turns out as null in this case, although, upon fiddling with the xml and skimming through the code, it seems that this pattern only works with <var name="map">. Puzzling and disappointing. I also have not been able to find even the slightest hint about the relevant xml schema in any documentation whatsoever...
Any idea on this? Thanks!
(I am working with Community Edition version 1.7.0.2)
If i understand right what you ask, you could overwrite the system/convert/profile/wizard.phtml from admin and add another section similar to existing map but the form elements should have name="gui_data[attribute_map]...[]".
Then you should overwrite the _parseGuiData method from Mage_Dataflow_Model_Profile to form the correct profile actions xml.
Hope that helps.
You can't, using the core implementation.
The var elements can only contain simple text, unless the element has the attribute name="map", in which case the profile parser will search for children map elements and use them to populate a php associative array.
The relevant code is inside the importProfileXml method of the Mage_Dataflow_Model_Convert_Profile_Collection class:
if ($varNode['name'] == 'map') {
$mapData = array();
foreach ($varNode->map as $mapNode) {
$mapData[(string)$mapNode['name']] = (string)$mapNode;
}
$container->setVar((string)$varNode['name'], $mapData);
}
To extend this behavior you should override this class with a custom (sub)class through the usual magento class override methods.

How to build CodeIgniter URL with hierarchy?

I know this doesn't exactly match the form of www.example.com/class/function/ID/, but what I want to display to the user would make more sense.
This is what I would like to do:
www.example.com/project/id/item/item_id/
So, an example would be:
www.example.com/project/5/item/198237/
And this would be the behavior:
www.example.com/project/ --> This would show a list of projects (current implementation)
www.example.com/project/5/ --> This would show a list of items on project 5 (current implementation)
www.example.com/project/5/item/ --> This wouldn't really mean anything different than the line above. (Is that bad?)
www.example.com/project/5/item/198237/ --> This would show details for item 198237.
So, each item is directly associated with one and only one project.
The only way I can think how to do this is to bloat the "project" controller and parse the various parameters and control ALL views from that "project" controller. I'd prefer not to do this, because the model and view for an "item" are truly separate from the model and view of a "project."
The only other solution (that I am currently implementing and don't prefer) is to have the following:
www.example.com/project/5/
www.example.com/item/198237/
Is there any way to build a hierarchical URL as I showed at the beginning without bloating the "project" controller?
There are 3 options, sorted by how practical they can be:
Use URI Routing. Define a regular expression that will use a specific controller/method combination for each URL.
Something like that could help you, in routes.php:
$route['project/'] = 'project/viewall';
$route['project/(.+)'] = 'project/view/$1';
$route['project/(.+)/item/'] = 'project/view/$1';
$route['project/(.+)/item/(.+)'] = 'item/view/$2';
That is, considering your controllers are item and project respectively. Also note that $n in the value corresponds to the part matched in the n-th parenthesis.
Use the same controller with (or without) redirection. I guess you already considered this.
Use redirection at a lower level, such as ModRewrite on Apache servers. You could come up with a rule similar to the one in routes.php. If you are already using such a method, it wouldn't be a bad idea to use that, but only if you are already using such a thing, and preferably, in the case of Apache, in the server configuration rather than an .htaccess file.
You can control all of these options using routes.php (found in the config folder). You can alternatively catch any of your URI segments using the URI class, as in $this->uri->segment(2). That is if you have the URL helper loaded. That you can load by default in the autoload.php file (also in the config folder).

Extend a Varien Form Element for a Custom Module

Improving on this question:
Is it good practice to add own file in lib/Varien/Data/Form/Element folder
The accepted answer shows how to extend a Varien form element, but this will not work if you want to package it into a custom module.
What would be the proper method of extending the Varien form element in a module? A simple XML setting I'm hoping?
Update:
Thanks Vinai for the response. Although that does work, I was hoping to extend the form element somehow. My extension is using the base File form element to allow administrators to upload files to categories. So, I'm not directly adding the form elements to the fieldset myself.
I suppose it's possible to to check for the file input on my category block on the backend: Mage_Adminhtml_Block_Catalog_Category_Tab_Attributes , and then change the form element if it is 'file' to 'mycompany_file' -- but this seems like a workaround.
Is there an easier way? Thanks again Vinai.
On the Varien_Data_Form instance you can specify custom element types like this:
$fieldset->addType('custom', 'Your_Module_Model_Form_Element_Custom');
Then, add your element with
$fieldset->addField('the_name', 'custom', $optionsArray);
If you are using a form without fieldsets you can do the same on the Varien_Data_Forminstance, too.
EDIT: Expand answer because of new additional details in the question.
In the class Mage_Adminhtml_Block_Widget_Form::_setFieldset() there is the following code:
$rendererClass = $attribute->getFrontend()->getInputRendererClass();
if (!empty($rendererClass)) {
$fieldType = $inputType . '_' . $attribute->getAttributeCode();
$fieldset->addType($fieldType, $rendererClass);
}
Because of this the attribute frontend_input_renderer on the attributes can be used to specify custom element classes.
This property can be found in the table catalog_eav_attribute, and luckily enough it isn't set for any of the category image attributes.
Given this, there are several ways to apply customizaton.
One option is to simply set the element class in the table using an upgrade script.
Another would be using an observer for the eav_entity_attribute_load_after event and setting the input renderer on the fly if the entity_type_id and the input type matches.
So it is a little more involved then just regular class rewrites in Magento, but it is quite possible.
You don't necessarily need to have a file in the lib/Varien/ directory in order to extend it. If you needed to add an element to that collection, you should be able to extend one of the Elements in your app/code/local module. The answer to the question you referenced seems to also indicate this is the case. I would create your custom field, extending its highest-level function set (i.e., lib/Varien/Data/Form/Element/File.php).
If you want to override the Mage_Adminhtml_Block_Catalog_Category_Tab_Attributes block, then you should extend that block in your module and then reference the new one. You may wish to extend the block using an event observer rather than an XML rewrite, for compatibility purposes.

Modifying view based on ACL in CakePHP

I want to be able to show or hide certain elements in a view based on ACL. For instance, if a user is looking at my Users/index view, I don't want to show a 'Delete User' element if he doesn't have permission to delete users. If he does have permission to edit users, I do want to show a 'Edit User' link.
I can hack this together, but being very new to Cake I'm hoping that there is an elegant solution. The best I've done involves keeping logic in two places, so it's hell to maintain.
Thanks!
I know this is an old question now but for anyone looking for a way like I was...
In AppController::beforeFilter you can assign the ACL component to a view variable and then use it in your view:
$this->set('user', $this->Auth->user());
$this->set('acl', $this->Acl);
And then in you view just juse it like thie:
if($acl->check(array('User' => $user), 'controllers/groupd/admin_delete')) {
This is't necessarily the most correct way to do it but it does work nicely
There is no generic "elegant solution" :) I've always wanted to make such thing as well. Anyway how you could do it:
Overwrite the Html Helper in your app directory - make a copy from /cake/libs/views/helpers/html.php to /app/views/helpers/html.php and made some changes in the Html::link function.
For example you can check if the url contain action edit or delete.
The other part is to pass the proper parameters from the controller. In AppController::beforeFilter you can read the rights of the user (it's better to be cached) and to pass it in a special Auth variable to the View.
So when you have the rights in your View it's easy to modify the link. :)
As I said I haven't did it in real example, but this is the way I would do it.
There is 1 bad point in that - if the original Html helper is changed, your one will remain the same. But I believe that Html helper is mature enough so for me is not a big issue.
I do it like this in app_controller.php, although you could just as well do it in specific controllers. The view variables $usersIndexAllowed and $configureAllowed are then used in conditional statements in the view.
function beforeRender()
{
if($this->layout=='admin')
{
$usersIndexAllowed = $this->Acl->check($user,"users/index");
$configureAllowed = $this->Acl->check($user,"siteAdmins/configure");
}
$this->set(compact('usersIndexAllowed','configureAllowed'));
}
In case you don't want to mess around with overriding core helpers and you want a more automatic way of checking (without hard-coding user group names and users or setting separate link-specific variables) here's my suggestion:
Store all user permissions as session vars when the user logs in (clear on logout) and create a permissions helper to check if logged on user has permissions for a specific action.
code and example here
hope that helps
There's multiple approaches to this scenario. As Nik stated, using a helper to do the checks for you is a quick way to "outsource" the logic and centralize it for ease of use.
Actually, have a look at the AclLinkHelper - it does exactly what you're looking for, however restricted to links only.

Resources