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

Former-commit-id: a7bdc427b9
pull/2/head
jensp 2018-06-14 18:26:03 +00:00
parent 83fc617596
commit f94b740801
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 ( create table CCM_CORE.PAGE_MODELS (
PAGE_MODEL_ID bigint not null, PAGE_MODEL_ID bigint not null,
LAST_MODIFIED timestamp,
MODEL_UUID varchar(255) not null, MODEL_UUID varchar(255) not null,
NAME varchar(255), NAME varchar(255),
TYPE varchar(255) not null, TYPE varchar(255) not null,

View File

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

View File

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

View File

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

View File

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

View File

@ -19,7 +19,6 @@
package org.libreccm.pagemodel.rs; package org.libreccm.pagemodel.rs;
import com.arsdigita.kernel.KernelConfig; import com.arsdigita.kernel.KernelConfig;
import org.libreccm.configuration.ConfigurationManager; import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.core.CoreConstants; import org.libreccm.core.CoreConstants;
import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.l10n.GlobalizationHelper;
@ -30,9 +29,6 @@ import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege; import org.libreccm.security.RequiresPrivilege;
import org.libreccm.web.CcmApplication; import org.libreccm.web.CcmApplication;
import java.util.Locale;
import java.util.Objects;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.json.Json; import javax.json.Json;
@ -48,6 +44,9 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; 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 * Provides RESTful endpoints for retrieving, creating, updating and deleting
@ -75,7 +74,8 @@ public class PageModels {
private ConfigurationManager confManager; 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}. * @param appPath The path of the {@code app}.
* *
@ -83,9 +83,9 @@ public class PageModels {
* {@link CcmApplication} {@code app}. * {@link CcmApplication} {@code app}.
* *
* @throws NotFoundException If there is no {@link CcmApplication} with the * @throws NotFoundException If there is no {@link CcmApplication} with the
* primary URL {@code appPath} an * primary URL {@code appPath} an {@link
* {@link NotFoundException} thrown resulting in * NotFoundException} thrown resulting in 404
* 404 response. * response.
*/ */
@GET @GET
@Path(PageModelsApp.PAGE_MODELS_PATH) @Path(PageModelsApp.PAGE_MODELS_PATH)
@ -114,8 +114,8 @@ public class PageModels {
* Retrieves a specific {@link PageModel}. * Retrieves a specific {@link PageModel}.
* *
* @param appPath The path ({@link CcmApplication#primaryUrl} of the * @param appPath The path ({@link CcmApplication#primaryUrl} of the
* {@link CcmApplication} to which the * {@link CcmApplication} to which the {@link
* {@link PageModel} belongs (see * PageModel} belongs (see
* {@link PageModel#application}). * {@link PageModel#application}).
* @param pageModelName The name of the {@link PageModel} to retrieve (see * @param pageModelName The name of the {@link PageModel} to retrieve (see
* {@link PageModel#name}). * {@link PageModel#name}).
@ -123,13 +123,13 @@ public class PageModels {
* @return A JSON object containing the data of the {@link PageModel}. * @return A JSON object containing the data of the {@link PageModel}.
* *
* @throws NotFoundException If there is not {@link CcmApplication} with the * @throws NotFoundException If there is not {@link CcmApplication} with the
* primary URL {@code appPath} a * primary URL {@code appPath} a {@link
* {@link NotFoundException} is thrown resulting * NotFoundException} is thrown resulting in a 404
* in a 404 response. A {@link NotFoundException} * response. A {@link NotFoundException} is also
* is also thrown if there no {@link PageModel} * thrown if there no {@link PageModel} identified
* identified by {@code pageModelName} for the * by {@code pageModelName} for the {@link
* {@link CcmApplication} with the primary URL * CcmApplication} with the primary URL {@code
* {@code appPath}. * appPath}.
*/ */
@GET @GET
@Path(PageModelsApp.PAGE_MODEL_PATH) @Path(PageModelsApp.PAGE_MODEL_PATH)
@ -157,15 +157,14 @@ public class PageModels {
* If a {@link PageModel} with the name {@code pageModelName} already exists * If a {@link PageModel} with the name {@code pageModelName} already exists
* for the {@link CcmApplication} with the primary URL {@code appPath} the * 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 updated. If there is no such {@link PageModel} a new
* {@link PageModel} is created and associated with the * {@link PageModel} is created and associated with the {@link
* {@link CcmApplication} identified by the primary URL {@code appPath}. * CcmApplication} identified by the primary URL {@code appPath}.
*
* *
* @param appPath The primary URL of the {@link CcmApplication} to * @param appPath The primary URL of the {@link CcmApplication} to
* which the {@link PageModel} belongs. * which the {@link PageModel} belongs.
* @param pageModelName The name of the {@link PageModel}. * @param pageModelName The name of the {@link PageModel}.
* @param pageModelData The data for creating or updating the * @param pageModelData The data for creating or updating the {@link
* {@link PageModel}. * PageModel}.
* *
* @return The new or updated {@link PageModel}. * @return The new or updated {@link PageModel}.
*/ */
@ -244,13 +243,23 @@ public class PageModels {
* *
* @param pageModel The {@link PageModel} to map. * @param pageModel The {@link PageModel} to map.
* *
* @return A {@link JSON} object with the data of the provided * @return A {@link JsonObject} object with the data of the provided {@link
* {@link PageModel}. * PageModel}.
*/ */
private JsonObject mapPageModelToJson(final PageModel pageModel) { private JsonObject mapPageModelToJson(final PageModel pageModel) {
Objects.requireNonNull(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 return Json
.createObjectBuilder() .createObjectBuilder()
.add("description", .add("description",
@ -265,7 +274,48 @@ public class PageModels {
.add("type", pageModel.getType()) .add("type", pageModel.getType())
.add("uuid", pageModel.getUuid()) .add("uuid", pageModel.getUuid())
.add("version", pageModel.getVersion().toString()) .add("version", pageModel.getVersion().toString())
.add("publicationStatus",
getPublicationStatus(pageModel).toString())
.add("lastPublished", lastPublished)
.build(); .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 ( create table CCM_CORE.PAGE_MODELS (
PAGE_MODEL_ID bigint not null, PAGE_MODEL_ID bigint not null,
LAST_MODIFIED timestamp,
MODEL_UUID varchar(255) not null, MODEL_UUID varchar(255) not null,
NAME varchar(255), NAME varchar(255),
TYPE varchar(255) not null, TYPE varchar(255) not null,

View File

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

View File

@ -1,5 +1,5 @@
import * as React from "react"; import * as React from "react";
import { PageModel, PageModelVersion } from "./datatypes"; import {PageModel, PageModelVersion, PublicationStatus} from "./datatypes";
export { export {
PageModelEditor, PageModelEditor,
@ -129,7 +129,7 @@ class PageModelsList
<PageModelListItem <PageModelListItem
index={index} index={index}
pageModel={pageModel} pageModel={pageModel}
selectPageModel={this.props.selectPageModel} />, selectPageModel={this.props.selectPageModel}/>,
)} )}
</ul> </ul>
} }
@ -219,18 +219,18 @@ class PageModelComponent
} }
<form <form
className="pagemodeleditor pagemodel propertiesForm" className="pagemodeleditor pagemodel propertiesForm"
onSubmit={this.handleSubmit} > onSubmit={this.handleSubmit}>
<label htmlFor="pageModelName"> <label htmlFor="pageModelName">
Name Name
</label> </label>
<input <input
disabled={this.props.pageModel.pageModelId === 0 ? false : true} disabled={this.props.pageModel.pageModelId !== 0}
id="pageModelName" id="pageModelName"
onChange={this.handleChange} onChange={this.handleChange}
size={32} size={32}
type="text" type="text"
value={this.state.form.name} /> value={this.state.form.name}/>
<label htmlFor="pageModelTitle"> <label htmlFor="pageModelTitle">
Title Title
@ -240,7 +240,7 @@ class PageModelComponent
onChange={this.handleChange} onChange={this.handleChange}
size={32} size={32}
type="text" type="text"
value={this.state.form.title} /> value={this.state.form.title}/>
<label htmlFor="pageModelDescription"> <label htmlFor="pageModelDescription">
Description Description
@ -250,7 +250,7 @@ class PageModelComponent
id="pageModelDescription" id="pageModelDescription"
onChange={this.handleChange} onChange={this.handleChange}
rows={20} rows={20}
value={this.state.form.description} /> value={this.state.form.description}/>
<div> <div>
<button type="submit">Save</button> <button type="submit">Save</button>
<button <button
@ -274,6 +274,14 @@ class PageModelComponent
<dd>{this.props.pageModel.version.toString()}</dd> <dd>{this.props.pageModel.version.toString()}</dd>
<dt>Description</dt> <dt>Description</dt>
<dd>{this.props.pageModel.description}</dd> <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> </dl>
<button onClick={(event) => { <button onClick={(event) => {
@ -282,7 +290,14 @@ class PageModelComponent
this.setState({ this.setState({
editMode: true, 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>; </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 { private handleChange(event: React.ChangeEvent<HTMLElement>): void {
const target: HTMLElement = event.target as HTMLElement; const target: HTMLElement = event.target as HTMLElement;
@ -475,7 +502,7 @@ class PageModelEditor
selectedPageModel, selectedPageModel,
}; };
}); });
}} /> }}/>
<button <button
className="pagemodeleditor addbutton" className="pagemodeleditor addbutton"
onClick={ onClick={
@ -507,7 +534,9 @@ class PageModelEditor
ccmApplication={this.getCcmApplication()} ccmApplication={this.getCcmApplication()}
dispatcherPrefix={this.getDispatcherPrefix()} dispatcherPrefix={this.getDispatcherPrefix()}
pageModel={this.state.selectedPageModel} pageModel={this.state.selectedPageModel}
reload={() => { this.reload(); }} /> reload={() => {
this.reload();
}}/>
} }
</div> </div>
</div> </div>
@ -522,9 +551,11 @@ class PageModelEditor
...this.state, ...this.state,
selectedPageModel: { selectedPageModel: {
description: "", description: "",
lastPublished: 0,
modelUuid: "", modelUuid: "",
name: "", name: "",
pageModelId: 0, pageModelId: 0,
publicationStatus: PublicationStatus.NOT_PUBLISHED,
title: "", title: "",
type: "", type: "",
uuid: "", uuid: "",

View File

@ -1,4 +1,4 @@
export { PageModel, PageModelVersion }; export { PageModel, PageModelVersion, PublicationStatus };
interface PageModel { interface PageModel {
@ -10,6 +10,8 @@ interface PageModel {
type: string; type: string;
uuid: string; uuid: string;
version: PageModelVersion; version: PageModelVersion;
publicationStatus: PublicationStatus;
lastPublished: number;
} }
enum PageModelVersion { enum PageModelVersion {
@ -17,3 +19,10 @@ enum PageModelVersion {
DRAFT, DRAFT,
LIVE, 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 ( create table CCM_CORE.PAGE_MODELS (
PAGE_MODEL_ID bigint not null, PAGE_MODEL_ID bigint not null,
LAST_MODIFIED timestamp,
MODEL_UUID varchar(255) not null, MODEL_UUID varchar(255) not null,
NAME varchar(255), NAME varchar(255),
TYPE varchar(255) not null, TYPE varchar(255) not null,

View File

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