Accessing pages file widget file

16 views
Skip to first unread message

Fotis Paraskevopoulos

unread,
Mar 12, 2015, 9:03:04 AM3/12/15
to apostr...@googlegroups.com
Hello,

I am encountering a weird issue which I would like to get to the bottom of. I have an apostrophe-fancy page with a singleton of widgetType  "files".


'brands':{
extend: 'apostrophe-snippets',
name: 'brands',
label: 'Brands',
instance: 'brand',
instanceLabel: 'Brand',
addFields:[
{
name:'brochure',
type: 'singleton',
widgetType: 'files',
options:{
limit: 1
}
}
]
},


Through a bridge I access the get method of this snippet in another module. This other module has a page loader function, and what it does is basically list all the brands with a link to the file if available.

The problem I am encountering is in the get method of the snippet. I define option.areas=true so that I can get the areas in the returned snippet document. And then I use 

apos.areaFile(brand,"brochure"); //brand is the snippet

To get the path of the pdf file. It turns out that the "areaFile" method checks if the area contains an internal "_items" property. 

It so happens that when I use the request "req" object for the snippets get method the area is returned properly but that "_items" property is not set. However if I use apos.getTaskReq()  instead, then it all works.

I am assuming this has something to do with permissions, so I also tried the options.permissions=false, but that didn't seem to work.

To summarize, is it the best practice to use apos.getTaskReq to bypass permission constraints? Why is it that that file is bound to permissions, I mean the user is just browsing the site, there is no need for the user to be logged in to see the file.


Any insight would be great.

Best,
Fotis



Tom Boutell

unread,
Mar 12, 2015, 10:17:46 AM3/12/15
to apostr...@googlegroups.com
Definitely not. You should not be bypassing permissions constraints.

My guess is there's another explanation, since widget loaders are
always called on any invocation of apos.get. You'd have to go well out
of your way to prevent it (areas: false).
> --
> You received this message because you are subscribed to the Google Groups
> "apostrophenow" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to apostropheno...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.



--


THOMAS BOUTELL, DEV & OPS
P'UNK AVENUE | (215) 755-1330 | punkave.com

Tom Boutell

unread,
Mar 12, 2015, 10:18:10 AM3/12/15
to apostr...@googlegroups.com
If you can boil this down to a simple demonstration in the sandbox I
can take a peek.

Fotis Paraskevopoulos

unread,
Mar 12, 2015, 2:11:30 PM3/12/15
to apostr...@googlegroups.com
Hi Tom,

I was able to reproduce the issue in this project 


Once you set it up, just add a "Brand" with a pdf file, and create a new page of "Brands Page" type.

The error occurs here



I hope you can shed some light.

Best,
Fotis


Fotis Paraskevopoulos

unread,
Mar 13, 2015, 9:48:37 AM3/13/15
to apostr...@googlegroups.com
Hello Tom,

Did you by any chance take a look at this, I am quite sure there is a bug somewhere in there.

FP

Tom Boutell

unread,
Mar 13, 2015, 10:45:25 AM3/13/15
to apostr...@googlegroups.com
I have some projects on the front burner today, but I will try to look
at it over the weekend.

On Fri, Mar 13, 2015 at 9:48 AM, Fotis Paraskevopoulos

Fotis Paraskevopoulos

unread,
Mar 13, 2015, 10:46:31 AM3/13/15
to apostr...@googlegroups.com
Thanks Tom, no pressure ;)

Fotis Paraskevopoulos

unread,
Mar 19, 2015, 8:11:46 AM3/19/15
to apostr...@googlegroups.com
Hi Tom,

Can you tell me where the ._items is created when loaded from the Widget code, I can't find it in the "apostrophe" module. I literally get lost in the code ;)

FP



Tom Boutell

unread,
Mar 19, 2015, 10:10:14 AM3/19/15
to apostr...@googlegroups.com
What kind of widget Fotis?

