HippoCMS Rest service does not return image links - rest

I'm a new bee to Hippo CMS. I'm working on version 10 and I'm using angularJS service to consume the rest url for "banners" I created through HippoCms.
This is my Rest URL for Banners created via Hippo's Rest Api Manager:
http://localhost:8080/site/stbetrest/Banner?_type=json
and the reponse I'm getting when consumed the link is:
{
"pageSize": 10,
"total": 3,
"items": [
{
"content": "<![CDATA[\r\n\r\n <p>Banner description</p>\r\n\r\n \r\n]]>",
"title": "Sample banner"
},
{
"content": "<![CDATA[<p>10 Simple Steps to Green Your Office:</p>\n\n<p> </p>\n\n<p>
<img src=\"/site/pagenotfound\" /></p>]]>",
"title": "10 Simple Steps to Green Your Office"
},
{
"content": "<![CDATA[<p>How to Green Your Dorm Room</p>]]>",
"title": "How to Green Your Dorm Room"
}
],
"currentPage": 1,
"totalPages": 1
}
The Problem here is I can't see the Images I used inside the banner documents in Hippo. I want to get those Images/links to load them into a carousel created in AngularJs. Please guide me how to generate the images also into the above banner response.
UPDATE:
All though via the 'localhost:8080/cms' it shows uploaded images, but can not access the image via response:
#XmlRootElement(name = "banner")
#XmlAccessorType(XmlAccessType.NONE)
#HippoEssentialsGenerated(internalName = "gogreen:bannerdocument")
#Node(jcrType = "gogreen:bannerdocument")
public class Banner extends BaseDocument {
#XmlElement
#HippoEssentialsGenerated(internalName = "gogreen:title")
public String getTitle() {
return getProperty("gogreen:title");
}
#XmlJavaTypeAdapter(HippoHtmlAdapter.class)
#XmlElement
#HippoEssentialsGenerated(internalName = "gogreen:content")
public HippoHtml getContent() {
return getHippoHtml("gogreen:content");
}
#HippoEssentialsGenerated(internalName = "gogreen:link")
public HippoBean getLink() {
return getLinkedBean("gogreen:link", HippoBean.class);
}
#XmlJavaTypeAdapter(KerkRestAdapter.class)
#XmlElement
#HippoEssentialsGenerated(internalName = "gogreen:image")
public Kerk getImage() {
return getLinkedBean("gogreen:image", Kerk.class);
}
}
and my Content rewriter is :
public class RestContentRewriter extends SimpleContentRewriter {
#Override
protected String rewriteBinaryLink(String binaryLinkSrc, Node node, HstRequestContext requestContext, Mount targetMount) {
return super.rewriteBinaryLink(binaryLinkSrc, node, requestContext, requestContext.getMount("site"));
}
And My Adapter is:
public class KerkRestAdapter extends XmlAdapter<String, HippoHtml> {
#Override
public HippoHtml unmarshal(String representation) throws Exception {
throw new UnsupportedOperationException("Unmarshalling not implemented.");
}
#Override
public String marshal(HippoHtml html) throws Exception {
if (html == null) {
return null;
}
final HstRequestContext context = RequestContextProvider.get();
//final RestContentRewriter contentRewriter = new RestContentRewriter();
final ContentReWriter<String> contentRewriter = new RestContentRewriter();
final String rewrite = contentRewriter.rewrite(html.getContent(), html.getNode(), context, context.getMount("api"));
return "<![CDATA[" + rewrite + "]]>";
}
}
additional Question: what is the mount point to be used in rewriter? ( Rest mount name or gogreen??)
Please help !

You have used the Essentials Rest setup tool. That generates a example or demo Rest implementation. After generating the setup a developer shall always want to extend and refine the result.
The links inside rich text in this setup are by default generated for the current mount, which is the rest mount. Since the images are not available through the rest mount, HST generated the /pagenotfound URL.
If you inspect the bean for the Banner you see that for the HippoHtml field an HippoHtmlAdapter is used. Check the code of it: it uses the SimpleContentRewriter. Create your own version of the Adapter and use an extended version of the ContentRewriter. Override the #rewriteBinaryLink method. In it call the super method, but specify the site mount as the target mount.
I think adding an hst:alias to the site mount is a good idea so you can reference the site with the alias.

Related

Liferay create a custom PanelCategory for multiple portlet

I use Liferay 7.2 and Liferay IDE (eclipse). I created two separate Liferay admin portlet to creating a view for the database entries. I added in the first portlet "Teachers" a new panel called school with this generated code in application.list Package.
here is the code of - PanelApp.java
#Component(
immediate = true,
property = {
"panel.app.order:Integer=300",
"panel.category.key=" + TeachersPanelCategoryKeys.CONTROL_PANEL_CATEGORY
},
service = PanelApp.class
)
public class TeachersPanelApp extends BasePanelApp {
#Override
public String getPortletId() {
return TeachersPortletKeys.TEACHERS;
}
#Override
#Reference(
target = "(javax.portlet.name=" + TeachersPortletKeys.TEACHERS+ ")",
unbind = "-"
)
public void setPortlet(Portlet portlet) {
super.setPortlet(portlet);
}
}
.
public class TeachersPanelCategoryKeys {
public static final String CONTROL_PANEL_CATEGORY = "Teachers";
}
And here is the code of - PanelCategory.java
#Component(
immediate = true,
property = {
"panel.category.key=" + PanelCategoryKeys.SITE_ADMINISTRATION,
"panel.category.order:Integer=300"
},
service = PanelCategory.class)
public class TeachersPanelCategory extends BasePanelCategory {
#Override
public String getKey() {
return TeachersPanelCategoryKeys.CONTROL_PANEL_CATEGORY;
}
#Override
public String getLabel(Locale locale) {
return LanguageUtil.get(locale, "School");
}}
And here is the code of portlet.java
#Component(
immediate = true,
property = {
"com.liferay.portlet.add-default-resource=true",
"com.liferay.portlet.display-category=category.hidden",
"com.liferay.portlet.header-portlet-css=/css/main.css",
"com.liferay.portlet.layout-cacheable=true",
"com.liferay.portlet.private-request-attributes=false",
"com.liferay.portlet.private-session-attributes=false",
"com.liferay.portlet.render-weight=50",
"com.liferay.portlet.use-default-template=true",
"javax.portlet.display-name=Teachers",
"javax.portlet.expiration-cache=0",
"javax.portlet.init-param.template-path=/",
"javax.portlet.init-param.view-template=/view.jsp",
"javax.portlet.name=" + TeachersPortletKeys.TEACHERS,
"javax.portlet.resource-bundle=content.Language",
"javax.portlet.security-role-ref=power-user,user",
},
service = Portlet.class
)
public class TeachersPortlet extends MVCPortlet {
// some code to get entries from db
#Override
public void doView(final RenderRequest renderRequest, final RenderResponse renderResponse)
throws IOException, PortletException {
// some code
Now I want to add the second created portlet "Students" under the same Panel "School". I created it in the same way as "Teachers" but now I have two school panel. As it is shown in the image below.
I just want to display one panel category called school that contain both Teachers and Students in the list.
I do not know how I can think to do that.
As you're implementing a TeachersPanelCategory, I'm assuming you're also implementing a StudentsPanelCategory. From a naming perspective, I'd have expected a SchoolPanelCategory.
I'm currently at a loss of how the ControlPanel portlets actually declare their associated panel, but that place would be where you pick the common "school" panel and use the same spelling for both.
In other words: If you deploy two panels with the same name, I'd expect exactly what you document here. Make sure you're only deploying one of them
Edit: I'd like to know what TeachersPanelCategoryKeys.CONTROL_PANEL_CATEGORY is defined as, and the corresponding (assumed, not shown) StudentsPanelCategoryKeys.CONTROL_PANEL_CATEGORY. Both categories have the same label, but if they have different keys, they'll be different. I'm not sure what happens when you deploy two components with the same key: You should deploy only one.
Edit2: I've missed the code before: You're producing the key to your first category as "Teachers", and the label as "School". I'm assuming that the key for your other category is "Students". Liferay organizes the categories by key - and if the keys are different, then you'll end up with two different categories. Make their key more similar to their name (e.g. create a single SchoolCategory and associate your portlets/panelApps with that:
#Component(
immediate = true,
property = {
"panel.category.key=" + PanelCategoryKeys.SITE_ADMINISTRATION,
"panel.category.order:Integer=300"
},
service = PanelCategory.class)
public class SchoolPanelCategory extends BasePanelCategory {
#Override
public String getKey() {
return "school"; // this is the category that you want to associate with
}
#Override
public String getLabel(Locale locale) {
return LanguageUtil.get(locale, "School");
}
}
and
#Component(
immediate = true,
property = {
"panel.app.order:Integer=300",
"panel.category.key=school" // referencing the category created above
// (use the same for your StudentsPanelApp)
},
service = PanelApp.class
)
public class TeachersPanelApp extends BasePanelApp {
#Override
public String getPortletId() {
return TeachersPortletKeys.TEACHERS;
}
#Override
#Reference(
target = "(javax.portlet.name=" + TeachersPortletKeys.TEACHERS+ ")",
unbind = "-"
)
public void setPortlet(Portlet portlet) {
super.setPortlet(portlet);
}
}
(See the one-line comments within the code for the critical lines. Replace with proper constants if you like)

