Skip to content

Commit

Permalink
Merge pull request #3010 from SCADA-LTS/feature/#2995_Added_saving_cu…
Browse files Browse the repository at this point in the history
…stom_stylesheet_to_the_database2

#2995 Added saving custom stylesheet to the database
  • Loading branch information
Limraj authored Sep 25, 2024
2 parents d79b34c + 9a4b858 commit 65b09ef
Show file tree
Hide file tree
Showing 37 changed files with 429 additions and 63 deletions.
3 changes: 0 additions & 3 deletions WebContent/WEB-INF/jsp/include/highlight.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ function updateCodeText(text, destination) {
function updateCodeTextEscaped(text, destination) {
let result_element = document.querySelector(destination);
if(text[text.length-1] == "\n") {
text += " ";
}
result_element.innerHTML = text;
hljs.highlightElement(result_element);
}
Expand Down
46 changes: 36 additions & 10 deletions WebContent/WEB-INF/jsp/systemSettings.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<script type="text/javascript">
var systemEventAlarmLevels = new Array();
var auditEventAlarmLevels = new Array();
function init() {
SystemSettingsDwr.getSettings(function(settings) {
$set("<c:out value="<%= SystemSettingsDAO.EMAIL_SMTP_HOST %>"/>", settings.<c:out value="<%= SystemSettingsDAO.EMAIL_SMTP_HOST %>"/>);
Expand Down Expand Up @@ -507,11 +507,6 @@
dialog.style.display = 'none';
}
function saveCssSettings() {
hideCssDialog();
saveCustomCssConfig();
}
function initCustomCssData() {
fetchCustomCssConfig().then((val) => {
let res = JSON.parse(val);
Expand Down Expand Up @@ -542,18 +537,31 @@
return new Promise((resolve, reject) => {
let req = new XMLHttpRequest();
req.open('POST', customCssUrl, true);
req.setRequestHeader('Content-type', 'application/text');
req.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
setUserMessage("customCssMessage");
req.onload = () => {
if (req.status === 200) {
resolve(req.responseText);
setUserMessage("customCssMessage", "<spring:message code="systemSettings.customCssSaved"/>");
} else if (req.status === 400) {
let errors = JSON.parse(req.responseText);
if(errors.length > 0) {
setUserMessage("customCssMessage", "<spring:message code="systemSettings.invalidCustomCss"/>");
}
reject(errors);
} else {
reject(req.status);
}
};
req.onerror = () => {
reject(req.status);
}
req.send(document.getElementById('cssEditor').value);
let cssContent = document.getElementById('cssEditor').value;
let cssStyle = {
content: cssContent
};
let body = JSON.stringify(cssStyle);
req.send(body);
});
}
Expand All @@ -565,6 +573,19 @@
$set("<c:out value="<%= SystemSettingsDAO.UI_PERFORMANCE %>"/>", uiPerformance);
}
document.addEventListener('DOMContentLoaded', () => {
const cssEditor = document.getElementById('cssEditor');
const cssHighlighting = document.getElementById('cssHighlighting');
if (cssEditor && cssHighlighting) {
cssEditor.addEventListener('input', () => {
updateCodeText(cssEditor.value, '#cssHighlightingContent');
});
cssEditor.addEventListener('scroll', () => {
syncCodeScroll(cssEditor, '#cssHighlighting');
});
}
});
</script>

<div class="borderDivPadded marB marR" style="float:left">
Expand Down Expand Up @@ -1142,13 +1163,18 @@
<table>
<tr>
<td>
<button onclick="hideCssDialog()"><spring:message code="common.cancel"/></button>
<button onclick="hideCssDialog()"><spring:message code="common.close"/></button>
</td>
<td>
<button onclick="saveCssSettings()"><spring:message code="common.save"/></button>
<button onclick="saveCustomCssConfig()"><spring:message code="common.save"/></button>
</td>
</tr>
</table>
<table>
<tr>
<td colspan="2" id="customCssMessage" class="formError"></td>
</tr>
</table>
</div>
</div>
</div>
Expand Down
Binary file added WebContent/WEB-INF/lib/classmate-1.3.4.jar
Binary file not shown.
Binary file added WebContent/WEB-INF/lib/cssparser-0.9.30.jar
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added WebContent/WEB-INF/lib/sac-1.3.jar
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ test {
includeTestsMatching "org.scada_lts.utils.BlockingQueuesUtilsTest"
includeTestsMatching "org.scada_lts.web.security.XssProtectHtmlEscapeUtilsTest"
includeTestsMatching "org.scada_lts.web.security.XssUtilsTest"
includeTestsMatching "org.scada_lts.web.mvc.api.css.validation.utils.CssValidatorTestsSuite"
}

failFast = true
Expand Down
2 changes: 1 addition & 1 deletion src/org/scada_lts/config/ScadaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ public class ScadaConfig {
private static final String FILE_NAME_PROPERTIES="env.properties";
private static final String FILE_NAME_CUSTOM_CSS="common.css";
private static final String DIR_NAME_CUSTOM_CONFIG="assets";
private static final String FILE_NAME_USER_STYLESHEET="user_styles.css";

private static ScadaConfig instance = null;

Expand Down Expand Up @@ -424,6 +425,5 @@ private static String getPathCustomConfig() {
return path;

}


}
4 changes: 3 additions & 1 deletion src/org/scada_lts/dao/SystemSettingsDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ public class SystemSettingsDAO {
public static final String EVENT_ASSIGN_ENABLED = "eventAssignEnabled";
public static final String TOP_DESCRIPTION_PREFIX = "topDescriptionPrefix";
public static final String TOP_DESCRIPTION = "topDescription";
public static final String CUSTOM_CSS_CONTENT = "customCssContent";

// @formatter:off
private static final String SELECT_SETTING_VALUE_WHERE = ""
Expand Down Expand Up @@ -418,7 +419,8 @@ public String getDatabaseSchemaVersion(String key, String defaultValue) {
DEFAULT_VALUES.put(EVENT_ASSIGN_ENABLED, SystemSettingsUtils.isEventAssignEnabled());
DEFAULT_VALUES.put(TOP_DESCRIPTION, "");
DEFAULT_VALUES.put(TOP_DESCRIPTION_PREFIX, "");
}
DEFAULT_VALUES.put(CUSTOM_CSS_CONTENT, SystemSettingsUtils.getCustomCssContent());
}

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED, rollbackFor = SQLException.class)
public void resetDataBase() {
Expand Down
8 changes: 8 additions & 0 deletions src/org/scada_lts/mango/adapter/MangoScadaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.scada_lts.config.ScadaConfig;
import org.scada_lts.mango.service.SystemSettingsService;
import org.scada_lts.web.mvc.api.css.CssStyle;
import org.scada_lts.web.mvc.api.css.CustomCssUtils;


/**
Expand Down Expand Up @@ -55,6 +58,11 @@ public void init() {
LOG.info("copy env.properties");
ScadaConfig.copyConfig();
}

LOG.info("loading user_styles.css form database");
SystemSettingsService service = new SystemSettingsService();
CssStyle cssStyle = service.getCustomCss();
CustomCssUtils.saveToFile(cssStyle);

}

Expand Down
10 changes: 10 additions & 0 deletions src/org/scada_lts/mango/service/SystemSettingsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.scada_lts.utils.SystemSettingsUtils;
import org.scada_lts.web.beans.ApplicationBeans;
import org.scada_lts.web.mvc.api.AggregateSettings;
import org.scada_lts.web.mvc.api.css.CssStyle;
import org.scada_lts.web.mvc.api.json.*;
import org.springframework.stereotype.Service;

Expand Down Expand Up @@ -519,4 +520,13 @@ private static Map<String, String> deserializeMap(String json) {
return Collections.emptyMap();
}
}

public CssStyle getCustomCss() {
String content = SystemSettingsDAO.getValue(SystemSettingsDAO.CUSTOM_CSS_CONTENT);
return new CssStyle(content);
}

public void saveCustomCss(CssStyle cssStyle) {
systemSettingsDAO.setValue(SystemSettingsDAO.CUSTOM_CSS_CONTENT, cssStyle.getContent());
}
}
11 changes: 11 additions & 0 deletions src/org/scada_lts/utils/SystemSettingsUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ private SystemSettingsUtils() {}
private static final String SECURITY_HTTP_QUERY_LIMIT_KEY = "scadalts.security.http.query.limit";
private static final String SECURITY_HTTP_QUERY_PROTECT_ENABLED_KEY = "scadalts.security.http.query.protect.enabled";

private static final String CUSTOM_CSS_CONTENT_KEY = "systemsettings.custom.css.content";

private static final org.apache.commons.logging.Log LOG = LogFactory.getLog(SystemSettingsUtils.class);

public static DataPointSyncMode getDataPointSynchronizedMode() {
Expand Down Expand Up @@ -594,4 +596,13 @@ public static boolean isSecurityHttpQueryProtectEnabled() {
return false;
}
}

public static String getCustomCssContent() {
try {
return ScadaConfig.getInstance().getConf().getProperty(CUSTOM_CSS_CONTENT_KEY, "");
} catch (Exception e) {
LOG.error(e.getMessage());
return "";
}
}
}
81 changes: 36 additions & 45 deletions src/org/scada_lts/web/mvc/api/CustomCssAPI.java
Original file line number Diff line number Diff line change
@@ -1,80 +1,71 @@
package org.scada_lts.web.mvc.api;

import com.serotonin.mango.Common;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.scada_lts.mango.service.SystemSettingsService;
import org.scada_lts.serorepl.utils.StringUtils;
import org.scada_lts.web.mvc.api.css.CssStyle;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.file.Files;
import javax.validation.Valid;

@Controller
import java.util.List;
import java.util.stream.Collectors;

import static org.scada_lts.web.mvc.api.css.CustomCssUtils.saveToFile;

@RestController
@RequestMapping("/api/customcss")
public class CustomCssAPI {

private static final Log LOG = LogFactory.getLog(CustomCssAPI.class);
private static final String CSS_FILENAME = "/assets/user_styles.css";

private static final String REQ_RESP_ERROR = "Couldn't create a *.css file.";
private final SystemSettingsService systemSettingsService;

public CustomCssAPI(SystemSettingsService systemSettingsService) {
this.systemSettingsService = systemSettingsService;
}

@GetMapping("/")
public ResponseEntity<?> getCustomCssFile(HttpServletRequest request) {
@GetMapping(value = "", produces = {"application/json;charset=UTF-8"})
public ResponseEntity<CssStyle> getCustomCss(HttpServletRequest request) {
LOG.info("GET: /api/customcss");
try {
File cssFile = getCustomCssFileFromPath();
if(cssFile != null) {
String content = Files.readString(cssFile.toPath());
return new ResponseEntity<>(new CssStyle(content), HttpStatus.OK);
} else {
return new ResponseEntity<>(REQ_RESP_ERROR,HttpStatus.INTERNAL_SERVER_ERROR);
CssStyle customCss = systemSettingsService.getCustomCss();
if (!StringUtils.isEmpty(customCss.getContent())) {
return new ResponseEntity<>(customCss.clearedOfTabs(), HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} catch (Exception e) {
LOG.error(e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}

@PostMapping("/")
public ResponseEntity<String> saveCustomCssFile(HttpServletRequest request, @RequestBody String fileContent) {
@PostMapping(value = "", consumes = {"application/json;charset=UTF-8"})
public ResponseEntity<?> saveCustomCss(HttpServletRequest request, @Valid @RequestBody(required = true) CssStyle cssStyle, BindingResult bindingResult) {
LOG.info("POST: /api/customcss");
if (bindingResult.hasErrors()) {
List<String> errors = bindingResult.getFieldErrors().stream()
.map(error -> error.getDefaultMessage())
.collect(Collectors.toList());

return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}

try {
File cssFile = getCustomCssFileFromPath();
if(cssFile != null) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(cssFile.getAbsolutePath()))) {
writer.write(fileContent);
}
if (!StringUtils.isEmpty(cssStyle.getContent())) {
systemSettingsService.saveCustomCss(cssStyle);
saveToFile(cssStyle);
return new ResponseEntity<>(HttpStatus.OK);
} else {
return new ResponseEntity<>(REQ_RESP_ERROR, HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} catch (Exception e) {
LOG.error(e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}

}

private File getCustomCssFileFromPath() {
try {
File cssFile = new File(Common.ctx.getCtx().getRealPath(CSS_FILENAME));
if(!cssFile.exists()) {
boolean created = cssFile.createNewFile();
if(created) {
LOG.info("Created custom CSS stylesheet file: " + CSS_FILENAME);
}
}
return cssFile;
} catch (IOException e) {
LOG.error("Could not create a custom CSS file: " + CSS_FILENAME);
}
return null;
}
}
16 changes: 14 additions & 2 deletions src/org/scada_lts/web/mvc/api/css/CssStyle.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
package org.scada_lts.web.mvc.api.css;


import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.scada_lts.web.mvc.api.css.validation.CssValid;

public class CssStyle {

@CssValid
private final String content;

public CssStyle(String content) {
this.content = content;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public CssStyle(@JsonProperty("content") String content) {
this.content = CustomCssUtils.replaceToTab(content);
}

public String getContent() {
return content;
}

public CssStyle clearedOfTabs() {
return new CssStyle(getContent().replace("\t", " "));
}
}
Loading

0 comments on commit 65b09ef

Please sign in to comment.