Composite C1 - MVC Player conflicting with Blog module - c1-cms

I have a composite C1 site - working fine. Some pages use the MVC Player - which works fine - along with all pages on the site - except the Blog which causes a routing conflict.
Error: The incoming request does not match any route.
C1 Function: Composite.AspNet.MvcPlayer.Render
Error details:
Exception has been thrown by the target of an invocation.
The incoming request does not match any route.
This error appears at the top of the page - the blog works fine under the error - I just need to get rid of the cause of this error. I guess the MVC controller is trying to route the blog pages because it thinks they don't exist & can't find the controller.
How can I get the controller to ignore the blog - or fix this some other way?

Short answer is that both items (blog and mvc player) are fighting over the path portion of your URL. They both expect they own the path into bit to do routing.
Example: /en/Blog /2011/11/29/Chamonix-To-Courmayeur-Skiing-Day-Trips
The /en/Blog portion is routing you to the page hosting your blog, while the rest is path info that is passed along to any functions you may have hosted on the page. Since the path is "one thing" there is no distinction whether this string is intended for the blog function or the MVC Player function. This is what is creating the confusion.
Provided you wish to leave the blog as is you can work around this issue in two ways:
Move the feature you have in MVC Player to another function provider, like Razor Functions
Change the MVC Player so it does not pass the path info along to you MVC controller.
The second workaround can be done quick and dirty by editing ~/App_Code/Composite/AspNet/MvcPlayer/Player.cs and commenting out this line (line 57)
Path = PathInfo;
Before you do this note that this would impact all your running instances of MvcPlayer.
To create a new alternative MvcPlayer which does not rely on routing (leaving the original one intact) do this:
Copy Player.cs to NoRoutePlayer.cs (and rename the class accordingly) and make the above mentioned change there (comment out line 57).
Then register this new function in Composite C1 by going to Functions | C# Functions | Composite | AspNet | MvcPlayer and add a node here, using the existing Render element as inspiration. Just set the 'Type' name to NoRoutePlayer.
With that change you will have a Player function and a NonRoutingPlayer function and you can then use the latter to run your MVC controller, and everyone should get along just fine :)

Related

Wagtail Page create via model_mommy

I'm trying to create some tests for my first Django site. One thing that is burdensome is creating example pages for testing (at least you have to specify a lot of parameters and some (such as ContentType) are not always obvious. More generally, I'd like to use Model Mommy to create many of the objects I need.
Near as I can tell, it can't create an instance of a Page (claiming that a "Page matching query does not exist"). [the test case is a simple import of Page and Model Mommy then create an instance of a page].
I'm not sure if this is properly an issue for Wagtail or for Model Mommy, but debugging it is getting a bit out of my depth and it would be very useful if it could work.
Unless there is something obvious I'm missing or can/should do, I'm posting this more to flag the problem than to try to get a solution right now.
Thx,
--Don
Mommy doesn't handle Django Tree Beard relations. Tree Beard is the package used by Wagtail to create the page tree.
Mommy doesn't create the tree structure correctly. You should add your pages to the tree yourself. You can do this with add_child.
Root is created by the Wagtail migrations: https://github.com/wagtail/wagtail/blob/master/wagtail/core/migrations/0002_initial_data.py#L13-L38
There is no need to set the content type manually if you use your specific class directly. I used FooPage in the example below.
from wagtail.wagtailcore.models import Page
from app.models import FooPage
root = Page.objects.get(slug='root')
page = FooPage(title='Example', ...)
root.add_child(instance=page)

templatetags and context['request']

So i'm learning Wagtail and trying to understand how to generate menus. So far i've found the bakerydemo repo helpful. One major point of confusion for me is understanding how to use the templatetags used for menus in the bakery demo. Below is the code for the get_site_root tag (django docs recommend that as of 1.11 that simple_tag will also work and so I changed it to that.)
#register.assignment_tag(takes_context=True)
def get_site_root(context):
# This returns a core.Page. The main menu needs to have
# the site.root_page
#defined else will return an object attribute error ('str' object
#has no attribute 'get_children')
return context['request'].site.root_page
No matter what I do I can't seem to get this to work. Either nothing is returned or I get various errors like the request key isn't in context or others. I looked at the Site middleware then traced that to the site model staticmethod "find_for_request" which in turn should be calling "get_site_for_hostname" in the sites.py . Anyways, I would love some guidance on what I am doing wrong or misunderstanding. Also, any help in understading the "wagtailthonic" way of generating menus from page hierarchies would be welcome.
Here is an image of the page and site tables.

Scrolling website with angular: states/routing setup

I can't seem to wrap my head around a routing setup for a project I'm working on at the moment. I tried ngRoute, angular-sement-router, now trying ui-router, however I'm still struggling to understand how to use them in my scenario.
I've attached an image to illustrate the kind of a thing I want to achieve. Basically, I need to have two types of pages — one type is a multi-section scrolling page. Another one is just a plain page with text and images.
The multi-section one should scroll to a certain section according to a current route. Each section has a set of subsections. So the route like
#!/section-2/subsection-2
should make the app scroll to Section-2 (smooth scrolling is not an issue at the moment) and activate Subsection 2.
I tried using named ui-views, but then I have to have an initial state of each named ui-view on my route state. It leads to another problem. If let's say I would navigate to
#!/section-1/subsection-1
my Section 1 subsection will return to whatever is set in the initial state.
Another issue is that my setup should separate Sections 1-4 from Section 5 which is a separate page.
I hope my description makes sense. Would love to here any advice on what I can read or where can I find some useful ideas. Thanks in advance.

