1 /**
2 * Copyright © DiamondMVC 2018
3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module diamond.core.webconfig;
7 
8 import diamond.core.apptype;
9 
10 static if (isWebApi)
11 {
12   /**
13   * Generates the controller data.
14   * Returns:
15   *   An array with the names of the controllers to handle.
16   */
17   string[] generateControllerData()
18   {
19     import std.array : replace, split, array;
20     import std..string : strip;
21     import std.algorithm : filter;
22 
23     return import("controllers.config")
24       .replace("\r", "").split("\n").filter!(c => c && c.strip().length).array;
25   }
26 }
27 
28 static if (!isWebApi)
29 {
30   /// Mixin template to load view data (name + content)
31   mixin template LoadViewData(bool namesOnly = false)
32   {
33     /// Generates the functon "getViewData()" which gives you an AA like content[viewName]
34     private string generateViewData()
35     {
36       import std..string : strip;
37       import std.array : split, replace;
38 
39       enum viewConfig = import("views.config");
40 
41       string viewDataString = "string[string] getViewData()
42       {
43         string[string] viewData;
44       ";
45 
46       foreach (line; viewConfig.split("\n"))
47       {
48         if (!line)
49         {
50           continue;
51         }
52 
53         line = line.strip().replace("\r", "");
54 
55         if (!line && line.length)
56         {
57           continue;
58         }
59 
60         auto data = line.split("|");
61 
62         if (data.length != 2)
63         {
64           continue;
65         }
66 
67         static if (namesOnly)
68         {
69           auto viewName = data[0].strip();
70 
71           viewDataString ~= "  viewData[\"" ~ viewName ~ "\"] = \"" ~ viewName  ~ "\";";
72         }
73         else
74         {
75           viewDataString ~= "  viewData[\"" ~ data[0].strip() ~ "\"] = import(\"" ~ data[1].strip() ~ "\");";
76         }
77       }
78 
79       viewDataString ~= "  return viewData;
80       }";
81 
82       return viewDataString;
83     }
84 
85     mixin(generateViewData);
86   }
87 }
88 
89 static if (isWeb)
90 {
91   import vibe.data.serialization : optional;
92 
93   /// Web configurations.
94   class WebConfig
95   {
96     /// The name of the web application.
97     string name;
98     /// The routes that are mapped to static files.
99     string[] staticFileRoutes;
100     /// The route that's mapped to the home page.
101     string homeRoute;
102     /// Boolean determining whether views can be accessed by their file name.
103     bool allowFileRoute;
104     /// An array of addresses the web application is accessible by.
105     WebAddress[] addresses;
106     /// The default headers the web application uses.
107     WebHeaders defaultHeaders;
108     /// Boolean determining whether the access log should be redirected to the console.
109     @optional bool accessLogToConsole;
110     /// The time sessions are stored in memory.
111     @optional long sessionAliveTime;
112     // A special string representation that splits the root routes when checking ACL.
113     @optional string specialRouteSplitter;
114     /// Boolean determnining whether views can be cached or not.
115     @optional bool shouldCacheViews;
116     /// An array of global restricted ip addresses.
117     @optional string[] globalRestrictedIPs;
118     /// An array of restricted ip addresses.
119     @optional string[] restrictedIPs;
120     /// A collection of db connection configurations.
121     @optional WebDbConnections dbConnections;
122     /// Tn associative array of specialized routes.
123     @optional WebSpecialRoute[string] specializedRoutes;
124     /// A static web-page to display for maintenance. When specified the website will automatically be set to maintenance-mode.
125     @optional string maintenance;
126     /// An array of ips that can still access the site during maintenance.
127     @optional string[] maintenanceWhiteList;
128     /// Boolean determining whethere there's only one view to use for routing. The view must be named __view.dd
129     @optional bool viewOnly;
130   }
131 
132   /// A web address.
133   class WebAddress
134   {
135     /// An array of ip addresses that the web address is bound to.
136     string[] ipAddresses;
137     /// The port the web address is bound to.
138     ushort port;
139   }
140 
141   /// Web headers.
142   class WebHeaders
143   {
144     /// Headers used for general purpose.
145     string[string] general;
146     /// Headers used for static files.
147     string[string] staticFiles;
148     /// Headers used for 404 responses.
149     string[string] notFound;
150     /// Headers used for error responses.
151     string[string] error;
152   }
153 
154   /// Wrapper around db connection configurations.
155   class WebDbConnections
156   {
157     @optional WebDbConnectionConfig[string] mysql;
158   }
159 
160   /// Wrapper around a db connection configuration.
161   class WebDbConnectionConfig
162   {
163     /// The host.
164     string host;
165     /// The port.
166     @optional ushort port;
167     /// The user.
168     string user;
169     /// The password.
170     string password;
171     /// The database.
172     string database;
173   }
174 
175   /// Wrapper around a special route.
176   class WebSpecialRoute
177   {
178     /// The type of the route.
179     string type;
180     /// The value of the route.
181     string value;
182   }
183 
184   /// The web configuration.
185   private static __gshared WebConfig _webConfig;
186 
187   /// Gets the web configuration.
188   @property WebConfig webConfig() { return _webConfig; }
189 
190   /// Loads the web configuration.
191   void loadWebConfig()
192   {
193     import vibe.d : deserializeJson;
194     import std.file : readText;
195 
196     _webConfig = deserializeJson!WebConfig(readText("config/web.json"));
197 
198     if (_webConfig.homeRoute[0] == '/')
199     {
200       _webConfig.homeRoute = _webConfig.homeRoute[1 .. $];
201     }
202 
203     if (_webConfig.homeRoute[$-1] == '/')
204     {
205       _webConfig.homeRoute = _webConfig.homeRoute[0 .. $-1];
206     }
207 
208     if (_webConfig.sessionAliveTime <= 0)
209     {
210       _webConfig.sessionAliveTime = 30;
211     }
212 
213     if (!_webConfig.specialRouteSplitter)
214     {
215       _webConfig.specialRouteSplitter = "-";
216     }
217   }
218 }