kendo ui grid not working with .net core

I am trying to get Kendo UI grid MVC working in a .net core, reading data from PostgreSQL database.
I set up a project, connected it to a database, scaffolded controller with appropriate views and it's working ok (meaning CRUD operations are working ok).
Now I want to hook it up with Kendo.
I followed guide from kendo website and installed successfully (although it didn't offer pro version in nugget so I had to install trial??). I added all those CSS/js files in _Layout.cshtml
this is my code in controller:
public ActionResult kendo()
{
return View();
}
// GET for Kendo
public ActionResult Categories_Read([DataSourceRequest] DataSourceRequest request)
{
return Json(GetCategories().ToDataSourceResult(request));
}
public static IEnumerable<Category> GetCategories()
{
var result = from c in _context.Categories
select new Category()
{
Id = c.Id,
Name = c.Name
};
return result;
}
this is my code in kendo.cshtml
#(Html.Kendo().Grid<Category>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.Id).Title("id");
columns.Bound(c => c.Name);
})
.HtmlAttributes(new { style = "height: 550px;" })
.Scrollable()
.Groupable()
.Sortable()
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
.ButtonCount(5))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("Categories_Read", "Categories"))
.PageSize(20)
)
Model is simple
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
The problem is that there is no data displayed in kendo grid. I can see in debugger that there is request going forward and data coming backwards but nothing is shown in grid.
?
The problem is most probably caused by the new ASP.NET Core serialization mechanism. Follow the guidelines in the "second" Step 4 here:
http://docs.telerik.com/kendo-ui/aspnet-mvc/mvc-core/getting-started
Step 4 Open Startup.cs, using a text editor (IDE) and update it as described below.
Locate the ConfigureServices method and add a call to services.AddKendo at the end.
public void ConfigureServices(IServiceCollection services)
{
...
// Maintain property names during serialization. See:
// https://github.com/aspnet/Announcements/issues/194
services
.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
// Add Kendo UI services to the services container
services.AddKendo();
}
Locate the Configure method and add a call to app.UseKendo at the end.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
// Configure Kendo UI
app.UseKendo(env);
}
UPDATE
In order to verify that the above configuration is applied, check the server response and see if it has the following structure and letter casing for Data and Total:
{
"Data": [
{ "Id": "1", "Name": "Name 1" },
{ "Id": "2", "Name": "Name 2" }
],
"Total": "2"
}
I had the same problem in a .net core 3.1 project, the solution here is to add the following lines in Startup.cs:
services
.AddMvc()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
services.AddKendo();