(In 0.6 each widget will be an a2 module so it's not such a pain to find that code.)

Tom Boutell

unread,
Mar 19, 2015, 10:10:33 AM3/19/15
to apostr...@googlegroups.com
Also are you talking about the ._items in an area, or the ._items in a snippet widget...

Fotis Paraskevopoulos

unread,
Mar 19, 2015, 10:14:51 AM3/19/15
to apostr...@googlegroups.com
In this fork of sandbox I am talking about the ._items in an area.

FP

Tom Boutell

unread,
Mar 19, 2015, 1:16:50 PM3/19/15
to apostr...@googlegroups.com
I misspoke, an area doesn't have a ._items property, it has a .items property. And that is a real property of the object which lives right in mongodb. It's an array of items (widgets and rich texts).

I suspect you didn't really mean that, though, so please be more specific.

Thanks!

Fotis Paraskevopoulos

unread,
Mar 19, 2015, 1:29:59 PM3/19/15
to apostr...@googlegroups.com
Hi,

I boiled it down to a fork of the sandbox here


Once you set it up, just add a "Brand" snippet with a pdf file, and create a new page of "Brands Page" type.

You can see that the _items is not set here.




Basically I have snippet with a singleton of widgetType  "files".

'brands':{
extend: 'apostrophe-snippets',
name: 'brands',
label: 'Brands',
instance: 'brand',
instanceLabel: 'Brand',
addFields:[
{
name:'brochure',
type: 'singleton',
widgetType: 'files',
options:{
limit: 1
}
}
]
},


Through a bridge I access the get method of this snippet in another module. This other module has a page loader function, and what it does is basically list all the brands with a link to the file if available.

I try to get the path of the pdf file but it turns out  the "areaFile" method fails on the if statement that checks if the area contains an internal "_items" property. 

It so happens that when I use the request "req" object for the snippets get method the area is returned properly but the "_items" property is not set. However if I use apos.getTaskReq()  instead, then it all works.

I hope this is more clear now.

Thank you for your time.

Cheers,
Fotis


Tom Boutell

unread,
Mar 19, 2015, 5:20:53 PM3/19/15
to apostr...@googlegroups.com
You're right Fotis, this is a deep one.

For performance reasons, all file joins are deferred via Apostrophe's deferredLoads mechanism rather than being joined one set of results at a time.

One big query happens just before the template for the page is rendered. The properties aren't available until that time.

But I think what you're trying to do here with your ._pdf property can be done just as easily in the page template. Nunjucks has access to all that areaFile stuff too.

{% set pdf = aposAreaFile(page, 'brochure', { extension: 'pdf' }) %}

Also, be aware that a snippet index page already has a loader, all the brands are already available in index.html as "items". (Or rather, one page's worth of them is available. If that's bothering you, you can set the perPage option higher for that module.)


So... you probably have a lot of extra JavaScript (:

Fotis Paraskevopoulos

unread,
Mar 20, 2015, 3:27:39 AM3/20/15
to apostr...@googlegroups.com
Hi Tom,

Thanks for the insight. However the above was just an example to present the problem to you. My use case does not allow the logic for move up to the front, that piece of logic needs to stay in the Controller layer. For example, I want to return a list of snippets which **have** a file and ignore the rest, the issue is not so much presenting the file.

Also when I use apos.getTaskReq() this problem/issue/feature does not present itselft so I am going to stick with that for now.

Hopefully this is something that you can consider for 0.6. 

To better clarify my requirement; The page dialog is not the best UI possible for all possible scenarios, even though it is excellent 90% of the time, there is that 10% where we need flexiblity. To be honest I am not just there yet with the internals of apostrophe, but I am getting there, however I believe that I have pushed it way outside its confort zone :). There are times where I would like my user to build an object in a page like interface, and I can achieve this by having pages of a specific type, and adding styled widgets all around. Then accessing the objects (a subtree of pages) from the database and using the helpers available in apos build lists, grids, menus and so on.

I cant see why a snippet in A2 which sort of like a node in Drupal can't have a file attached to it in the simplest possible way, or that there is not way to access the full object if the delevoper requires it. As a side note, one of the main reasons we had dropped Drupal back in the day was that bloody "node" object, please try to steer away from that path, the snippet is heading there.

We can continue discussing this if you feel it can help developing a more flexible snippet or developer API for the future.

Cheers,
Fotis



Tom Boutell

unread,
Mar 20, 2015, 9:20:29 AM3/20/15
to apostr...@googlegroups.com
getTaskReq is evil (: People are going to see content on pages they are not allowed to see by your permissions.

I don't see what this has to do with whether you're using page settings or something else... that sounds like an unrelated issue. But I understand that it's a pain for you that you can't "see" the joined files until it's too late for your needs.

We should talk about an API that would accommodate you without making our sites slower by forcing every slideshow widget on the page to do its own query for files. That's the question here, it's really not about "nodes" or page settings (:

Maybe we should just provide a flag to shut deferred joins off. Maybe there's a way to provide that flag for a single get() call, but I'm not sure we could easily accommodate that without changing all of the APIs to propagate the flag.

Perhaps the best API would be something like:

    self._brands.get(req, {}, {areas:true}, function (err, results) {

      if(err || results.total <=0){
        return callback();
      }
      req.afterDeferredLoads(function() { ... the rest of your logic ... });
      return callback(null);
    });

There wouldn't be any sacrifice of performance, and you'd be able to explicitly run code after deferred loads are complete.

Fotis Paraskevopoulos

unread,
Mar 20, 2015, 9:24:39 AM3/20/15
to apostr...@googlegroups.com
Hello Tom,

Yes I can see where you are coming from. I am not so worried about getTaskReq since I am filtering the results myself anyways.

You callback suggestion makes sense to me, but I am wondering why you are not calling the callback inside the afterDeferredLoads function.


So to sum up, I will stick with getTaskReq for now; Be really really carefull about the permissions and hope for the best :)

FP


Tom Boutell

unread,
Mar 20, 2015, 12:44:51 PM3/20/15
to apostr...@googlegroups.com
We don't have such a callback for you yet, it's a proposed API.

Fotis Paraskevopoulos

unread,
Mar 20, 2015, 1:19:22 PM3/20/15
to apostr...@googlegroups.com
Yes I got that, its just the geek in me.

Tom Boutell

unread,
Mar 26, 2015, 3:35:08 PM3/26/15
to apostr...@googlegroups.com
Fotis, I'm back in the swing of things after a vacation and I just figured out what you meant about calling the callback in the afterDeferredLoads function. It's a good question.

The issue is that we're in the process of invoking widget loaders for many widgets on many pages. And we do those in series, to avoid bombarding mongodb with an unpredictable number of simultaneous queries.

So when we invoke the callback, we're not really saying "we did everything." We're saying "we loaded your documents; it's safe to do more work. We'll finish loading the widgets at a sensible time."

When the page is about to be rendered, the pages module invokes the deferred loaders - merging all compatible calls (calls for the same widget type, basically) into a single call. But if we waited until then to invoke your callback, you would never make the additional widget loader calls we're wanting you to make.

As you point out, this is a pain for what you're trying to do. But, the performance benefit is significant.

So: it's tricky.









Reply all
Reply to author
Forward
0 new messages