Automatically generating pages from app data - django-cms

I am a novice to Django CMS and am wondering what is the best way to do the following. I am running a Django CMS project together with a custom app that has an Event model for some (virtual) social events. Ideally I would like the url ^events/<event_id>/ to map to the appropriate event page for any valid Event id value. These event pages should look similar to my static pages, in particular using the same static placeholders and (ideally) inheriting from the same base template files.
What is the best way to achieve this? It appears from the documentation that a plugin or apphooks would allow me to attach app data to a Django CMS page, but with that approach I would have to manually create a Django CMS page for each event. Is there a way to avoid that?

Usually on SO you'd be asked to show what you've tried so far, but today is your lucky day 🎅🏼.
Here's a stub of how you could achieve what you're describing. Regarding placeholders, you can find more info in the documentation here and here.
Good luck!
models.py
class Event(models.Model):
name = models.CharField(max_length=200)
views.py
from django.views.generic import ListView, DetailView
class EventListView(ListView):
model = Event
template_name = "events/listview.html"
class EventDetailView(ListView):
model = Event
template_name = "events/detailview.html"
apphook_urls.py
urlpatterns = [
path('', EventListView.as_view(), name='event-list'),
path('<int:pk>/', EventDetailView.as_view(), name='event-detail'),
]
cms_apps.py
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
class EventsAppHook(CMSApp):
name = "Events"
app_name = "events
def get_urls(self, *args, **kwargs):
return ["events.apphook_urls"]
apphook_pool.register(EventsAppHook)
Once everything is up and running, you attach your AppHook to a cms page of your choice and you should be good to go.

Related

Silverstripe's Versioned feature for dataobjects in new release (3.2)

I want to audit-trail all changes made to dataobjects. Say I have Event dataobject and I want to know who changed it, when changed, what is changed etc. (Similar to Pages).
Silverstripe site recommends the use of Verioned but I can't find any examples of implementation. It says the best example is Pages which is is already comes with Versioned implemented. The basic rule is to define an augmentDatabase() method on your decorator.
So, I want to use DataExtention for dataobject (extension) and then use the extended one for my Event dataobject. But is there any simple example?
Assuming you want to manage and monitor multiple versions of the event DataObject, you simply need to declare that you want to use the versioned extension for thatDataObject
Class Event extends DataObject{
static $extensions = array(
"Versioned('Stage', 'Live')"
);
...
}
Then run a dev/build
You should now have a Event, Event_Live, and Event_versions tables.
You can then have a look at the methods available in Versioned.php, and use them with Event, ie publish(). This should get you started.
"Versioning in SilverStripe is handled through the Versioned class. It's a DataExtension, which allow it to be applied to any DataObject subclass."
"Similarly, any subclass you create on top of a versioned base will trigger the creation of additional tables, which are automatically joined as required."
Here is link to read further with examples
Versioning of Database Content

Converting my existing code to PageObject design pattern with PageFactory

I'm creating tests using Selenium 2 Web Driver with C#.Net. After reading through a lot of the Selenium documentation, I am not sure if I'm followign the correct design pattern and feeling unsure on how to go about testing using PageObject design patterns.
here is my current code that I'm using on my page and its working
WaitForElement(By.CssSelector("input#ctl00_ctl00_signinControl_txtUsername")).SendKeys("abc123");
WaitForElement(By.CssSelector("input#ctl00_ctl00_signinControl_txtPassword")).SendKeys("password");
SelectElement select;
IWebElement selElement = WaitForElement(By.CssSelector("select#ctl00_ctl00_ddlGoTo"));
select = new SelectElement(selElement);
select.SelectByText("Homepage");
*<more code .....>*
also I have told that I can not use Select page element using pageFactory.
Do I need to change my code the way I have coded? any feedback would be great.
The idea of the page object pattern is to have an object that represents the page. You are essentially writing an API for how to interact with the page.
For example a login page object may have the following methods:
enterUserName(String userName);
enterPassword(String password);
clickLoginButton();
The person using the page object to interact with the page does not need to care about how selenium finds elements and interacts with them. If the id on a field changes you would just need to change the locator on the page object and would not need to change all tests that call the associated page object public method.

Querying adapters against plone.directives.form.Schema

I have a form model created as following:
from plone.app.directives import Form
class IFormSchema(form.Schema):
foobar = schema.Bool(title=u"Just another field")
I'd like to register an adapter against this definition:
#component.adapter(IFormSchema)
#interface.implementer(ITreeSelectURLProvider)
def TreeSourceURL():
"""
"""
return "http://foobar"
The registration goes correctly.
However, there is an issue that I don't know if IFormSchema is directly provided by any object in any point of z3c.form processing chain, so that I could call:
provider = ITreeSelectURLProvider(someObject)
Does IFormSchema get directly applied to some object (zope.interface.directlyProvides?) in any point of z3c.form or plone.autoform chain
If not, what is the recommended practice so that I can register adapters against the model? What classes I should make to implement this interface?
To make matters worse, the context in the question is not a real content item but a subform object.
Dexterity make sure that the schema interface (be that defined on the filesystem and referenced in the FTI, or defined through the web or in an XML file) is provided by instances of the content type.
This isn't really about forms, it's about Dexterity. The form.Schema base class is just a marker that extends Interface, and which allows some of plone.autoform's processing to take place at configuration time.