Configuration for loading story from String?

I have a web service posting Gherkins stories to a back-end and would like to load those stories into configuration as a string without having to save them as a file.
Can this be accomplished?
You need to implement your custoom story loader that will collect stories from the web service and pass them to JBehave.
You need also use a GherkinStoryParser to translate stories from Gherking format to JBehave format.
An example configuration might look like in the following example.
A custom story loader that retrieves stories from a map of strings:
public class MyStoryLoader implements StoryLoader {
private Map<String,String> stories;
public MyStoryLoader( Map<String,String> storiesToLoad){
this.stories = storiesToLoad;
}
public String loadStoryAsText(String storyName) {
return stories.get( storyName );
}
}
Some class that collects stories from the web service and return them as a map with unique story names and story bodies:
public class StoryCollectorFromWebService {
private final static String storyTemplate = "Feature: A story that is saved in the string\n"
+ "\n"
+ "Scenario: Read the scenario from the string\n"
+ "\n"
+ "Given There is some story named ${name} saved in the string\n"
+ "When I run this story named ${name}\n"
+ "Then I can see it's results";
// This is a method that collects stories from the Web Service and saves them in a map of strings
public Map<String,String> getStoriesFromWebService(){
Map<String,String> storiesFromWebService = new HashMap<String,String>();
String storyNames[] = {"A","B","C","ABC","Some story", "Another story"};
for(String storyName: storyNames)
storiesFromWebService.put( storyName, storyTemplate.replace("${name}", storyName));
return storiesFromWebService;
}
}
and sample configuration to run these stories using our StoryLoader and GherkinStoryParser:
public class RunAs_JUnitStories extends JUnitStories {
public RunAs_JUnitStories() {
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
.doIgnoreFailureInView(true).useThreads(1).useStoryTimeoutInSecs(60);
}
Map<String,String> storiesFromWebService = new StoryCollectorFromWebService().getStoriesFromWebService();
#Override
protected List<String> storyPaths() {
return new ArrayList<String>( storiesFromWebService.keySet());
}
#Override
public Configuration configuration() {
Class<? extends Embeddable> embeddableClass = this.getClass();
ParameterConverters parameterConverters = new ParameterConverters();
ExamplesTableFactory examplesTableFactory = new ExamplesTableFactory(new LocalizedKeywords(), new LoadFromClasspath(embeddableClass), parameterConverters);
parameterConverters.addConverters(new DateConverter(new SimpleDateFormat("yyyy-MM-dd")),
new ExamplesTableConverter(examplesTableFactory));
return new MostUsefulConfiguration()
// Use custom story loader
.useStoryLoader(new MyStoryLoader( storiesFromWebService ))
// Use Gherkin parser
.useStoryParser( new GherkinStoryParser() )
.useStoryReporterBuilder(new StoryReporterBuilder()
.withCodeLocation(CodeLocations.codeLocationFromClass(embeddableClass))
.withDefaultFormats()
.withMultiThreading(true)
.withFormats(CONSOLE, TXT, HTML, XML))
.useParameterConverters(parameterConverters);
}
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new MySteps());
}
}
Here is a link to a working example: https://github.com/kordirko/TestJBB
You can try import it into Eclipse and play with it, but I apologize if something goes wrong,
It's my first project on github, I'am still learning how to do it :)