adding controller later

I'm trying to create an NG app where parts can be enabled/disabled dynamically. The idea is to have an "admin" page, where parts of the app can be enabled or disabled, and then see new functionality appear, in the form of an adjusted menu at the top of the page, and matching routes, controllers, etc loaded into the app (I'm using SocketStream w/ NG).
The first step was to add / remove routes dynamically, for which I found a solution at https://stackoverflow.com/a/13173667 - working well, as far as I can tell.
Next, adding items to the menu bar - easy with ng-repeat on ul/li items.
So the app adjusts its menu and recognizes the corresponding route. So far so good.
The problem comes with registering a controller. I'm calling myApp.controller('SandboxCtrl',[...]) with proper args (same as what worked when initialising statically on startup), but the controller does not appear to get loaded or inited properly. Navigating to the newly added route generates errors such as:
Error: Argument 'SandboxCtrl' is not a function, got undefined
assertArg#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:973
assertArgFn#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:984
#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:4638
update#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:14007
$broadcast#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:8098
#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:7258
wrappedCallback#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:6658
wrappedCallback#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:6658
#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:6695
$eval#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:7848
$digest#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:7713
$apply#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:7934
#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:5433
I'm currently at a loss on how to proceed. I've not been able to find a solution on the web. The app is too large to put in a jsFiddle, but I can commit the last changes on GitHub if needed.
Questions: is this feasible? what can I do to debug this? any examples I could look at?
EDIT: The code is now at https://github.com/jcw/housemon (needs node/npm/redis). It's easy to reproduce the problem: launch with "npm start", browse to localhost:3333, go to admin tab, click on "jcw-sandbox" and then "Install". Top menu will update with new a "Sandbox" entry. Clicking on that entry generates the error shown above.
Oh, almost forgot: relevant code is in client/code/app/main.coffee and client/code/modules/routes.coffee ...
The answer turns out to be two-fold:
the NG calls were made from SocketStream RPC callbacks, and had to be wrapped in $scope.$apply calls - my bad, didn't know about this SS/NG interaction
the rest of the solution was outlined by #matys84pl - pick up $controllerProvider (and $filterProvider) early on, so they can be called at a later time instead of the normal "app.controller" and "app.filter" members, which don't seem to work anymore later on
Example code in GitHub, I'll link to a specific commit so this answer stays valid:
https://github.com/jcw/housemon/commit/f199ff70e3000dbf57836f0cbcbb3306c31279de

Dealing with Alias URLs in CakePHP

I am rewriting our company website in cakephp, and need to find a way to do the following:
A user enters our site by using one
of the promotional alias URLS that
has been pregenerated for a specific
media advert ( magazine, web
promotion etc )
The URL is checked against a
database of alias URLs, and if an
alias exists, then a specific
tracking code is written into the
session.
I have considered several options, none of which seem suitable for this purpose. They are:
Putting the lookup script in the
beforeFilter() in appcontroller, so
that its included in every
controller. (Writes a session value
so it only perfoms once.)
This option only works for existing contollers, and gives the
Cake 'missing controller' error if a
URL doesn't exist.
Specific routes for each alias in
Routes.php - Works but there are
potentially hundreds of alias urls
added/removed regularly via admin
interface.
Route all site URLs to their own
actions, and having an 'everything
else' rule, for the alias URLs that
maps to my lookup script. - Messy
and I lose the built in Cake
routing.
Custom 404. - I don't want to
return 404's for these urls, as I
feel its bad practice unless they
really don't map to anything.
I really could do with a place in the application flow where I can put this lookup/tracking script, and I'm fairly new to cake so I'm stumped.
EDIT: Also, I know that a subfolder called say 'promo' would easily do this, but I have a lot of legacy URLS from our old site, that need handling too.
Note: I'm making an assumption that your promo URLs are in the form of "domain.com/advert-259" or something like that (i.e. no "domain.com/adverts/advert-259'). That would be just too simple :)
Hopefully, you can use the routing with some regex. Add this to your /config/routes.php and let me know if a different regex will help :)
$controllers = Configure::listObjects('controller');
foreach ($controllers as &$value)
{
$value = Inflector::underscore($value);
}
Router::connect('/:promo', array('controller' => 'promos', 'action' => 'process'), array('promo' => '(?!('.implode('|', $controllers).')\W+)[a-zA-Z\-_]+/?$'));
Now you can handle all your promo codes in PromosController::process().
Basically, it checks for a promo code in url, excluding those in the $controllers array (i.e. your regular routes won't be messed up).
Later on you might want to consider caching the value of Configure::listObjects() depending on the speed of your app and your requirements.
A very interesting question. I think I would use item #3. It's not really that messy -- after all, this typically is handled by the pages controller in my stuff. That's how I'd handle it - hardcode your routes to your controllers in routes.php, then have a matchall route that will work for your promo codes. This allows you to keep legacy URLs, as well as use a lot of the standard cake stuff (you probably will just have to explicitly state each of your controllers routes, not such a chore...) Additionally, it will let you do some cool stuff with 404 errors -- you can put some logic in there to try and figure out where they were trying to go, so you can superpower your 404's.

Resources