How do I get the 'kind' of portlet (group/context/type) from it's renderer in Plone

Context:
I would like to build an URL to traverse to the current portlet to provide an external view rendering specific data.
Real use case:
I'm doing a video player which wait for an URL as parameters to get the video captions. Captions are stored in a schema.Text field. So the goal is to create a view to display theses data; something like:
/++contextportlets++plone.rightcolumn/test-video/##video_captions
So I'm in the python code renderer and I would like to build that URL from it. (self is renderer) I need:
kind of portlet in context, type, group
manager name (self.manager.name do the job)
portlet id (self.data.id do the job)
So the question is How do I get the kind of portlet from it's renderer.
The portlet category is only available from the portlet retriever. You can look it up by looping over the getPortlets method of the retriever. As the information that method returns deals with assignments, you'll need the portlet assignment (.data on a renderer), to pick out the correct entry:
from zope.component import getMultiAdapter
from plone.portlets.interfaces import IPortletRetriever
# This assumes you have the portlet context and manager as attributes of self,
# like in the renderer:
retriever = getMultiAdapter((self.context, self.manager), IPortletRetriever)
for info in retriever.getPortlets():
if info['assignment'] is self.data:
return info['category']

Setting the WebServiceWrapper endpointURI at run time

I'm in the middle of switching from Flex Builder 3 to Flash Builder 4, and one of the problems I have run into is that support for web services in 4 is substantially different. In both IDE's I am able to import a WSDL for my web service and it will generate the appropriate client classes for communicating with the service. The generated code in each is different.
In my Flex3 code I was able to access the endpointURI property of the mx.rpc.soap.AbstractWebService, but in the Flex4 code that is generated, the new class extends com.adobe.fiber.services.wrapper.WebServiceWrapper which does not have the endpointURI property.
My project has mulitple game servers and the player picks which server they want to play on. In the past if the player wanted server 1, I would set the endpoint URI to http://game1.server.com/service.asmx, and like wise if they wanted server 2 I would set the endpoint to http://game2.server.com/service.asmx.
What am I looking for to accomplish this in Flash Builder 4?
Short Answer:
var s:ClassThatExtendsWebServiceWrapper = new ClassThatExtendsWebServiceWrapper;
s.serviceControl.endpointURI = 'http://service.com/service.asmx';
Long Answer:
Well I finally found a solution. Adobe seems to have made this much harder than it should have been.
Web Service classes that are generated by Flash Builder 4 extend the com.adobe.fiber.services.wrapper.WebServiceWrapper. WebServiceWrapper has a property called serviceControl that can be used to control the service. The problem is that not all the members of serviceControl are accessible at the application code level. Lets assume that I have a web service called GameService. When I use the data tool to connect to the web service by providing a WSDL, Flash Builder will create two classes for me automcatically.
internal class _Super_GameService extends
com.adobe.fiber.services.wrapper.WebServiceWrapper
{ ... }
public class GameService extends _Super_GameService
{}
_Super_GameService contains all the automatically generated code to make calls to the web service. GameService contains no code itself, but unlike _Super_GameService, it is public. The idea here is that any enhancements that we need to make can be made to GameService, then later on if we need to update, _Super_GameService can be regenerated, but out changes to GameService will not be overwritten by the code generation tool.
Now this leads us to usage of these generated classes. Typically all I should have to do is create an instance of GameService and call a method on it. In this example DoSomethingAwesome is a method available on the web service.
var gs:GameService = new GameService();
var token:AsyncToken = gs.DoSomethingAwesome();
Now this will call the service using the URI of the service specified in the WSDL file. In my situation I wanted GameService to connect to a different URI. This should have been simple, but things fell apart.
My first problem was that viewing the documentation on WebServiceWrapper (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/com/adobe/fiber/services/wrapper/WebServiceWrapper.html) did not render properly in Firefox. So when I was reading the documentation I wasn't getting the full picture. This really needs to be fixed by Adobe.
Viewing the documentation in another browser helped me find out about the serviceControl property of WebServiceWrapper. serviceControl is declared as a mx.rpc.soap.AbstractWebService. AbstractWebService does have an endpointURI property which makes the following code valid.
var gs:GameService = new GameService();
gs.serviceControl.endpointURI = 'http://game1.service.com/GameService.asmx';
The other problem I had is that for some reason the endpointURI property of serviceControl does not appear in the Intellisense context menu. So since I didn't see serviceControl in the online documentation at first, and I didn't see endpointURI in intellisense, I didn't realize the property was there to be set.
If you look at the source for AbstractWebserivce, (http://opensource.adobe.com/svn/opensource/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/soap/AbstractWebService.as) there doesn't seem to be an Exclude tag to explain why endpointURI does not appear in the Intellisense context menu. So I don't know what is going on there.
You should be able to override the endpointURI on the WebService. But I'm not sure where to do that with the generated code since I use <s:WebService/>.
This is the only way I could get it to work, in the generated stub for your service:
import com.adobe.fiber.core.model_internal;
Also:
/**
* Override super.init() to provide any initialization customization if needed.
*/
protected override function preInitializeService():void
{
_needWSDLLoad = false; // to prevent loading the default WSDL
super.preInitializeService();
// Initialization customization goes here
wsdl = "http://localhost/yourservice?wsdl";
_needWSDLLoad = true;
model_internal::loadWSDLIfNecessary();

Resources