How to find out component-path

I use junit to assert the existing of wicket components:
wicketTester.assertComponent("dev1WicketId:dev2WicketId:formWicketId", Form.class);
This works for some forms. For complex structure, it is defficult to find out the path of the form by searching all html files. Is there any method how to find out the path easy?
If you have the component you can call #getPageRelativePath(). E.g.
// Supposing c is a component that has been added to the page.
// Returns the full path to the component relative to the page, e.g., "path:to:label"
String pathToComponent = c.getPageRelativePath();
You can get the children of a markup container by using the visitChildren() method. The following example shows how to get all the Forms from a page.
List<Form> list = new ArrayList<Form<?>>();
Page page = wicketTester.getLastRenderedPage();
for (Form form : page.visitChildren(Form.class)) {
list.add(form);
}
An easy way to get those is to call getDebugSettings().setOutputComponentPath(true); when initializing your application. This will make Wicket to output these paths to the generated HTML as an attribute on every component-bound tag.
It's recommended to only enable this on debug mode, though:
public class WicketApplication extends WebApplication {
#Override
public void init() {
super.init();
if (getConfigurationType() == RuntimeConfigurationType.DEVELOPMENT) {
getDebugSettings().setOutputComponentPath(true);
}
}
}
Extending the RJo's answer.
It seems that the method page.visitChildren(<Class>) is deprecated (Wicket 6), so with an IVisitor it can be :
protected String findPathComponentOnLastRenderedPage(final String idComponent) {
final Page page = wicketTester.getLastRenderedPage();
return page.visitChildren(Component.class, new IVisitor<Component, String>() {
#Override
public void component(final Component component, final IVisit<String> visit) {
if (component.getId().equals(idComponent)) {
visit.stop(component.getPageRelativePath());
}
}
});
}

