Skip to content

Commit bb0223f

Browse files
committed
Allow setting custom theme colors
1 parent 557cd94 commit bb0223f

2 files changed

Lines changed: 48 additions & 18 deletions

File tree

src/main/java/eu/openanalytics/shinyproxy/ShinyProxySpecProvider.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
import eu.openanalytics.shinyproxy.runtimevalues.WebSocketReconnectionModeKey;
4646
import eu.openanalytics.shinyproxy.runtimevalues.WebsocketReconnectionMode;
4747
import eu.openanalytics.shinyproxy.ShinyProxySpecProvider.ShinyProxySpec;
48+
49+
import org.slf4j.Logger;
50+
import org.slf4j.LoggerFactory;
4851
import org.springframework.beans.factory.annotation.Autowired;
4952
import org.springframework.beans.factory.annotation.Value;
5053
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -65,6 +68,10 @@
6568
import java.io.File;
6669
import java.io.FileInputStream;
6770
import java.io.FileNotFoundException;
71+
import java.io.IOException;
72+
import java.nio.file.Files;
73+
import java.nio.file.Path;
74+
import java.nio.charset.StandardCharsets;
6875
import java.util.ArrayList;
6976
import java.util.Collections;
7077
import java.util.HashMap;
@@ -112,6 +119,7 @@ public void setSpecs(List<KubernetesSpecExtension> specs) {
112119
@Primary
113120
public class ShinyProxySpecProvider implements IProxySpecProvider {
114121

122+
private final Logger log = LoggerFactory.getLogger(getClass());
115123
private static final String PROP_DEFAULT_MAX_INSTANCES = "proxy.default-max-instances";
116124
private static final String PROP_DEFAULT_ALWAYS_SWITCH_INSTANCE = "proxy.default-always-switch-instance";
117125
private static Environment environment;
@@ -120,6 +128,7 @@ public class ShinyProxySpecProvider implements IProxySpecProvider {
120128
private List<ProxySpec> specs = new ArrayList<>();
121129
private List<TemplateGroup> templateGroups = new ArrayList<>();
122130
private String defaultMaxInstances;
131+
private String customThemeColors;
123132
private Boolean defaultAlwaysSwitchInstance;
124133

125134
private long specsFileTs = 0;
@@ -216,6 +225,17 @@ public void setEnvironment(Environment env) {
216225

217226
@PostConstruct
218227
public void afterPropertiesSet() {
228+
if (miroTheme.equals("custom")) {
229+
try {
230+
customThemeColors = Files
231+
.readString(Path.of("/home/miroproxy/templates/2col/assets/css/themes/colors_custom.css"),
232+
StandardCharsets.UTF_8)
233+
.replaceAll("\\s+",
234+
"");
235+
} catch (IOException e) {
236+
log.error("Error reading custom colors CSS file", e);
237+
}
238+
}
219239
this.setSpecs();
220240
this.specs.stream().collect(Collectors.groupingBy(ProxySpec::getId)).forEach((id, duplicateSpecs) -> {
221241
if (duplicateSpecs.size() > 1)
@@ -231,6 +251,7 @@ public List<ProxySpec> getSpecs() {
231251
try {
232252
File specsFile = new File(specsPath);
233253
if (specsFile.lastModified() > specsFileTs) {
254+
log.info("Reloading specs.yaml file as it was modified");
234255
specsMap = new HashMap<>();
235256
maxInstancesCache = new HashMap<>();
236257
Representer representer = new Representer(new DumperOptions());
@@ -251,9 +272,11 @@ public List<ProxySpec> getSpecs() {
251272
if (!containerEnv.containsKey("MIRO_LANG")) {
252273
containerEnv.put("MIRO_LANG", miroLang);
253274
}
254-
255275
if (!containerEnv.containsKey("MIRO_THEME")) {
256276
containerEnv.put("MIRO_THEME", miroTheme);
277+
if (miroTheme.equals("custom")) {
278+
containerEnv.put("MIRO_CUSTOM_THEME_COLORS", customThemeColors);
279+
}
257280
}
258281

259282
if (authentication.equals("none")) {

src/main/java/eu/openanalytics/shinyproxy/controllers/BaseController.java

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,16 @@ protected void prepareMap(ModelMap map, HttpServletRequest request) {
140140
} else {
141141
map.put("showNavbar", defaultShowNavbar);
142142
}
143-
144-
map.put("themeCss", "/assets/css/themes/" + environment.getProperty("proxy.theme", "default") + ".css");
143+
144+
map.put("themeCss", "/assets/css/themes/colors_" + environment.getProperty("proxy.theme", "default") + ".css");
145145
map.put("bootstrapCss", "/webjars/bootstrap/3.4.1/css/bootstrap.min.css");
146146
map.put("bootstrapJs", "/webjars/bootstrap/3.4.1/js/bootstrap.min.js");
147147
map.put("jqueryJs", "/webjars/jquery/3.7.1/jquery.min.js");
148148
map.put("handlebars", "/webjars/handlebars/4.7.7/handlebars.runtime.min.js");
149149

150150
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
151-
boolean isLoggedIn = authentication != null && !(authentication instanceof AnonymousAuthenticationToken) && authentication.isAuthenticated();
151+
boolean isLoggedIn = authentication != null && !(authentication instanceof AnonymousAuthenticationToken)
152+
&& authentication.isAuthenticated();
152153
map.put("isLoggedIn", isLoggedIn);
153154
map.put("isAdmin", userService.isAdmin(authentication));
154155
map.put("isSupportEnabled", isLoggedIn && defaultSupportAddress != null);
@@ -173,8 +174,8 @@ protected void prepareMap(ModelMap map, HttpServletRequest request) {
173174
}
174175
map.put("appLogos", appLogos);
175176

176-
177-
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
177+
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder
178+
.currentRequestAttributes();
178179
HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
179180
HttpServletResponse httpServletResponse = servletRequestAttributes.getResponse();
180181
map.put("request", httpServletRequest);
@@ -193,12 +194,12 @@ protected LogoInfo getAppLogoInfo(ProxySpec proxySpec) {
193194
}
194195

195196
return LogoInfo.builder()
196-
.src(src)
197-
.width(coalesce(proxySpec.getLogoWidth(), defaultLogoWidth))
198-
.height(coalesce(proxySpec.getLogoHeight(), defaultLogoHeight))
199-
.style(coalesce(proxySpec.getLogoStyle(), defaultLogoStyle))
200-
.classes(coalesce(proxySpec.getLogoClasses(), defaultLogoClasses))
201-
.build();
197+
.src(src)
198+
.width(coalesce(proxySpec.getLogoWidth(), defaultLogoWidth))
199+
.height(coalesce(proxySpec.getLogoHeight(), defaultLogoHeight))
200+
.style(coalesce(proxySpec.getLogoStyle(), defaultLogoStyle))
201+
.classes(coalesce(proxySpec.getLogoClasses(), defaultLogoClasses))
202+
.build();
202203
});
203204
}
204205

@@ -226,7 +227,8 @@ protected String resolveImageURI(String resourceURI) {
226227
}
227228

228229
/**
229-
* Checks whether starting a proxy violates the max instances of this spec and user.
230+
* Checks whether starting a proxy violates the max instances of this spec and
231+
* user.
230232
* This corresponds to the `max-instances` property of an app.
231233
*/
232234
protected boolean validateMaxInstances(ProxySpec spec) {
@@ -236,15 +238,20 @@ protected boolean validateMaxInstances(ProxySpec spec) {
236238
return true;
237239
}
238240

239-
// note: there is a very small change that the user is able to start more instances than allowed, if the user
241+
// note: there is a very small change that the user is able to start more
242+
// instances than allowed, if the user
240243
// starts many proxies at once. E.g. in the following scenario:
241244
// - max proxies = 2
242245
// - user starts a proxy
243-
// - user sends a start proxy request -> this function is called and returns true
244-
// - just before this new proxy is added to the list of active proxies, the user sends a new start proxy request
245-
// - again this new proxy is allowed, because there is still only one proxy in the list of active proxies
246+
// - user sends a start proxy request -> this function is called and returns
247+
// true
248+
// - just before this new proxy is added to the list of active proxies, the user
249+
// sends a new start proxy request
250+
// - again this new proxy is allowed, because there is still only one proxy in
251+
// the list of active proxies
246252
// -> the user has three proxies running.
247-
// Because of chance that this happens is small and that the consequences are low, we accept this risk.
253+
// Because of chance that this happens is small and that the consequences are
254+
// low, we accept this risk.
248255
long currentAmountOfInstances = proxyService.getUserProxiesBySpecId(spec.getId()).count();
249256

250257
return currentAmountOfInstances < maxInstances;

0 commit comments

Comments
 (0)