CCM NG: Publish button (not yet working) and publish status display for PageModelEditor

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5518 8810af33-2d31-482b-a856-94f89814c4df
ccm-docs
jensp 2018-06-14 18:26:03 +00:00
parent 63d2730fbf
commit f671bd3e55
13 changed files with 197 additions and 69 deletions

View File

@ -1331,6 +1331,7 @@ drop sequence if exists HIBERNATE_SEQUENCE;
create table CCM_CORE.PAGE_MODELS (
PAGE_MODEL_ID bigint not null,
LAST_MODIFIED timestamp,
MODEL_UUID varchar(255) not null,
NAME varchar(255),
TYPE varchar(255) not null,

View File

@ -1332,6 +1332,7 @@ drop sequence if exists HIBERNATE_SEQUENCE;
create table CCM_CORE.PAGE_MODELS (
PAGE_MODEL_ID int8 not null,
LAST_MODIFIED timestamp,
MODEL_UUID varchar(255) not null,
NAME varchar(255),
TYPE varchar(255) not null,

View File

@ -22,11 +22,14 @@ import org.libreccm.core.CoreConstants;
import org.libreccm.l10n.LocalizedString;
import org.libreccm.web.CcmApplication;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@ -202,6 +205,11 @@ public class PageModel implements Serializable {
@Enumerated(EnumType.STRING)
private PageModelVersion version;
@Column(name = "LAST_MODIFIED")
@Temporal(TemporalType.TIMESTAMP)
private Date lastModified;
/**
* The localised title of this {@code PageModel} (shown in the
* administration UI),
@ -294,6 +302,14 @@ public class PageModel implements Serializable {
this.version = version;
}
public Date getLastModified() {
return lastModified;
}
protected void setLastModified(final Date lastModified) {
this.lastModified = new Date(lastModified.getTime());
}
public LocalizedString getTitle() {
return title;
}

View File

@ -47,6 +47,7 @@ import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@ -314,6 +315,8 @@ public class PageModelManager {
.forEach(liveContainerModel -> addContainerModel(pageModel,
liveContainerModel));
liveModel.setLastModified(new Date());
LOGGER.debug("Successfully published PageModel \"{}\".",
liveModel.getName());
return liveModel;

View File

@ -28,6 +28,7 @@ import javax.enterprise.context.RequestScoped;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@ -90,6 +91,9 @@ public class PageModelRepository extends AbstractEntityRepository<Long, PageMode
@Transactional(Transactional.TxType.REQUIRED)
@Override
public void save(final PageModel pageModel) {
pageModel.setLastModified(new Date());
super.save(pageModel);
}

View File

@ -19,7 +19,6 @@
package org.libreccm.pagemodel.rs;
import com.arsdigita.kernel.KernelConfig;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.core.CoreConstants;
import org.libreccm.l10n.GlobalizationHelper;
@ -30,9 +29,6 @@ import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege;
import org.libreccm.web.CcmApplication;
import java.util.Locale;
import java.util.Objects;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.json.Json;
@ -48,6 +44,9 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;
/**
* Provides RESTful endpoints for retrieving, creating, updating and deleting
@ -75,17 +74,18 @@ public class PageModels {
private ConfigurationManager confManager;
/**
* Retrieves all {@link PageModel}s available for an {@link CcmApplication}.
* Retrieves all {@link PageModel}s available for an {@link
* CcmApplication}.
*
* @param appPath The path of the {@code app}.
*
* @return A JSON array with the data of all {@link PageModel}s of the
* {@link CcmApplication} {@code app}.
* {@link CcmApplication} {@code app}.
*
* @throws NotFoundException If there is no {@link CcmApplication} with the
* primary URL {@code appPath} an
* {@link NotFoundException} thrown resulting in
* 404 response.
* primary URL {@code appPath} an {@link
* NotFoundException} thrown resulting in 404
* response.
*/
@GET
@Path(PageModelsApp.PAGE_MODELS_PATH)
@ -114,8 +114,8 @@ public class PageModels {
* Retrieves a specific {@link PageModel}.
*
* @param appPath The path ({@link CcmApplication#primaryUrl} of the
* {@link CcmApplication} to which the
* {@link PageModel} belongs (see
* {@link CcmApplication} to which the {@link
* PageModel} belongs (see
* {@link PageModel#application}).
* @param pageModelName The name of the {@link PageModel} to retrieve (see
* {@link PageModel#name}).
@ -123,13 +123,13 @@ public class PageModels {
* @return A JSON object containing the data of the {@link PageModel}.
*
* @throws NotFoundException If there is not {@link CcmApplication} with the
* primary URL {@code appPath} a
* {@link NotFoundException} is thrown resulting
* in a 404 response. A {@link NotFoundException}
* is also thrown if there no {@link PageModel}
* identified by {@code pageModelName} for the
* {@link CcmApplication} with the primary URL
* {@code appPath}.
* primary URL {@code appPath} a {@link
* NotFoundException} is thrown resulting in a 404
* response. A {@link NotFoundException} is also
* thrown if there no {@link PageModel} identified
* by {@code pageModelName} for the {@link
* CcmApplication} with the primary URL {@code
* appPath}.
*/
@GET
@Path(PageModelsApp.PAGE_MODEL_PATH)
@ -157,15 +157,14 @@ public class PageModels {
* If a {@link PageModel} with the name {@code pageModelName} already exists
* for the {@link CcmApplication} with the primary URL {@code appPath} the
* {@link PageModel} is updated. If there is no such {@link PageModel} a new
* {@link PageModel} is created and associated with the
* {@link CcmApplication} identified by the primary URL {@code appPath}.
*
* {@link PageModel} is created and associated with the {@link
* CcmApplication} identified by the primary URL {@code appPath}.
*
* @param appPath The primary URL of the {@link CcmApplication} to
* which the {@link PageModel} belongs.
* @param pageModelName The name of the {@link PageModel}.
* @param pageModelData The data for creating or updating the
* {@link PageModel}.
* @param pageModelData The data for creating or updating the {@link
* PageModel}.
*
* @return The new or updated {@link PageModel}.
*/
@ -244,13 +243,23 @@ public class PageModels {
*
* @param pageModel The {@link PageModel} to map.
*
* @return A {@link JSON} object with the data of the provided
* {@link PageModel}.
* @return A {@link JsonObject} object with the data of the provided {@link
* PageModel}.
*/
private JsonObject mapPageModelToJson(final PageModel pageModel) {
Objects.requireNonNull(pageModel);
final long lastPublished;
final Optional<PageModel> liveModel = pageModelManager
.getLiveVersion(pageModel);
if (liveModel.isPresent()
&& liveModel.get().getLastModified() != null) {
lastPublished = liveModel.get().getLastModified().getTime();
} else {
lastPublished = 0;
}
return Json
.createObjectBuilder()
.add("description",
@ -265,7 +274,48 @@ public class PageModels {
.add("type", pageModel.getType())
.add("uuid", pageModel.getUuid())
.add("version", pageModel.getVersion().toString())
.add("publicationStatus",
getPublicationStatus(pageModel).toString())
.add("lastPublished", lastPublished)
.build();
}
/**
* Check if the {@link PublicationStatus} of the provided PageModel.
*
* @param pageModel
*
* @return
*/
private PublicationStatus getPublicationStatus(final PageModel pageModel) {
final PageModel draftModel = pageModelManager
.getDraftVersion(pageModel);
final Optional<PageModel> liveModel = pageModelManager
.getLiveVersion(pageModel);
final PublicationStatus publicationStatus;
if (liveModel.isPresent()) {
// Fallback if one the last modified dates is null
if (draftModel.getLastModified() == null
|| liveModel.get().getLastModified() == null) {
return PublicationStatus.NEEDS_UPDATE;
} else if (liveModel
.get()
.getLastModified()
.before(draftModel.getLastModified())) {
publicationStatus = PublicationStatus.PUBLISHED;
} else {
publicationStatus = PublicationStatus.NEEDS_UPDATE;
}
} else {
publicationStatus = PublicationStatus.NOT_PUBLISHED;
}
return publicationStatus;
}
}

View File

@ -0,0 +1,9 @@
package org.libreccm.pagemodel.rs;
public enum PublicationStatus {
NOT_PUBLISHED,
PUBLISHED,
NEEDS_UPDATE,
}

View File

@ -427,6 +427,7 @@ drop sequence if exists HIBERNATE_SEQUENCE;
create table CCM_CORE.PAGE_MODELS (
PAGE_MODEL_ID bigint not null,
LAST_MODIFIED timestamp,
MODEL_UUID varchar(255) not null,
NAME varchar(255),
TYPE varchar(255) not null,

View File

@ -428,6 +428,7 @@ drop sequence if exists HIBERNATE_SEQUENCE;
create table CCM_CORE.PAGE_MODELS (
PAGE_MODEL_ID int8 not null,
LAST_MODIFIED timestamp,
MODEL_UUID varchar(255) not null,
NAME varchar(255),
TYPE varchar(255) not null,

View File

@ -1,5 +1,5 @@
import * as React from "react";
import { PageModel, PageModelVersion } from "./datatypes";
import {PageModel, PageModelVersion, PublicationStatus} from "./datatypes";
export {
PageModelEditor,
@ -123,15 +123,15 @@ class PageModelsList
return <div className="pagemodeleditor pageModelsList">
{this.props.pageModels.length > 0 &&
<ul>
{this.props.pageModels
.map((pageModel: PageModel, index: number) =>
<PageModelListItem
index={index}
pageModel={pageModel}
selectPageModel={this.props.selectPageModel} />,
<ul>
{this.props.pageModels
.map((pageModel: PageModel, index: number) =>
<PageModelListItem
index={index}
pageModel={pageModel}
selectPageModel={this.props.selectPageModel}/>,
)}
</ul>
</ul>
}
</div>;
}
@ -153,14 +153,14 @@ class PageModelListItem
public render(): React.ReactNode {
return <li>
<a data-pagemodel-id="{this.props.pageModel.pageModelId}"
href="#"
onClick={
(event) => {
event.preventDefault();
// console.log("A PageModel has been selected");
this.props.selectPageModel(this.props.pageModel);
}
}>
href="#"
onClick={
(event) => {
event.preventDefault();
// console.log("A PageModel has been selected");
this.props.selectPageModel(this.props.pageModel);
}
}>
{this.props.pageModel.title}
</a>
</li>;
@ -213,24 +213,24 @@ class PageModelComponent
if (this.state.editMode) {
return <div className="bebop-body">
{this.state.errorMsg !== null &&
<div className="errorPanel">
{this.state.errorMsg}
</div>
<div className="errorPanel">
{this.state.errorMsg}
</div>
}
<form
className="pagemodeleditor pagemodel propertiesForm"
onSubmit={this.handleSubmit} >
onSubmit={this.handleSubmit}>
<label htmlFor="pageModelName">
Name
</label>
<input
disabled={this.props.pageModel.pageModelId === 0 ? false : true}
disabled={this.props.pageModel.pageModelId !== 0}
id="pageModelName"
onChange={this.handleChange}
size={32}
type="text"
value={this.state.form.name} />
value={this.state.form.name}/>
<label htmlFor="pageModelTitle">
Title
@ -240,7 +240,7 @@ class PageModelComponent
onChange={this.handleChange}
size={32}
type="text"
value={this.state.form.title} />
value={this.state.form.title}/>
<label htmlFor="pageModelDescription">
Description
@ -250,7 +250,7 @@ class PageModelComponent
id="pageModelDescription"
onChange={this.handleChange}
rows={20}
value={this.state.form.description} />
value={this.state.form.description}/>
<div>
<button type="submit">Save</button>
<button
@ -274,6 +274,14 @@ class PageModelComponent
<dd>{this.props.pageModel.version.toString()}</dd>
<dt>Description</dt>
<dd>{this.props.pageModel.description}</dd>
<dt>Last published</dt>
<dd>{this.getLastPublishedDate()}</dd>
<dt>PublicationStatus</dt>
<dd>{this.props.pageModel.publicationStatus}</dd>
<dt>Publish</dt>
<dd>{this.props.pageModel.publicationStatus === PublicationStatus.NOT_PUBLISHED}</dd>
<dt>Republish</dt>
<dd>{this.props.pageModel.publicationStatus === PublicationStatus.NEEDS_UPDATE}</dd>
</dl>
<button onClick={(event) => {
@ -282,7 +290,14 @@ class PageModelComponent
this.setState({
editMode: true,
});
}}>Edit</button>
}}>Edit
</button>
{this.props.pageModel.publicationStatus === PublicationStatus.NOT_PUBLISHED
&& <button>Publish</button>
}
{this.props.pageModel.publicationStatus === PublicationStatus.NEEDS_UPDATE
&& <button>Republish</button>
}
</div>;
}
}
@ -302,6 +317,18 @@ class PageModelComponent
});
}
private getLastPublishedDate(): string {
if (this.props.pageModel.lastPublished === 0) {
return "";
} else {
const lastPublished: Date = new Date();
lastPublished.setTime(this.props.pageModel.lastPublished);
return lastPublished.toISOString();
}
}
private handleChange(event: React.ChangeEvent<HTMLElement>): void {
const target: HTMLElement = event.target as HTMLElement;
@ -387,7 +414,7 @@ class PageModelComponent
this.setState({
...this.state,
errorMsg: `Failed to update/create PageModel: `
+ ` ${response.status} ${response.statusText}`,
+ ` ${response.status} ${response.statusText}`,
});
}
})
@ -455,7 +482,7 @@ class PageModelEditor
<div className="bebop-segment">
<h3 className="bebop-segment-header">
Available PageModels
</h3>
</h3>
<div className="bebop-segment-body">
<button
className="pagemodeleditor addbutton"
@ -475,7 +502,7 @@ class PageModelEditor
selectedPageModel,
};
});
}} />
}}/>
<button
className="pagemodeleditor addbutton"
onClick={
@ -494,20 +521,22 @@ class PageModelEditor
</div>
<div className="column-content">
{this.state.errorMessages.length > 0 &&
<div className="errorPanel">
{this.state.errorMessages.map((msg) => {
<p>
{msg}
</p>
})}
</div>
<div className="errorPanel">
{this.state.errorMessages.map((msg) => {
<p>
{msg}
</p>
})}
</div>
}
{this.state.selectedPageModel !== null &&
<PageModelComponent
ccmApplication={this.getCcmApplication()}
dispatcherPrefix={this.getDispatcherPrefix()}
pageModel={this.state.selectedPageModel}
reload={() => { this.reload(); }} />
<PageModelComponent
ccmApplication={this.getCcmApplication()}
dispatcherPrefix={this.getDispatcherPrefix()}
pageModel={this.state.selectedPageModel}
reload={() => {
this.reload();
}}/>
}
</div>
</div>
@ -522,9 +551,11 @@ class PageModelEditor
...this.state,
selectedPageModel: {
description: "",
lastPublished: 0,
modelUuid: "",
name: "",
pageModelId: 0,
publicationStatus: PublicationStatus.NOT_PUBLISHED,
title: "",
type: "",
uuid: "",

View File

@ -1,4 +1,4 @@
export { PageModel, PageModelVersion };
export { PageModel, PageModelVersion, PublicationStatus };
interface PageModel {
@ -10,6 +10,8 @@ interface PageModel {
type: string;
uuid: string;
version: PageModelVersion;
publicationStatus: PublicationStatus;
lastPublished: number;
}
enum PageModelVersion {
@ -17,3 +19,10 @@ enum PageModelVersion {
DRAFT,
LIVE,
}
enum PublicationStatus {
NOT_PUBLISHED,
PUBLISHED,
NEEDS_UPDATE,
}

View File

@ -431,6 +431,7 @@ DROP SEQUENCE IF EXISTS hibernate_sequence;
create table CCM_CORE.PAGE_MODELS (
PAGE_MODEL_ID bigint not null,
LAST_MODIFIED timestamp,
MODEL_UUID varchar(255) not null,
NAME varchar(255),
TYPE varchar(255) not null,

View File

@ -431,6 +431,7 @@ DROP SEQUENCE IF EXISTS hibernate_sequence;
create table CCM_CORE.PAGE_MODELS (
PAGE_MODEL_ID int8 not null,
LAST_MODIFIED timestamp,
MODEL_UUID varchar(255) not null,
NAME varchar(255),
TYPE varchar(255) not null,