How to translate,use JSON in GWT?

I'm new in gwt. and need to know how to use JSON in gwt so i try this simple data loader but i'm still confuse.
I create a project named 'tesdb3' in eclipse. I create the PHP side to access the database, and made the output as JSON.. I create the userdata.php in folder war. then I compile tesdb3 project. Folder tesdb3 and the userdata.php in war moved in local server(I use WAMP). I put the PHP in folder tesdb3. This is the result from my localhost/phpmyadmin/tesdb3/userdata.php
[{"kode":"002","nama":"bambang gentolet"}{"kode":"012","nama":"Algiz"}]
From that result I think the PHP side was working good.Then I create UserData.java as JSNI overlay like this:
package com.tesdb3.client;
import com.google.gwt.core.client.JavaScriptObject;
class UserData extends JavaScriptObject{
protected UserData() {}
public final native String getKode() /*-{ return this.kode; }-*/;
public final native String getNama() /*-{ return this.nama; }-*/;
public final String getFullData() {
return getKode() + ":" + getNama();
}
}
Then Finally in the tesdb3.java:
public class Tesdb3 implements EntryPoint {
String url= "http://localhost/phpmyadmin/tesdb3/datauser.php";
private native JsArray<UserData> getuserdata(String json)
/*-{
return eval(json);
}-*/;
public void LoadData() throws RequestException{
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
builder.sendRequest(null, new RequestCallback(){
#Override
public void onError(Request request, Throwable exception) {
Window.alert("error " + exception);
}
public void onResponseReceived(Request request,
Response response) {
//1
//data(getuserdata(response.getText()));
//2
JsArray<UserData> uda = JsonUtils.unsafeEval(response.getText())
data(uda);
}
});
}
public void data(JsArray<UserData> data){
for (int i = 0; i < data.length(); i++) {
String lkode =data.get(i).getKode();
String lname =data.get(i).getNama();
Label l = new Label(lkode+" "+lname);
tb.setWidget(i, 0, l);
}
RootPanel.get().add(new HTML("my data"));
RootPanel.get().add(tb);
}
public void onModuleLoad() {
try {
LoadData();
} catch (RequestException e) {
e.printStackTrace();
}
}
}
The result from both method i use in the onResponseReceived is the same. Just showing string "my data". but the method 2 create eror like this:
14:41:59.875 [ERROR] [tesdb3] Uncaught exception escaped
com.google.gwt.core.client.JavaScriptException: (SyntaxError): syntax error
Did I miss use the 2nd method? Why method 1 didn't have any eror but can't show the data?
The problem is that your JSON has incorrect syntax, you are missing a comma after the first item of the table, it should be (whitespace added for readability):
[
{
"kode": "002",
"nama": "bambang gentolet"
},
{
"kode": "012",
"nama": "Algiz"
}
]
Since JSON is a part of JavaScript this might be the syntax error exception you are getting.
PS: I'd recommend using some PHP framework to create JSON for you (Zend Framework is my usual choice). Also, JSON validators like JSONLint are very useful for debugging JSON.
It looks like a typo in your code, which brings me to naming conventions: for variables and methods use camel case, starting with a lower case character. Thus UserData UD should be UserData ud.
In your getuserdata method (which should be getUserData) you use the parameter name Json with capital J and in the native code json with the lower j. This explains the error.
Regarding the getUserData method. There is a GWT method: JsonUtils.unsafeEval(json) which you should use.
Furthermore, the code in the onResponseReceived seems incomplete, it might not be of importance as it might be incorrectly be put in this example, but just to be complete, here is what it should look like:
JsArray<UserData> uda = JsonUtils.unsafeEval(response.getText());
for (int i = 0; i < uda.length(); i++) {
UserData ud = uda.get(i);
String lKode = ud.getKode();
String lName = ud.getNama();
Label l = new Label(lKode + " " +lName);
RootPanel.get().add(l);
}