001/* 002 * Stallion Core: A Modern Web Framework 003 * 004 * Copyright (C) 2015 - 2016 Stallion Software LLC. 005 * 006 * This program is free software: you can redistribute it and/or modify it under the terms of the 007 * GNU General Public License as published by the Free Software Foundation, either version 2 of 008 * the License, or (at your option) any later version. This program is distributed in the hope that 009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 011 * License for more details. You should have received a copy of the GNU General Public License 012 * along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. 013 * 014 * 015 * 016 */ 017 018package io.stallion.settings; 019 020import io.stallion.boot.CommandOptionsBase; 021import io.stallion.exceptions.ConfigException; 022import io.stallion.exceptions.UsageException; 023import io.stallion.reflection.PropertyUtils; 024import io.stallion.requests.RouteDefinition; 025import io.stallion.services.Log; 026import io.stallion.settings.childSections.*; 027import io.stallion.utils.GeneralUtils; 028import org.apache.commons.lang3.StringUtils; 029 030import java.io.File; 031import java.time.ZoneId; 032import java.util.*; 033import java.util.regex.Pattern; 034 035import static io.stallion.utils.Literals.empty; 036import static io.stallion.utils.Literals.*; 037 038public class Settings implements ISettings { 039 040 041 042 // Child sections 043 private DbConfig database = null; 044 private UserSettings users = null; 045 private EmailSettings email = null; 046 private CustomSettings custom = null; 047 private CloudStorageSettings cloudStorage = null; 048 private StyleSettings styles = null; 049 private CorsSettings cors = null; 050 private OAuthSettings oAuth; 051 private SecretsSettings secrets; 052 053 054 // Site information 055 @SettingMeta() 056 private String authorName = null; 057 @SettingMeta() 058 private String siteName = null; 059 @SettingMeta(val="A Stallion Web Site") 060 private String defaultTitle = null; 061 @SettingMeta() 062 private String metaDescription = null; 063 @SettingMeta(val="Stallion") 064 private String metaGenerator = null; 065 @SettingMeta(val="", help = "The email address users of the site should contact in case of problems. This will be publicly viewable.") 066 private String supportEmail; 067 @SettingMeta(valLong = 1430510589000L) 068 private Long appCreatedMillis; 069 070 // Tuning 071 @SettingMeta(valLong = 5000000) 072 private Long filterCacheSize; 073 074 075 // File system info 076 @SettingMeta() 077 private String dataDirectory = null; 078 @SettingMeta() 079 private String targetFolder = null; 080 081 // Runtime mode config 082 @SettingMeta() 083 private Boolean localMode; 084 @SettingMeta() 085 private Boolean devMode; 086 @SettingMeta() 087 private String logFile; 088 @SettingMeta() 089 private Boolean logToConsole; 090 @SettingMeta() 091 private Boolean logToFile; 092 @SettingMeta() 093 private Boolean debug; 094 @SettingMeta() 095 private Boolean emailErrors; 096 @SettingMeta() 097 private StrictnessLevel strictnessLevel; 098 @SettingMeta(val="INFO") 099 private String logLevel; 100 private Map<String, String> packageLogLevels = new HashMap<>(); 101 private Integer nodeNumber = 1; 102 @SettingMeta(val="x-Real-Ip", help="The HTTP header that contains the original client IP address, by default, with nginx proxying, this is x-Real-Ip") 103 private String ipHeaderName; 104 105 106 107 private String env; 108 @SettingMeta() 109 private Boolean bundleDebug; 110 111 // Routes and rewrites 112 @SettingMeta(val="SAMEORIGIN") 113 private String xFrameOptions; 114 @SettingMeta(cls=ArrayList.class) 115 private List<RouteDefinition> routes = new ArrayList<>(); 116 @SettingMeta(cls=HashMap.class) 117 private Map<String, String> redirects = null; 118 @SettingMeta(cls=HashMap.class) 119 private Map<String, String> rewrites = null; 120 @SettingMeta(cls=ArrayList.class) 121 private List<String[]> rewritePatterns = null; 122 @SettingMeta(cls=ArrayList.class) 123 private List<Map.Entry<Pattern, String>> rewriteCompiledPatterns = null; 124 @SettingMeta(cls=ArrayList.class) 125 private List<SecondaryDomain> secondaryDomains; 126 private Map<String, SecondaryDomain> secondaryDomainByDomain = map(); 127 @SettingMeta(cls=ArrayList.class) 128 private List<AssetPreprocessorConfig> assetPreprocessors; 129 130 // Web Serving 131 @SettingMeta(valInt=8090) 132 private Integer port; 133 @SettingMeta(val="http://localhost:{port}") 134 private String cdnUrl; 135 @SettingMeta(val="http://localhost:{port}") 136 private String siteUrl; 137 @SettingMeta(val="25M") 138 private String nginxClientMaxBodySize; 139 @SettingMeta(val="3600") 140 private String nginxProxyReadTimeout; 141 142 // Default code directories and files 143 @SettingMeta(cls=ArrayList.class) 144 private List<ContentFolder> folders; 145 @SettingMeta(val="page.jinja") 146 private String pageTemplate = "page.jinja"; 147 148 // Email 149 150 // Publishing 151 //@SettingMeta(cls=ArrayList.class) 152 //private List<PublishingConfig> publishing; 153 154 155 // Time 156 @SettingMeta() 157 private String timeZone;// = ZoneId.systemDefault().toString(); 158 @SettingMeta() 159 private ZoneId timeZoneId;// = ZoneId.systemDefault(); 160 161 162 // Anti-spam 163 @SettingMeta(val = "") 164 private String antiSpamSecret; 165 @SettingMeta(valBoolean = false) 166 private Boolean disableFormSubmissions; 167 168 // Health 169 @SettingMeta(cls=ArrayList.class) 170 private List<String[]> healthCheckEndpoints = new ArrayList<>(); 171 @SettingMeta() 172 private String healthCheckSecret; 173 174 private static Settings _instance; 175 176 public static boolean isNull() { 177 return _instance == null; 178 } 179 180 public static void shutdown() { 181 _instance = null; 182 } 183 184 public static Settings instance() { 185 if (_instance == null) { 186 throw new UsageException("You must call load() before instance()."); 187 } 188 return _instance; 189 } 190 191 public static Settings init(String env, CommandOptionsBase options) { 192 _instance = new SettingsLoader().loadSettings(env, options.getTargetPath(), "stallion", Settings.class, options); 193 194 _instance.setCdnUrl(_instance.getCdnUrl().replace("{port}", _instance.getPort().toString())); 195 _instance.setSiteUrl(_instance.getSiteUrl().replace("{port}", _instance.getPort().toString())); 196 return _instance; 197 } 198 199 public void assignDefaults() { 200 if (getLocalMode() == null) { 201 if (empty(System.getenv().getOrDefault("STALLION_DEPLOY_TIME", ""))) { 202 setLocalMode(true); 203 } else { 204 setLocalMode(false); 205 } 206 } 207 208 if (bundleDebug == null) { 209 bundleDebug = getLocalMode(); 210 } 211 212 213 214 if (getDebug() == null) { 215 if (getEnv().equals("prod") && !getLocalMode()) { 216 setDebug(false); 217 } else { 218 setDebug(true); 219 } 220 } 221 222 if (timeZone == null) { 223 timeZone = ZoneId.systemDefault().toString(); 224 } 225 if (timeZoneId == null) { 226 timeZoneId = ZoneId.of(timeZone); 227 } 228 229 230 if (logFile == null) { 231 logFile = "/tmp/log/stallion/" + StringUtils.strip(GeneralUtils.slugify(targetFolder), "-") + ".log"; 232 } 233 if (logToConsole == null) { 234 logToConsole = getLocalMode(); 235 } 236 if (logToFile == null) { 237 logToFile = !logToConsole; 238 } 239 240 if (getEmailErrors() == null) { 241 if ((getEnv().equals("prod") || getEnv().equals("qa")) && !getLocalMode()) { 242 setEmailErrors(true); 243 } else { 244 setEmailErrors(false); 245 } 246 } 247 248 if (getStrictnessLevel() == null) { 249 if (getEnv().equals("prod") && !getLocalMode()) { 250 setStrictnessLevel(StrictnessLevel.LAX); 251 } else { 252 setStrictnessLevel(StrictnessLevel.STRICT); 253 } 254 } 255 256 if (!empty(secondaryDomains)) { 257 secondaryDomainByDomain = map(); 258 for (SecondaryDomain d: secondaryDomains) { 259 secondaryDomainByDomain.put(d.getDomain(), d); 260 } 261 } 262 263 264 if (!StringUtils.isEmpty(getDataDirectory())) { 265 if (!getDataDirectory().startsWith("/")) { 266 setDataDirectory(targetFolder + "/" + getDataDirectory()); 267 } 268 } else { 269 setDataDirectory(targetFolder + "/app-data"); 270 } 271 if (getDataDirectory().endsWith("/")) { 272 setDataDirectory(getDataDirectory().substring(0, getDataDirectory().length() - 1)); 273 } 274 275 if (getRewrites() != null) { 276 // THe Toml library has a bug whereby if a map key is quoted, it keeps the 277 // quotes as part of the key, rather than using the String inside the quotes 278 Set<String> keys = new HashSet<>(getRewrites().keySet()); 279 for(String key: keys) { 280 if (key.startsWith("\"") && key.endsWith("\"")) { 281 getRewrites().put(key.substring(1, key.length()-1), getRewrites().get(key)); 282 } 283 } 284 } 285 286 if (getRedirects() != null) { 287 // THe Toml library has a bug whereby if a map key is quoted, it keeps the 288 // quotes as part of the key, rather than using the String inside the quotes 289 Set<String> keys = new HashSet<>(getRedirects().keySet()); 290 for(String key: keys) { 291 if (key.startsWith("\"") && key.endsWith("\"")) { 292 getRedirects().put(key.substring(1, key.length()-1), getRedirects().get(key)); 293 } 294 } 295 } 296 297 if (getRewritePatterns() != null && getRewritePatterns().size() > 0) { 298 if (rewriteCompiledPatterns == null) { 299 rewriteCompiledPatterns = new ArrayList(); 300 } 301 for(String[] entry: getRewritePatterns()) { 302 if (entry.length != 2) { 303 Log.warn("Invalid rewritePatterns entry, size should be 2 but is {0} {1}", entry.length, entry); 304 } 305 Pattern pattern = Pattern.compile(entry[0]); 306 Map.Entry<Pattern, String> kv = new AbstractMap.SimpleEntry<Pattern, String>(pattern, entry[1]); 307 getRewriteCompiledPatterns().add(kv); 308 } 309 } 310 311 if (getEmail() != null) { 312 // By default, in debug mode, we do not want to send real emails to people 313 if (getEmail().getRestrictOutboundEmails() == null) { 314 getEmail().setRestrictOutboundEmails(getDebug()); 315 } 316 if (getEmail().getOutboundEmailTestAddress() == null) { 317 if (getEmail().getAdminEmails() != null && getEmail().getAdminEmails().size() > 0) { 318 getEmail().setOutboundEmailTestAddress(getEmail().getAdminEmails().get(0)); 319 } 320 } 321 if (!empty(getEmail().getAllowedTestingOutboundEmailPatterns())) { 322 if (getEmail().getAllowedTestingOutboundEmailCompiledPatterns() == null) { 323 getEmail().setAllowedTestingOutboundEmailCompiledPatterns(new ArrayList<>()); 324 } 325 for (String emailPattern : getEmail().getAllowedTestingOutboundEmailPatterns()) { 326 getEmail().getAllowedTestingOutboundEmailCompiledPatterns().add(Pattern.compile(emailPattern)); 327 } 328 } 329 } 330 331 if (getSecrets() == null) { 332 setSecrets(new SecretsSettings()); 333 } 334 335 if (new File(targetFolder + "/pages").isDirectory()) { 336 if (folders == null) { 337 folders = new ArrayList<>(); 338 } 339 folders.add(new ContentFolder().setPath(targetFolder + "/pages").setType("markdown").setItemTemplate(getPageTemplate())); 340 } 341 342 343 } 344 345 /** 346 * Gets the scheme (https or http) for a given secondary domain 347 * @return 348 */ 349 public String getSchemeForSecondaryDomain(String domain) { 350 SecondaryDomain d = secondaryDomainByDomain.get(domain); 351 return or(d.getScheme(), getSiteUrlScheme()); 352 } 353 354 /** 355 * Get siteUrl scheme 356 * @return 357 */ 358 public String getSiteUrlScheme() { 359 if (getSiteUrl().startsWith("https:")) { 360 return "https"; 361 } else { 362 return "http"; 363 } 364 } 365 366 367 public SecondaryDomain getSecondaryDomainByDomain(String domain) { 368 return secondaryDomainByDomain.get(domain); 369 } 370 371 /** 372 * In strict mode, more errors will be exceptions that stop all processing. For instance, missing template variables 373 * will cause exceptions rather than being ignored. 374 * @return 375 */ 376 public boolean isStrict() { 377 return StrictnessLevel.STRICT.equals(getStrictnessLevel()); 378 } 379 380 /** 381 * ContentFolders are folders in your local site directory that are to be registered with the data access controller. 382 * The .txt will be converted into accessible web pages in your site. 383 * @return 384 */ 385 public List<ContentFolder> getFolders() { 386 return folders; 387 } 388 389 public void setFolders(List<ContentFolder> folders) { 390 this.folders = folders; 391 } 392 393 /** 394 * The database configuration 395 * @return 396 */ 397 public DbConfig getDatabase() { 398 return database; 399 } 400 401 public void setDatabase(DbConfig database) { 402 this.database = database; 403 } 404 405 /** 406 * The user configuration 407 * @return 408 */ 409 public UserSettings getUsers() { 410 return users; 411 } 412 413 public void setUsers(UserSettings users) { 414 this.users = users; 415 } 416 417 /** 418 * Email configuration for Stallion sending emails via SMTP 419 * @return 420 */ 421 public EmailSettings getEmail() { 422 return email; 423 } 424 425 public void setEmail(EmailSettings email) { 426 this.email = email; 427 } 428 429 430 /** 431 * Cross-Origin Request configuration -- allow endpoints to respond to cross-origin requests. 432 * @return 433 */ 434 public CorsSettings getCors() { 435 return cors; 436 } 437 438 public Settings setCors(CorsSettings cors) { 439 this.cors = cors; 440 return this; 441 } 442 443 /** 444 * Where all data stored to flat-file by the Controllers and Persisters will actually live in the 445 * file system. This will be "app-data" under the site directory by default. 446 * @return 447 */ 448 public String getDataDirectory() { 449 return dataDirectory; 450 } 451 452 public void setDataDirectory(String dataDirectory) { 453 this.dataDirectory = dataDirectory; 454 } 455 456 /** 457 * A hashtable of arbitrary user defined settings. 458 * @return 459 */ 460 public CustomSettings getCustom() { 461 return custom; 462 } 463 464 public void setCustom(CustomSettings custom) { 465 this.custom = custom; 466 } 467 468 /** 469 * The default template to use to render pages 470 * 471 * @return 472 */ 473 public String getPageTemplate() { 474 return pageTemplate; 475 } 476 477 public void setPageTemplate(String pageTemplate) { 478 this.pageTemplate = pageTemplate; 479 } 480 481 /** 482 * The base URL for CDN (Content Delivery Network) that will pass through to your site. This is used 483 * by AssetsController.url() or AssetsController.bundle() to build URL's to your assets. If empty, will use 484 * the site URL instead. Using a CDN can improve performance as it will cache requested assets in data centers 485 * nearer to the end user. 486 * 487 * @return 488 */ 489 public String getCdnUrl() { 490 return cdnUrl; 491 } 492 493 public void setCdnUrl(String cdnUrl) { 494 this.cdnUrl = cdnUrl; 495 } 496 497 /** 498 * The base URL at which the site lives. Used to build links internally, also used for checking cross-origin 499 * requests. 500 * 501 * @return 502 */ 503 public String getSiteUrl() { 504 return siteUrl; 505 } 506 507 public void setSiteUrl(String siteUrl) { 508 this.siteUrl = siteUrl; 509 } 510 511 512 public List<RouteDefinition> getRoutes() { 513 return routes; 514 } 515 516 public void setRoutes(List<RouteDefinition> routes) { 517 this.routes = routes; 518 } 519 520 /** 521 * Run in debug mode. True by default when env=local. In debug mode, the full stack trace of exceptions 522 * will be rendered to the HTML output. 523 * 524 * @return 525 */ 526 public Boolean getDebug() { 527 return debug; 528 } 529 530 public void setDebug(Boolean debug) { 531 this.debug = debug; 532 } 533 534 /** 535 * Should be a time zone parseable by ZoneId.of() Used by the DateUtils.renderLocalDate() method when there 536 * is no time zone for the particular user. 537 * 538 * @return 539 */ 540 public String getTimeZone() { 541 return timeZone; 542 } 543 544 public void setTimeZone(String timeZone) { 545 this.timeZone = timeZone; 546 } 547 548 public ZoneId getTimeZoneId() { 549 return timeZoneId; 550 } 551 552 public void setTimeZoneId(ZoneId timeZoneId) { 553 this.timeZoneId = timeZoneId; 554 } 555 556 /** 557 * Usually set by the command line options, rather than the stallion.toml file. 558 * 559 * If true, templates and assets will automatically be checked for changes from the original source 560 * and re-compiled if they have changed. 561 * 562 * @return 563 */ 564 public Boolean getDevMode() { 565 return devMode; 566 } 567 568 public void setDevMode(Boolean devMode) { 569 this.devMode = devMode; 570 } 571 572 /** 573 * Set the log level - INFO, FINE, FINER, FINEST 574 * 575 * @return 576 */ 577 public String getLogLevel() { 578 return logLevel; 579 } 580 581 public void setLogLevel(String logLevel) { 582 this.logLevel = logLevel; 583 } 584 585 public Map<String, String> getPackageLogLevels() { 586 return packageLogLevels; 587 } 588 589 public void setPackageLogLevels(Map<String, String> packageLogLevels) { 590 this.packageLogLevels = packageLogLevels; 591 } 592 593 594 /** 595 * The current environment name, set by command line options. 596 * 597 * @return 598 */ 599 public String getEnv() { 600 return env; 601 } 602 603 public void setEnv(String env) { 604 this.env = env; 605 } 606 607 /** 608 * True by default if in debug mode, false on production. If true, 609 * bundle files will be included on the page as individual source files, rather than as a concatenated, 610 * minified file. 611 * 612 * @return 613 */ 614 public Boolean getBundleDebug() { 615 return bundleDebug; 616 } 617 618 public void setBundleDebug(Boolean bundleDebug) { 619 this.bundleDebug = bundleDebug; 620 } 621 622 /** 623 * The name of your site, accessible in templates via {{ site.name }} 624 * 625 * @return 626 */ 627 public String getSiteName() { 628 return siteName; 629 } 630 631 public void setSiteName(String siteName) { 632 this.siteName = siteName; 633 } 634 635 /** 636 * The default title of your site, will be used in the HTML title tag in the default base template 637 * if no other title for a page is defined. 638 * 639 * 640 * @return 641 */ 642 public String getDefaultTitle() { 643 return defaultTitle; 644 } 645 646 public void setDefaultTitle(String defaultTitle) { 647 this.defaultTitle = defaultTitle; 648 } 649 650 /** 651 * The default meta tag description value. Used if there is no override for the particular page or endpoint. 652 * @return 653 */ 654 public String getMetaDescription() { 655 return metaDescription; 656 } 657 658 public void setMetaDescription(String metaDescription) { 659 this.metaDescription = metaDescription; 660 } 661 662 /** 663 * Get the name of the author of the site 664 * 665 * @return 666 */ 667 public String getAuthorName() { 668 return authorName; 669 } 670 671 public void setAuthorName(String authorName) { 672 this.authorName = authorName; 673 } 674 675 /** 676 * The port the server should run on. Usually set by the command line options. 677 * 678 * @return 679 */ 680 public Integer getPort() { 681 return port; 682 } 683 684 public void setPort(Integer port) { 685 this.port = port; 686 } 687 688 /** 689 * The root site folder that contains the conf directory and the conf/stallion.toml files. 690 * This is always set via the command line options, or defaults to the current working directory. 691 * 692 * @return 693 */ 694 public String getTargetFolder() { 695 return targetFolder; 696 } 697 698 public void setTargetFolder(String targetFolder) { 699 this.targetFolder = targetFolder; 700 } 701 702 public StrictnessLevel getStrictnessLevel() { 703 return strictnessLevel; 704 } 705 706 public void setStrictnessLevel(StrictnessLevel strictnessLevel) { 707 this.strictnessLevel = strictnessLevel; 708 } 709 710 /** 711 * A list of paths that will be checked for a 200 response when the health check 712 * is run. 713 * 714 * @return 715 */ 716 public List<String[]> getHealthCheckEndpoints() { 717 return healthCheckEndpoints; 718 } 719 720 public void setHealthCheckEndpoints(List<String[]> healthCheckEndpoints) { 721 this.healthCheckEndpoints = healthCheckEndpoints; 722 } 723 724 /** 725 * A secret token that must be passed in when accessing the health endpoints. 726 * 727 * @return 728 */ 729 public String getHealthCheckSecret() { 730 return healthCheckSecret; 731 } 732 733 public void setHealthCheckSecret(String healthCheckSecret) { 734 this.healthCheckSecret = healthCheckSecret; 735 } 736 737 738 /** 739 * If true, exceptions will emailed to the admin defined in the email configuration. 740 * 741 * @return 742 */ 743 public Boolean getEmailErrors() { 744 return emailErrors; 745 } 746 747 public void setEmailErrors(Boolean emailErrors) { 748 this.emailErrors = emailErrors; 749 } 750 751 /** 752 * A map of 301 redirects in the form of original URL or path to destination URL or path. 753 * 754 * @return 755 */ 756 public Map<String, String> getRedirects() { 757 return redirects; 758 } 759 760 public void setRedirects(Map<String, String> redirects) { 761 this.redirects = redirects; 762 } 763 764 /** 765 * The meta tag value for generator. "Stallion" by default. 766 * @return 767 */ 768 public String getMetaGenerator() { 769 return metaGenerator; 770 } 771 772 public void setMetaGenerator(String metaGenerator) { 773 this.metaGenerator = metaGenerator; 774 } 775 776 /** 777 * The path to the log file when file-based logging is on. 778 * 779 * @return 780 */ 781 public String getLogFile() { 782 return logFile; 783 } 784 785 public void setLogFile(String logFile) { 786 this.logFile = logFile; 787 } 788 789 /** 790 * If true, log to the console instead of file. This defaults to true in local mode. 791 * 792 * @return 793 */ 794 public Boolean getLogToConsole() { 795 return logToConsole; 796 } 797 798 public void setLogToConsole(Boolean logToConsole) { 799 this.logToConsole = logToConsole; 800 } 801 802 public Boolean getLogToFile() { 803 return logToFile; 804 } 805 806 public void setLogToFile(Boolean logToFile) { 807 this.logToFile = logToFile; 808 } 809 810 /** 811 * True if this is a developer running locally, false if this is running deployed on a server. 812 * 813 * If localMode is true, production jobs and tasks will not be run and logging will go to the console. 814 * 815 * 816 * @return 817 */ 818 public Boolean getLocalMode() { 819 return localMode; 820 } 821 822 public void setLocalMode(Boolean localMode) { 823 this.localMode = localMode; 824 } 825 826 827 /** 828 * A mapping of internal rewrites, from source path to destintion path. 829 * @return 830 */ 831 public Map<String, String> getRewrites() { 832 return rewrites; 833 } 834 835 public void setRewrites(Map<String, String> rewrites) { 836 this.rewrites = rewrites; 837 } 838 839 /** 840 * A list of domains that content is also accesible at, and their mapping 841 * to URL paths. 842 * 843 * @return 844 */ 845 public List<SecondaryDomain> getSecondaryDomains() { 846 return secondaryDomains; 847 } 848 849 public Settings setSecondaryDomains(List<SecondaryDomain> secondaryDomains) { 850 this.secondaryDomains = secondaryDomains; 851 return this; 852 } 853 854 public List<Map.Entry<Pattern, String>> getRewriteCompiledPatterns() { 855 return rewriteCompiledPatterns; 856 } 857 858 public void setRewriteCompiledPatterns(List<Map.Entry<Pattern, String>> rewriteCompiledPatterns) { 859 this.rewriteCompiledPatterns = rewriteCompiledPatterns; 860 } 861 862 /** 863 * A list of arrays, each array has two values, a source regular expression and a destination path. 864 * @return 865 */ 866 public List<String[]> getRewritePatterns() { 867 return rewritePatterns; 868 } 869 870 public void setRewritePatterns(List<String[]> rewritePatterns) { 871 this.rewritePatterns = rewritePatterns; 872 } 873 874 /** 875 * Configuration for integration with a cloud file storage, such as S3. 876 * 877 * @return 878 */ 879 public CloudStorageSettings getCloudStorage() { 880 return cloudStorage; 881 } 882 883 public void setCloudStorage(CloudStorageSettings cloudStorage) { 884 this.cloudStorage = cloudStorage; 885 } 886 887 /** 888 * Default CSS styles and colors that will be used in the default templates 889 * for log in, password reset emails, etc. 890 * 891 * @return 892 */ 893 public StyleSettings getStyles() { 894 return styles; 895 } 896 897 public void setStyles(StyleSettings style) { 898 this.styles = style; 899 } 900 901 /** 902 * For deployed sites using stablehand, which node this is. 903 * 904 * @return 905 */ 906 public Integer getNodeNumber() { 907 return nodeNumber; 908 } 909 910 public Settings setNodeNumber(Integer nodeNumber) { 911 this.nodeNumber = nodeNumber; 912 return this; 913 } 914 915 /** 916 * A random token used for preventing spam in form submissions and comments. 917 * 918 * @return 919 */ 920 public String getAntiSpamSecret() { 921 return antiSpamSecret; 922 } 923 924 public Settings setAntiSpamSecret(String antiSpamSecret) { 925 this.antiSpamSecret = antiSpamSecret; 926 return this; 927 } 928 929 /** 930 * If true, the default form submission endpoint will be disabled. 931 * @return 932 */ 933 public Boolean getDisableFormSubmissions() { 934 return disableFormSubmissions; 935 } 936 937 public Settings setDisableFormSubmissions(Boolean disableFormSubmissions) { 938 this.disableFormSubmissions = disableFormSubmissions; 939 return this; 940 } 941 942 943 /** 944 * If there is a proxy server in front of Stallion, that proxy server will set 945 * the IP address of the original requester and put it in a header. Add that header 946 * name here so that Stallion can know the IP of the original requester. 947 * 948 * @return 949 */ 950 public String getIpHeaderName() { 951 return ipHeaderName; 952 } 953 954 public Settings setIpHeaderName(String ipHeaderName) { 955 this.ipHeaderName = ipHeaderName; 956 return this; 957 } 958 959 /** 960 * Configuration for enabling users to give out OAuth access 961 * 962 * @return 963 */ 964 public OAuthSettings getoAuth() { 965 return oAuth; 966 } 967 968 public Settings setoAuth(OAuthSettings oAuth) { 969 this.oAuth = oAuth; 970 return this; 971 } 972 973 public Long getFilterCacheSize() { 974 return filterCacheSize; 975 } 976 977 public Settings setFilterCacheSize(Long filterCacheSize) { 978 this.filterCacheSize = filterCacheSize; 979 return this; 980 } 981 982 public SecretsSettings getSecrets() { 983 return secrets; 984 } 985 986 public Settings setSecrets(SecretsSettings secrets) { 987 this.secrets = secrets; 988 return this; 989 } 990 991 /** 992 * Included in the templates for error pages. 993 * 994 * @return 995 */ 996 public String getSupportEmail() { 997 return supportEmail; 998 } 999 1000 public Settings setSupportEmail(String supportEmail) { 1001 this.supportEmail = supportEmail; 1002 return this; 1003 } 1004 1005 1006 /* 1007 public List<PublishingConfig> getPublishing() { 1008 return publishing; 1009 } 1010 1011 1012 public Settings setPublishing(List publishing) { 1013 if (publishing == null) { 1014 this.publishing = null; 1015 return this; 1016 } 1017 if (publishing.size() == 0) { 1018 this.publishing = new ArrayList<>(); 1019 return this; 1020 } 1021 this.publishing = new ArrayList<>(); 1022 if (publishing.get(0) instanceof Map) { 1023 for(Object o: publishing) { 1024 PublishingConfig config = new PublishingConfig(); 1025 Map<String, Object> m = (Map<String, Object>)o; 1026 for(Map.Entry<String, Object> e: m.entrySet()) { 1027 Object value = e.getValue(); 1028 if (e.getKey().equals("basePort") && e.getValue() instanceof Long) { 1029 value = Math.toIntExact((Long)value); 1030 } 1031 PropertyUtils.setProperty(config, e.getKey(), value); 1032 } 1033 this.publishing.add(config); 1034 } 1035 } else { 1036 this.publishing.addAll(publishing); 1037 } 1038 return this; 1039 } 1040 */ 1041 1042 public Long getAppCreatedMillis() { 1043 return appCreatedMillis; 1044 } 1045 1046 public Settings setAppCreatedMillis(Long appCreatedMillis) { 1047 this.appCreatedMillis = appCreatedMillis; 1048 return this; 1049 } 1050 1051 public List<AssetPreprocessorConfig> getAssetPreprocessors() { 1052 return assetPreprocessors; 1053 } 1054 1055 public Settings setAssetPreprocessors(List assetPreProcessors) { 1056 this.assetPreprocessors = convertMapListToObjects(assetPreProcessors, AssetPreprocessorConfig.class); 1057 for (AssetPreprocessorConfig config: this.assetPreprocessors) { 1058 if (empty(config.getCommand()) || empty(config.getName()) || empty(config.getExtension())) { 1059 throw new ConfigException("Asset Pre-processors must have a valid command, name, and extension"); 1060 } 1061 } 1062 return this; 1063 } 1064 1065 protected List convertMapListToObjects(List maps, Class targetClass) { 1066 if (maps.size() == 0) { 1067 return maps; 1068 } 1069 if (targetClass.isAssignableFrom(maps.get(0).getClass())) { 1070 return maps; 1071 } 1072 List items = new ArrayList<>(); 1073 for (Object o: maps) { 1074 Map<String, Object> map = (Map<String, Object>)o; 1075 try { 1076 Object instance = targetClass.newInstance(); 1077 for(Map.Entry<String, Object> e: map.entrySet()) { 1078 Object value = e.getValue(); 1079 if (e.getKey().equals("basePort") && e.getValue() instanceof Long) { 1080 value = Math.toIntExact((Long)value); 1081 } 1082 PropertyUtils.setProperty(instance, e.getKey(), value); 1083 } 1084 items.add(instance); 1085 1086 } catch (InstantiationException e) { 1087 throw new RuntimeException(e); 1088 } catch (IllegalAccessException e) { 1089 throw new RuntimeException(e); 1090 } 1091 } 1092 return items; 1093 } 1094 1095 public String getxFrameOptions() { 1096 return xFrameOptions; 1097 } 1098 1099 public Settings setxFrameOptions(String xFrameOptions) { 1100 this.xFrameOptions = xFrameOptions; 1101 return this; 1102 } 1103 1104 1105 1106 public String getNginxClientMaxBodySize() { 1107 return nginxClientMaxBodySize; 1108 } 1109 1110 public Settings setNginxClientMaxBodySize(String nginxClientMaxBodySize) { 1111 this.nginxClientMaxBodySize = nginxClientMaxBodySize; 1112 return this; 1113 } 1114 1115 1116 public String getNginxProxyReadTimeout() { 1117 return nginxProxyReadTimeout; 1118 } 1119 1120 public Settings setNginxProxyReadTimeout(String nginxProxyReadTimeout) { 1121 this.nginxProxyReadTimeout = nginxProxyReadTimeout; 1122 return this; 1123 } 1124}