use of org.structr.common.SecurityContext in project structr by structr.
the class DeployCommand method doImport.
// ----- private methods -----
private void doImport(final Map<String, Object> attributes) throws FrameworkException {
final long startTime = System.currentTimeMillis();
customHeaders.put("start", new Date(startTime).toString());
final String path = (String) attributes.get("source");
final SecurityContext ctx = SecurityContext.getSuperUserInstance();
final App app = StructrApp.getInstance(ctx);
ctx.setDoTransactionNotifications(false);
ctx.disableEnsureCardinality();
ctx.disableModificationOfAccessTime();
final Map<String, Object> componentsConf = new HashMap<>();
final Map<String, Object> templatesConf = new HashMap<>();
final Map<String, Object> pagesConf = new HashMap<>();
final Map<String, Object> filesConf = new HashMap<>();
if (StringUtils.isBlank(path)) {
throw new FrameworkException(422, "Please provide 'source' attribute for deployment source directory path.");
}
final Path source = Paths.get(path);
if (!Files.exists(source)) {
throw new FrameworkException(422, "Source path " + path + " does not exist.");
}
if (!Files.isDirectory(source)) {
throw new FrameworkException(422, "Source path " + path + " is not a directory.");
}
final Map<String, Object> broadcastData = new HashMap();
broadcastData.put("type", DEPLOYMENT_IMPORT_STATUS);
broadcastData.put("subtype", DEPLOYMENT_STATUS_BEGIN);
broadcastData.put("start", startTime);
broadcastData.put("source", source);
TransactionCommand.simpleBroadcastGenericMessage(broadcastData);
// apply configuration
final Path preDeployConf = source.resolve("pre-deploy.conf");
if (Files.exists(preDeployConf)) {
try (final Tx tx = app.tx()) {
final String confSource = new String(Files.readAllBytes(preDeployConf), Charset.forName("utf-8")).trim();
if (confSource.length() > 0) {
info("Applying pre-deployment configuration from {}", preDeployConf);
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Applying pre-deployment configuration");
Scripting.evaluate(new ActionContext(ctx), null, confSource, "pre-deploy.conf");
} else {
info("Ignoring empty pre-deployment configuration {}", preDeployConf);
}
tx.success();
} catch (Throwable t) {
logger.warn("", t);
publishDeploymentWarningMessage("Exception caught while importing pre-deploy.conf", t.toString());
}
}
// backup previous value of change log setting
// temporary disable creation of change log
final boolean changeLogEnabled = Settings.ChangelogEnabled.getValue();
Settings.ChangelogEnabled.setValue(false);
// read grants.json
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing resource access grants");
final Path grantsConf = source.resolve("security/grants.json");
if (Files.exists(grantsConf)) {
info("Reading {}", grantsConf);
importListData(ResourceAccess.class, readConfigList(grantsConf));
}
// read schema-methods.json
final Path schemaMethodsConf = source.resolve("schema-methods.json");
if (Files.exists(schemaMethodsConf)) {
info("Reading {}", schemaMethodsConf);
final String title = "Deprecation warning";
final String text = "Found file 'schema-methods.json'. Newer versions store global schema methods in the schema snapshot file. Recreate the export with the current version to avoid compatibility issues. Support for importing this file will be dropped in future versions.";
info(title + ": " + text);
publishDeploymentWarningMessage(title, text);
importListData(SchemaMethod.class, readConfigList(schemaMethodsConf));
}
// read mail-templates.json
final Path mailTemplatesConf = source.resolve("mail-templates.json");
if (Files.exists(mailTemplatesConf)) {
info("Reading {}", mailTemplatesConf);
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing mail templates");
importListData(MailTemplate.class, readConfigList(mailTemplatesConf));
}
// read widgets.json
final Path widgetsConf = source.resolve("widgets.json");
if (Files.exists(widgetsConf)) {
info("Reading {}", widgetsConf);
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing widgets");
importListData(Widget.class, readConfigList(widgetsConf));
}
// read localizations.json
final Path localizationsConf = source.resolve("localizations.json");
if (Files.exists(localizationsConf)) {
final PropertyMap additionalData = new PropertyMap();
// Question: shouldn't this be true? No, 'imported' is a flag for legacy-localization which
// have been imported from a legacy-system which was replaced by structr.
// it is a way to differentiate between new and old localization strings
additionalData.put(StructrApp.key(Localization.class, "imported"), false);
info("Reading {}", localizationsConf);
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing localizations");
importListData(Localization.class, readConfigList(localizationsConf), additionalData);
}
// read files.conf
final Path filesConfFile = source.resolve("files.json");
if (Files.exists(filesConfFile)) {
info("Reading {}", filesConfFile);
filesConf.putAll(readConfigMap(filesConfFile));
}
// read pages.conf
final Path pagesConfFile = source.resolve("pages.json");
if (Files.exists(pagesConfFile)) {
info("Reading {}", pagesConfFile);
pagesConf.putAll(readConfigMap(pagesConfFile));
}
// read components.conf
final Path componentsConfFile = source.resolve("components.json");
if (Files.exists(componentsConfFile)) {
info("Reading {}", componentsConfFile);
componentsConf.putAll(readConfigMap(componentsConfFile));
}
// read templates.conf
final Path templatesConfFile = source.resolve("templates.json");
if (Files.exists(templatesConfFile)) {
info("Reading {}", templatesConfFile);
templatesConf.putAll(readConfigMap(templatesConfFile));
}
// import schema
final Path schema = source.resolve("schema");
if (Files.exists(schema)) {
try {
info("Importing data from schema/ directory");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing schema");
Files.walkFileTree(schema, new SchemaImportVisitor(schema));
} catch (IOException ioex) {
logger.warn("Exception while importing schema", ioex);
}
}
// import files
final Path files = source.resolve("files");
if (Files.exists(files)) {
try {
info("Importing files (unchanged files will be skipped)");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing files");
FileImportVisitor fiv = new FileImportVisitor(files, filesConf);
Files.walkFileTree(files, fiv);
fiv.handleDeferredFiles();
} catch (IOException ioex) {
logger.warn("Exception while importing files", ioex);
}
}
for (StructrModule module : StructrApp.getConfiguration().getModules().values()) {
if (module.hasDeploymentData()) {
info("Importing deployment data for module {}", module.getName());
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing deployment data for module " + module.getName());
final Path moduleFolder = source.resolve("modules/" + module.getName() + "/");
module.importDeploymentData(moduleFolder, getGson());
}
}
// construct paths
final Path templates = source.resolve("templates");
final Path components = source.resolve("components");
final Path pages = source.resolve("pages");
// an empty directory was specified accidentially).
if (Files.exists(templates) && Files.exists(components) && Files.exists(pages)) {
try (final Tx tx = app.tx()) {
final String tenantIdentifier = app.getDatabaseService().getTenantIdentifier();
info("Removing pages, templates and components");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Removing pages, templates and components");
if (tenantIdentifier != null) {
app.cypher("MATCH (n:" + tenantIdentifier + ":DOMNode) DETACH DELETE n", null);
} else {
app.cypher("MATCH (n:DOMNode) DETACH DELETE n", null);
}
FlushCachesCommand.flushAll();
tx.success();
}
} else {
logger.info("Import directory does not seem to contain pages, templates or components, NOT removing any data.");
}
// import templates, must be done before pages so the templates exist
if (Files.exists(templates)) {
try {
info("Importing templates");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing templates");
Files.walkFileTree(templates, new TemplateImportVisitor(templatesConf));
} catch (IOException ioex) {
logger.warn("Exception while importing templates", ioex);
}
}
// import components, must be done before pages so the shared components exist
if (Files.exists(components)) {
try {
info("Importing shared components");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing shared components");
Files.walkFileTree(components, new ComponentImportVisitor(componentsConf));
} catch (IOException ioex) {
logger.warn("Exception while importing shared components", ioex);
}
}
// import pages
if (Files.exists(pages)) {
try {
info("Importing pages");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing pages");
Files.walkFileTree(pages, new PageImportVisitor(pages, pagesConf));
} catch (IOException ioex) {
logger.warn("Exception while importing pages", ioex);
}
}
try (final Tx tx = app.tx()) {
deferredPageLinks.forEach((String linkableUUID, String pagePath) -> {
try {
final DOMNode page = StructrApp.getInstance().get(DOMNode.class, linkableUUID);
final Linkable linkedPage = StructrApp.getInstance().nodeQuery(Linkable.class).and(StructrApp.key(Page.class, "path"), pagePath).or(Page.name, pagePath).getFirst();
((LinkSource) page).setLinkable(linkedPage);
} catch (FrameworkException ex) {
}
});
deferredPageLinks.clear();
tx.success();
}
// apply configuration
final Path postDeployConf = source.resolve("post-deploy.conf");
if (Files.exists(postDeployConf)) {
try (final Tx tx = app.tx()) {
final String confSource = new String(Files.readAllBytes(postDeployConf), Charset.forName("utf-8")).trim();
if (confSource.length() > 0) {
info("Applying post-deployment configuration from {}", postDeployConf);
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Applying post-deployment configuration");
Scripting.evaluate(new ActionContext(ctx), null, confSource, "post-deploy.conf");
} else {
info("Ignoring empty post-deployment configuration {}", postDeployConf);
}
tx.success();
} catch (Throwable t) {
logger.warn("", t);
publishDeploymentWarningMessage("Exception caught while importing post-deploy.conf", t.toString());
}
}
// restore saved value
Settings.ChangelogEnabled.setValue(changeLogEnabled);
final long endTime = System.currentTimeMillis();
DecimalFormat decimalFormat = new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
final String duration = decimalFormat.format(((endTime - startTime) / 1000.0)) + "s";
customHeaders.put("end", new Date(endTime).toString());
customHeaders.put("duration", duration);
info("Import from {} done. (Took {})", source.toString(), duration);
broadcastData.put("subtype", DEPLOYMENT_STATUS_END);
broadcastData.put("end", endTime);
broadcastData.put("duration", duration);
TransactionCommand.simpleBroadcastGenericMessage(broadcastData);
}
use of org.structr.common.SecurityContext in project structr by structr.
the class DirectFileImportCommand method execute.
@Override
public void execute(final Map<String, Object> attributes) throws FrameworkException {
indexer = StructrApp.getInstance(securityContext).getFulltextIndexer();
final String sourcePath = getParameterValueAsString(attributes, "source", null);
final String modeString = getParameterValueAsString(attributes, "mode", Mode.COPY.name()).toUpperCase();
final String existingString = getParameterValueAsString(attributes, "existing", Existing.SKIP.name()).toUpperCase();
final boolean doIndex = Boolean.parseBoolean(getParameterValueAsString(attributes, "index", Boolean.TRUE.toString()));
if (StringUtils.isBlank(sourcePath)) {
throw new FrameworkException(422, "Please provide 'source' attribute for deployment source directory path.");
}
if (!EnumUtils.isValidEnum(Mode.class, modeString)) {
throw new FrameworkException(422, "Unknown value for 'mode' attribute. Valid values are: copy, move");
}
if (!EnumUtils.isValidEnum(Existing.class, existingString)) {
throw new FrameworkException(422, "Unknown value for 'existing' attribute. Valid values are: skip, overwrite, rename");
}
// use actual enums
final Existing existing = Existing.valueOf(existingString);
final Mode mode = Mode.valueOf(modeString);
final List<Path> paths = new ArrayList<>();
if (sourcePath.contains(PathHelper.PATH_SEP)) {
final String folderPart = PathHelper.getFolderPath(sourcePath);
final String namePart = PathHelper.getName(sourcePath);
if (StringUtils.isNotBlank(folderPart)) {
final Path source = Paths.get(folderPart);
if (!Files.exists(source)) {
throw new FrameworkException(422, "Source path " + sourcePath + " does not exist.");
}
if (!Files.isDirectory(source)) {
throw new FrameworkException(422, "Source path " + sourcePath + " is not a directory.");
}
try {
try (final DirectoryStream<Path> stream = Files.newDirectoryStream(source, namePart)) {
for (final Path entry : stream) {
paths.add(entry);
}
} catch (final DirectoryIteratorException ex) {
throw ex.getCause();
}
} catch (final IOException ioex) {
throw new FrameworkException(422, "Unable to parse source path " + sourcePath + ".");
}
}
} else {
// Relative path
final Path source = Paths.get(Settings.BasePath.getValue()).resolve(sourcePath);
if (!Files.exists(source)) {
throw new FrameworkException(422, "Source path " + sourcePath + " does not exist.");
}
paths.add(source);
}
final SecurityContext ctx = SecurityContext.getSuperUserInstance();
final App app = StructrApp.getInstance(ctx);
String targetPath = getParameterValueAsString(attributes, "target", "/");
Folder targetFolder = null;
ctx.setDoTransactionNotifications(false);
if (StringUtils.isNotBlank(targetPath) && !("/".equals(targetPath))) {
try (final Tx tx = app.tx()) {
targetFolder = app.nodeQuery(Folder.class).and(StructrApp.key(Folder.class, "path"), targetPath).getFirst();
if (targetFolder == null) {
throw new FrameworkException(422, "Target path " + targetPath + " does not exist.");
}
tx.success();
}
}
String msg = "Starting direct file import from source directory " + sourcePath + " into target path " + targetPath;
logger.info(msg);
publishProgressMessage(msg);
paths.forEach((path) -> {
try {
final String newTargetPath;
// If path is a directory, create it and use it as the new target folder
if (Files.isDirectory(path)) {
Path parentPath = path.getParent();
if (parentPath == null) {
parentPath = path;
}
createFileOrFolder(ctx, app, parentPath, path, Files.readAttributes(path, BasicFileAttributes.class), sourcePath, targetPath, mode, existing, doIndex);
newTargetPath = targetPath + PathHelper.PATH_SEP + PathHelper.clean(path.getFileName().toString());
} else {
newTargetPath = targetPath;
}
Files.walkFileTree(path, new FileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
return createFileOrFolder(ctx, app, path, file, attrs, sourcePath, newTargetPath, mode, existing, doIndex);
}
@Override
public FileVisitResult visitFileFailed(final Path file, final IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
});
} catch (final IOException ex) {
logger.debug("Mode: " + modeString + ", path: " + sourcePath, ex);
}
});
msg = "Finished direct file import from source directory " + sourcePath + ". Imported " + folderCount + " folders and " + fileCount + " files.";
logger.info(msg);
publishProgressMessage(msg);
}
use of org.structr.common.SecurityContext in project structr by structr.
the class DOMNode method render.
static void render(final DOMNode thisNode, final RenderContext renderContext, final int depth) throws FrameworkException {
final SecurityContext securityContext = renderContext.getSecurityContext();
if (!securityContext.isVisible(thisNode)) {
return;
}
final GraphObject details = renderContext.getDetailsDataObject();
final boolean detailMode = details != null;
if (detailMode && thisNode.hideOnDetail()) {
return;
}
if (!detailMode && thisNode.hideOnIndex()) {
return;
}
final EditMode editMode = renderContext.getEditMode(securityContext.getUser(false));
if (EditMode.RAW.equals(editMode) || EditMode.WIDGET.equals(editMode) || EditMode.DEPLOYMENT.equals(editMode)) {
thisNode.renderContent(renderContext, depth);
} else {
final String subKey = thisNode.getDataKey();
if (StringUtils.isNotBlank(subKey)) {
final GraphObject currentDataNode = renderContext.getDataObject();
// fetch (optional) list of external data elements
final Iterable<GraphObject> listData = checkListSources(thisNode, securityContext, renderContext);
final PropertyKey propertyKey;
if (thisNode.renderDetails() && detailMode) {
renderContext.setDataObject(details);
renderContext.putDataObject(subKey, details);
thisNode.renderContent(renderContext, depth);
} else {
if (Iterables.isEmpty(listData) && currentDataNode != null) {
// There are two alternative ways of retrieving sub elements:
// First try to get generic properties,
// if that fails, try to create a propertyKey for the subKey
final Object elements = currentDataNode.getProperty(new GenericProperty(subKey));
renderContext.setRelatedProperty(new GenericProperty(subKey));
renderContext.setSourceDataObject(currentDataNode);
if (elements != null) {
if (elements instanceof Iterable) {
for (Object o : (Iterable) elements) {
if (o instanceof GraphObject) {
GraphObject graphObject = (GraphObject) o;
renderContext.putDataObject(subKey, graphObject);
thisNode.renderContent(renderContext, depth);
}
}
}
} else {
propertyKey = StructrApp.getConfiguration().getPropertyKeyForJSONName(currentDataNode.getClass(), subKey, false);
renderContext.setRelatedProperty(propertyKey);
if (propertyKey != null) {
final Object value = currentDataNode.getProperty(propertyKey);
if (value != null) {
if (value instanceof Iterable) {
for (final Object o : ((Iterable) value)) {
if (o instanceof GraphObject) {
renderContext.putDataObject(subKey, (GraphObject) o);
thisNode.renderContent(renderContext, depth);
}
}
}
}
}
}
// reset data node in render context
renderContext.setDataObject(currentDataNode);
renderContext.setRelatedProperty(null);
} else {
renderContext.setListSource(listData);
thisNode.renderNodeList(securityContext, renderContext, depth, subKey);
}
}
} else {
thisNode.renderContent(renderContext, depth);
}
}
}
use of org.structr.common.SecurityContext in project structr by structr.
the class DOMNode method cloneNode.
public static Node cloneNode(final DOMNode thisNode, boolean deep) {
final SecurityContext securityContext = thisNode.getSecurityContext();
if (deep) {
return cloneAndAppendChildren(securityContext, thisNode);
} else {
final PropertyMap properties = new PropertyMap();
for (Iterator<PropertyKey> it = thisNode.getPropertyKeys(PropertyView.Ui).iterator(); it.hasNext(); ) {
final PropertyKey key = it.next();
// skip blacklisted properties
if (cloneBlacklist.contains(key.jsonName())) {
continue;
}
if (!key.isUnvalidated()) {
properties.put(key, thisNode.getProperty(key));
}
}
// htmlView is necessary for the cloning of DOM nodes - otherwise some properties won't be cloned
for (Iterator<PropertyKey> it = thisNode.getPropertyKeys(PropertyView.Html).iterator(); it.hasNext(); ) {
final PropertyKey key = it.next();
// skip blacklisted properties
if (cloneBlacklist.contains(key.jsonName())) {
continue;
}
if (!key.isUnvalidated()) {
properties.put(key, thisNode.getProperty(key));
}
}
if (thisNode instanceof LinkSource) {
final LinkSource linkSourceElement = (LinkSource) thisNode;
properties.put(StructrApp.key(LinkSource.class, "linkable"), linkSourceElement.getLinkable());
}
final App app = StructrApp.getInstance(securityContext);
try {
return app.create(thisNode.getClass(), properties);
} catch (FrameworkException ex) {
ex.printStackTrace();
throw new DOMException(DOMException.INVALID_STATE_ERR, ex.toString());
}
}
}
use of org.structr.common.SecurityContext in project structr by structr.
the class Content method renderContent.
/*
@Override
public String getIdHash() {
final DOMNode _parent = getProperty(DOMNode.parent);
if (_parent != null) {
String dataHash = _parent.getProperty(DOMNode.dataHashProperty);
if (dataHash == null) {
dataHash = _parent.getIdHash();
}
return dataHash + "Content" + treeGetChildPosition(this);
}
return super.getIdHash();
}
*/
public static void renderContent(final Content thisNode, final RenderContext renderContext, final int depth) throws FrameworkException {
final SecurityContext securityContext = thisNode.getSecurityContext();
try {
final EditMode edit = renderContext.getEditMode(securityContext.getUser(false));
if (EditMode.DEPLOYMENT.equals(edit)) {
final AsyncBuffer buf = renderContext.getBuffer();
// output ownership comments
DOMNode.renderDeploymentExportComments(thisNode, buf, true);
// EditMode "deployment" means "output raw content, do not interpret in any way
buf.append(escapeForHtml(thisNode.getContent()));
return;
}
if (thisNode.isDeleted() || thisNode.isHidden() || !thisNode.displayForLocale(renderContext) || !thisNode.displayForConditions(renderContext)) {
return;
}
final String id = thisNode.getUuid();
final boolean inBody = renderContext.inBody();
final AsyncBuffer out = renderContext.getBuffer();
final String _contentType = thisNode.getContentType();
// apply configuration for shared component if present
final String _sharedComponentConfiguration = thisNode.getSharedComponentConfiguration();
if (StringUtils.isNotBlank(_sharedComponentConfiguration)) {
Scripting.evaluate(renderContext, thisNode, "${" + _sharedComponentConfiguration + "}", "shared component configuration");
}
// fetch content with variable replacement
String _content = thisNode.getPropertyWithVariableReplacement(renderContext, StructrApp.key(Content.class, "content"));
if (!(EditMode.RAW.equals(edit) || EditMode.WIDGET.equals(edit)) && (_contentType == null || ("text/plain".equals(_contentType)))) {
_content = escapeForHtml(_content);
}
if (EditMode.CONTENT.equals(edit) && inBody && thisNode.isGranted(Permission.write, securityContext)) {
if ("text/javascript".equals(_contentType)) {
// Javascript will only be given some local vars
out.append("// data-structr-type='").append(thisNode.getType()).append("'\n// data-structr-id='").append(id).append("'\n");
} else if ("text/css".equals(_contentType)) {
// CSS will only be given some local vars
out.append("/* data-structr-type='").append(thisNode.getType()).append("'*/\n/* data-structr-id='").append(id).append("'*/\n");
} else {
// In edit mode, add an artificial comment tag around content nodes within body to make them editable
final String cleanedContent = StringUtils.remove(StringUtils.remove(org.apache.commons.lang3.StringUtils.replace(thisNode.getContent(), "\n", "\\\\n"), "<!--"), "-->");
out.append("<!--data-structr-id=\"".concat(id).concat("\" data-structr-raw-value=\"").concat(escapeForHtmlAttributes(cleanedContent)).concat("\"-->"));
}
}
// examine content type and apply converter
if (_contentType != null) {
final Adapter<String, String> converter = ContentConverters.getConverterForType(_contentType);
if (converter != null) {
try {
// apply adapter
_content = converter.adapt(_content);
} catch (FrameworkException fex) {
logger.warn("Unable to convert content: {}", fex.getMessage());
}
}
}
// replace newlines with <br /> for rendering
if (((_contentType == null) || _contentType.equals("text/plain")) && (_content != null) && !_content.isEmpty()) {
final DOMNode _parent = thisNode.getParent();
if (_parent == null || !(_parent instanceof Textarea)) {
_content = _content.replaceAll("[\\n]{1}", "<br>");
}
}
if (_content != null) {
// insert whitespace to make element clickable
if (EditMode.CONTENT.equals(edit) && _content.length() == 0) {
_content = "--- empty ---";
}
out.append(_content);
}
if (EditMode.CONTENT.equals(edit) && inBody && !("text/javascript".equals(_contentType) && !("text/css".equals(_contentType)))) {
out.append("<!---->");
}
} catch (Throwable t) {
// catch exception to prevent ugly status 500 error pages in frontend.
logger.error("", t);
}
}
Aggregations