Zope 5 dtml-if folder

I am trying to use a to check whether the url is in a certain path. Been playing around with this for a few hours now and am hoping someone knows how to accomplish it.

Let's say you have a folder structure of:

secure
secure/docs
secure/foo

what I want to do is check if I am only in secure OR if I am in secure/docs (and anything underneath docs, i.e. secure/docs/blah/blah) OR if I am in secure/foo (and anything underneath foo, i.e. secure/foo/blah/blah)

Doing a <dtml-if "not secure"> doesn't work because everything is traversed back to the root folder of secure. Using restrictedTraverse doesn't do anything because it's simply checking if what you are traversing to exists.

Just need that dtml-if statement so I can show or not show a piece of code based on where the user is browsing. Think of a navbar where you don't want to show a link to where you already are. That's the idea.

Look at the request attributes {URL,BASE}PATH (--> described in the Zope documentation). Split at /, if necessary.

I have been looking at all of that and cannot get it working, which is why I posted.

This code going to be inside a document located in secure/subfolder and called from everywhere on the site.

With obj.aq_inner.aq_parent you can get obj's container. Not sure that those attributes are accessible in untrusted code; you may need a trusted helper.

You can also try obj.getPhysicalPath(), potentially via a trusted helper.

If I don't have to, I would rather not use a separate python script to do this.

Is there a way to use restricted traverse (or something similar) to say it has to include the full path given?

Like <dtml-if "restrictedTraverse('/secure/foo')">blah</dtml-if>

Check whether getPhysicalPath can be used by anonymous users.

Even if it can, how specifically would you solve this issue using it?

For example, here's a quick python script:

fullstring = context.getPhysicalPath()
substring = "foo"

if substring in fullstring:
    print("true")
else:
    print("false")
return printed

That script works and returns true or false properly. However, using a dtml-if like this:

<dtml-if expr="'foo' in getPhysicalPath()">

does not work.

Read a DTML reference: when I remember right then there is a variable (this?) which refers to the top level element of the DTML namespace stack. You could call getPhysicalPath as method of this variable.

Alternatively, you could use a dtml-let to bind the result of a getPhysicalPath call to a variable and use this variable.

Finally, you could use a page template (instead of DTML): better documented, easier to grasp, less help required.

I don't think you're understanding the issue. getPhysicalPath() returns a tuple which contains various strings. If a doc is located in secure/foo/blah binding a variable to getPhysicalPath() still means I would need to test against the result for a string called foo.

The question is how to test for that string when I can do it in a python script and get a correct result but cannot in a dtml-if expression (which makes no sense btw).

The python script example I posted above quite literally says if "foo" in getPhysicalPath() which is exactly what I wrote in the dtml-if expr, with the exception of using single quotes around foo because you cannot use double quotes in a dtml-if expr.

The thing between double quotes in a DTML expression is a Python expression. Thus, you use Python as usual to test whether a string is in a tuple or is the i. element of a tuple -- you already did this in a Python script.

Your only problem is how to get at the equivalent of context (--> read the DTML reference to find out) or how you get at the result of the method call without explicitly refering to the context (--> try dtml-let).

This will be my last answer.

I solved it, but continuously saying "read the docs" after I have repeatedly said I have read the docs, isn't very helpful. People post on this forum to receive either pointers in the right direction, links to docs that specifically address their issue, OR actual solutions.

To respond to your last post, context cannot be used in a dtml expr. It does not work because context is automatically implied. You only use the function not context.function. Also, I am aware that you use double quotes in a python script and single quotes in a dtml expr. Hence the fact that I posted actual code stating that fact.

The actual answer to this is that since getPhysicalPath returns a tuple, you cannot just test for a string directly, you have to test for a string that is in a certain index of the tuple (i.e. if you have a let saying dtml-let myURL="getPhysicalPath() then you can say dtml-if expr="'test' == myURL[2]

One final update to show an actual solution for anyone who might need it.

  1. Create a dtml-doc with the content you want to call all over your website. For me it was a navmenu that I placed in a folder called sitefiles.

  2. Surround your call to that dtml-doc like this (surrounded with the dtml-let):

<dtml-let myURL="'/'.join(getPhysicalPath())">
<dtml-var "sitefiles.navmenu(None, _)">
</dtml-let>

Obviously you can change myURL to anything you want. It's just a variable name.

While getPhysicalPath() returns a tuple, using join transforms that into /foo/blah/whatever so you can then use a normal "string in" rather than being forced to test whether a string equals a certain place in the tuple index.

In the navmenu dtml-doc, you put all your relevant code. One example of how to check if you are in the folder foo, which would mean you do not wish to display the link to foo because you are already there, would be:

<dtml-if expr="'foo' not in myURL">
<li><a href="https://www.domain.com/secure/foo">Foo</a></li>
</dtml-if>

The biggest thing to watch out for with this solution is that since you are creating the dtml-let in various locations, while referencing the variable you are creating (i.e. myURL) in the main navmenu file, if you do not have the let, your site will error. As this is a navmenu which appears on every page of the website, that would take your entire site down. So, be careful.