use of org.craftercms.studio.api.v1.ebus.PreviewEventContext in project studio by craftercms.
the class ContentServiceImpl method writeContent.
@Override
@ValidateParams
public void writeContent(@ValidateStringParam(name = "site") String site, @ValidateSecurePathParam(name = "path") String path, @ValidateStringParam(name = "fileName") String fileName, @ValidateStringParam(name = "contentType") String contentType, InputStream input, @ValidateStringParam(name = "createFolders") String createFolders, @ValidateStringParam(name = "edit") String edit, @ValidateStringParam(name = "unlock") String unlock, boolean skipAuditLogInsert) throws ServiceLayerException {
try {
entitlementValidator.validateEntitlement(EntitlementType.ITEM, 1);
} catch (EntitlementException e) {
throw new ServiceLayerException("Unable to complete request due to entitlement limits. Please contact your " + "system administrator.");
}
Map<String, String> params = new HashMap<String, String>();
params.put(DmConstants.KEY_SITE, site);
params.put(DmConstants.KEY_PATH, path);
params.put(DmConstants.KEY_FILE_NAME, fileName);
params.put(DmConstants.KEY_CONTENT_TYPE, contentType);
params.put(DmConstants.KEY_CREATE_FOLDERS, createFolders);
params.put(DmConstants.KEY_EDIT, edit);
params.put(DmConstants.KEY_UNLOCK, unlock);
params.put(DmConstants.KEY_SKIP_AUDIT_LOG_INSERT, String.valueOf(skipAuditLogInsert));
String id = site + ":" + path + ":" + fileName + ":" + contentType;
String relativePath = path;
boolean contentExists = contentExists(site, path);
String lockKey = id;
if (contentExists) {
lockKey = site + ":" + path;
}
try {
// Check if the user is saving and closing (releasing the lock) or just saving and will continue to edit
// If "unlock" is empty, it means it's a save and close operation
// if "unlock" is set to "false", it also means it's a save and continue operation
boolean isSaveAndClose = (StringUtils.isNotEmpty(unlock) && !unlock.equalsIgnoreCase("false"));
if (contentExists) {
ItemState itemState = objectStateService.getObjectState(site, path);
if (itemState == null) {
// This file is either new or someone created it outside of our system, we must create a state
// for it
ContentItemTO item = getContentItem(site, path, 0);
objectStateService.insertNewEntry(site, item);
itemState = objectStateService.getObjectState(site, path);
}
if (itemState != null) {
if (itemState.getSystemProcessing() != 0) {
// TODO: SJ: Review and refactor/redo
logger.error("Error Content {0} is being processed (Object State is system " + "processing);", path);
throw new ServiceLayerException("Content " + path + " is in system processing, we can't write " + "it");
}
objectStateService.setSystemProcessing(site, path, true);
} else {
logger.error("the object state is still null even after attempting to create it for site {0} " + "path {1} fileName {2} contentType {3}" + ".", site, path, fileName, contentType);
}
} else {
// Content does not exist; check for moved content and deleted content
if (objectStateService.deletedPathExists(site, path) || objectMetadataManager.movedPathExists(site, path)) {
throw new ServiceLayerException("Content " + path + " for site " + site + ", cannot be created " + "because this name/URL was in use by another content item that has been moved or" + " deleted by not yet published.");
}
}
// TODO: SJ: Item processing pipeline needs to be configurable without hardcoded paths
// TODO: SJ: We need to consider various mechanics for pipeline choice other than path
// TODO: SJ: Furthermore, we already have similar machinery in Crafter Core that might be a fit for some
// TODO: SJ: of this work
// default chain is asset type
String chainID = DmConstants.CONTENT_CHAIN_ASSET;
if (path.startsWith("/site")) {
// anything inside site is a form based XML
// example /site/website
// /site/components
// /site/books
chainID = DmConstants.CONTENT_CHAIN_FORM;
}
// TODO: SJ: Content is being written here via the pipeline, this is not the best design and will be
// TODO: SJ: refactored in 2.7.x
processContent(id, input, true, params, chainID);
// Item has been processed and persisted, set system processing state to off
objectStateService.setSystemProcessing(site, path, false);
// TODO: SJ: The path sent from the UI is inconsistent, hence the acrobatics below. Fix in 2.7.x
String savedFileName = params.get(DmConstants.KEY_FILE_NAME);
String savedPath = params.get(DmConstants.KEY_PATH);
relativePath = savedPath;
if (!savedPath.endsWith(savedFileName)) {
relativePath = savedPath + FILE_SEPARATOR + savedFileName;
}
// TODO: SJ: Why is the item being loaded again? Why is the state being set to system not processing
// TODO: SJ: again? Why would we insert the item into objectStateService again?
// TODO: SJ: Refactor for 2.7.x
ContentItemTO itemTo = getContentItem(site, relativePath, 0);
if (itemTo != null) {
if (isSaveAndClose) {
objectStateService.transition(site, itemTo, SAVE);
} else {
objectStateService.transition(site, itemTo, SAVE_FOR_PREVIEW);
}
objectStateService.setSystemProcessing(site, itemTo.getUri(), false);
} else {
// TODO: SJ: the line below doesn't make any sense, itemTo == null => insert? Investigate and fix in
// TODO: SJ: 2.7.x
objectStateService.insertNewEntry(site, itemTo);
}
// Sync preview
PreviewEventContext context = new PreviewEventContext();
context.setSite(site);
eventService.publish(EVENT_PREVIEW_SYNC, context);
} catch (RuntimeException e) {
logger.error("error writing content", e);
// TODO: SJ: Why setting two things? Are we guessing? Fix in 2.7.x
objectStateService.setSystemProcessing(site, relativePath, false);
objectStateService.setSystemProcessing(site, path, false);
throw e;
}
}
Aggregations