Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ThemeConfiguration.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Xml;
5using System.Xml.Schema;
6using System.Threading.Tasks;
7using Waher.Content;
9using Waher.Events;
16
18{
23 {
24 private readonly static Dictionary<string, ThemeDefinition> themeDefinitions = new Dictionary<string, ThemeDefinition>();
25 private static ThemeConfiguration instance = null;
26 private HttpResource setTheme = null;
27
28 private string themeId = string.Empty;
29 private Dictionary<string, object> themeIdByAlternativeHost;
30
35 : base()
36 {
37 }
38
42 public static ThemeConfiguration Instance => instance;
43
47 [DefaultValueStringEmpty]
48 public string ThemeId
49 {
50 get => this.themeId;
51 set => this.themeId = value;
52 }
53
59 public string GetThemeId(IHostReference HostReference)
60 {
61 string Host = DomainSettings.IsAlternativeDomain(HostReference.Host);
62 if (string.IsNullOrEmpty(Host))
63 return this.themeId;
64
65 lock (themeDefinitions)
66 {
67 if (themeDefinitions.TryGetValue(Host, out ThemeDefinition Def))
68 return Def.Id;
69 else
70 return this.themeId;
71 }
72 }
73
77 public override string Resource => "/Settings/Theme.md";
78
82 public override int Priority => 500;
83
89 public override Task<string> Title(Runtime.Language.Language Language)
90 {
91 return Language.GetStringAsync(typeof(Gateway), 5, "Theme");
92 }
93
97 public override Task ConfigureSystem()
98 {
99 if (!string.IsNullOrEmpty(this.themeId) && themeDefinitions.TryGetValue(this.themeId, out ThemeDefinition Def))
100 Theme.CurrentTheme = Def;
101
102 // TODO: GraphViz, PlantUml, LayoutXml for alternative domains.
103
104 return Task.CompletedTask;
105 }
106
111 public override void SetStaticInstance(ISystemConfiguration Configuration)
112 {
113 instance = Configuration as ThemeConfiguration;
114 }
115
120 public override async Task InitSetup(HttpServer WebServer)
121 {
122 XmlSchema Schema = XSL.LoadSchema(typeof(Gateway).Namespace + ".Schema.Theme.xsd", typeof(Gateway).Assembly);
123 string ThemesFolder = Path.Combine(Gateway.AppDataFolder, "Root", "Themes");
124 ThemeDefinition Def;
125
126 await base.InitSetup(WebServer);
127
128 await WebServer.SetETagSalt(this.Updated.Ticks.ToString());
129
130 if (Directory.Exists(ThemesFolder))
131 {
132 foreach (string FileName in Directory.GetFiles(ThemesFolder, "*.xml", SearchOption.AllDirectories))
133 {
134 try
135 {
136 XmlDocument Doc = new XmlDocument()
137 {
138 PreserveWhitespace = true
139 };
140 Doc.Load(FileName);
141
142 XSL.Validate(FileName, Doc, "Theme", "http://waher.se/Schema/Theme.xsd", Schema);
143
144 Def = new ThemeDefinition(Doc);
145 themeDefinitions[Def.Id] = Def;
146 }
147 catch (Exception ex)
148 {
149 Log.Exception(ex, FileName);
150 continue;
151 }
152 }
153 }
154
155 bool Update = false;
156
157 if (!string.IsNullOrEmpty(this.themeId) && !themeDefinitions.ContainsKey(this.themeId))
158 {
159 this.themeId = string.Empty;
160 this.Step = 0;
161 this.Completed = DateTime.MinValue;
162 this.Complete = false;
163
164 Update = true;
165 }
166
167 if (string.IsNullOrEmpty(this.themeId) && themeDefinitions.Count == 1)
168 {
169 foreach (ThemeDefinition Def2 in themeDefinitions.Values)
170 {
171 this.themeId = Def2.Id;
172
173 await this.MakeCompleted();
174 Update = false;
175
176 break;
177 }
178 }
179
180 if (Update)
181 {
182 this.Updated = DateTime.Now;
183 await Database.Update(this);
184 }
185
186 if (!string.IsNullOrEmpty(this.themeId) && themeDefinitions.TryGetValue(this.themeId, out Def))
187 Theme.CurrentTheme = Def;
188 else if (themeDefinitions.TryGetValue("CactusRose", out Def))
189 Theme.CurrentTheme = Def;
190 else
191 {
192 foreach (ThemeDefinition Def2 in themeDefinitions.Values)
193 {
194 Theme.CurrentTheme = Def2;
195 break;
196 }
197 }
198
199 this.themeIdByAlternativeHost = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
200 foreach (KeyValuePair<string, object> P in await HostSettings.GetHostValuesAsync("ThemeId"))
201 this.themeIdByAlternativeHost[P.Key] = P.Value;
202
203 foreach (KeyValuePair<string, object> P in this.themeIdByAlternativeHost)
204 {
205 if (P.Value is string ThemeId && themeDefinitions.TryGetValue(ThemeId, out Def))
206 Theme.SetTheme(P.Key, Def);
207 }
208
209 this.setTheme = WebServer.Register("/Settings/SetTheme", null, this.SetTheme, true, false, true);
210 }
211
216 public override Task UnregisterSetup(HttpServer WebServer)
217 {
218 WebServer.Unregister(this.setTheme);
219
220 return base.UnregisterSetup(WebServer);
221 }
222
226 protected override string ConfigPrivilege => "Admin.Presentation.Theme";
227
228 private async Task SetTheme(HttpRequest Request, HttpResponse Response)
229 {
230 Gateway.AssertUserAuthenticated(Request, this.ConfigPrivilege);
231
232 if (!Request.HasData)
233 throw new BadRequestException();
234
235 object Obj = await Request.DecodeDataAsync();
236 if (!(Obj is string ThemeId))
237 throw new BadRequestException();
238
239 string TabID = Request.Header["X-TabID"];
240 if (string.IsNullOrEmpty(TabID))
241 throw new BadRequestException();
242
243 if (!themeDefinitions.TryGetValue(ThemeId, out ThemeDefinition Def))
244 throw new NotFoundException("Theme not found: " + ThemeId);
245
246 string Host = DomainSettings.IsAlternativeDomain(Request.Host);
247 if (string.IsNullOrEmpty(Host))
248 {
249 Theme.CurrentTheme = Def;
250
251 this.themeId = Def.Id;
252
253 if (this.Step <= 0)
254 this.Step = 1;
255 }
256 else
257 {
258 lock (this.themeIdByAlternativeHost)
259 {
260 this.themeIdByAlternativeHost[Host] = Def;
261 }
262
263 await HostSettings.SetAsync(Host.ToLower(), "ThemeId", Def.Id);
264
265 Theme.SetTheme(Host, Def);
266
267 // TODO: GraphViz, PlantUml, LayoutXml colors.
268 }
269
270 this.Updated = DateTime.Now;
271 await Database.Update(this);
272
273 await Gateway.HttpServer.SetETagSalt(this.Updated.Ticks.ToString());
274
275 await ClientEvents.PushEvent(new string[] { TabID }, "ThemeOk", JSON.Encode(new KeyValuePair<string, object>[]
276 {
277 new KeyValuePair<string, object>("themeId", Def.Id),
278 new KeyValuePair<string, object>("cssUrl", Def.CSSX),
279 }, false), true, "User");
280
281 Response.StatusCode = 200;
282 }
283
289 {
290 ThemeDefinition[] Result = new ThemeDefinition[themeDefinitions.Count];
291 themeDefinitions.Values.CopyTo(Result, 0);
292
293 Array.Sort(Result, (t1, t2) => t1.Title.CompareTo(t2.Title));
294
295 return Result;
296 }
297
304 public static bool TryGetTheme(string ThemeId, out ThemeDefinition Definition)
305 {
306 return themeDefinitions.TryGetValue(ThemeId, out Definition);
307 }
308
312 public const string GATEWAY_THEME_ID = nameof(GATEWAY_THEME_ID);
313
318 public override Task<bool> EnvironmentConfiguration()
319 {
320 string Value = Environment.GetEnvironmentVariable(GATEWAY_THEME_ID);
321 if (string.IsNullOrEmpty(Value))
322 return Task.FromResult(false);
323
324 if (!themeDefinitions.ContainsKey(Value))
325 {
326 this.LogEnvironmentError("Theme not found.", GATEWAY_THEME_ID, Value);
327 return Task.FromResult(false);
328 }
329
330 this.themeId = Value;
331
332 return Task.FromResult(true);
333 }
334
335 }
336}
Helps with common JSON-related tasks.
Definition: JSON.cs:14
static string Encode(string s)
Encodes a string for inclusion in JSON.
Definition: JSON.cs:507
Static class managing loading of XSL resources stored as embedded resources or in content files.
Definition: XSL.cs:15
static XmlSchema LoadSchema(string ResourceName)
Loads an XML schema from an embedded resource.
Definition: XSL.cs:23
static void Validate(string ObjectID, XmlDocument Xml, params XmlSchema[] Schemas)
Validates an XML document given a set of XML schemas.
Definition: XSL.cs:118
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1647
The ClientEvents class allows applications to push information asynchronously to web clients connecte...
Definition: ClientEvents.cs:51
static Task< int > PushEvent(string[] TabIDs, string Type, object Data)
Puses an event to a set of Tabs, given their Tab IDs.
Static class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:126
static HttpServer HttpServer
HTTP Server
Definition: Gateway.cs:3299
static IUser AssertUserAuthenticated(HttpRequest Request, string Privilege)
Makes sure a request is being made from a session with a successful user login.
Definition: Gateway.cs:3041
static string AppDataFolder
Application data folder.
Definition: Gateway.cs:2369
Returns the time elapsed since the gateway was started.
Definition: Runtime.cs:13
DateTime Updated
When the object was updated.
void LogEnvironmentError(string EnvironmentVariable, object Value)
Logs an error to the event log, telling the operator an environment variable value contains an error.
virtual Task MakeCompleted()
Sets the configuration task as completed.
Abstract base class for multi-step system configurations.
override void SetStaticInstance(ISystemConfiguration Configuration)
Sets the static instance of the configuration.
override int Priority
Priority of the setting. Configurations are sorted in ascending order.
static ThemeDefinition[] GetDefinitions()
Gets available theme definitions.
override Task< string > Title(Runtime.Language.Language Language)
Gets a title for the system configuration.
string GetThemeId(IHostReference HostReference)
Gets the Theme ID that corresponds to a host.
override async Task InitSetup(HttpServer WebServer)
Initializes the setup object.
override Task< bool > EnvironmentConfiguration()
Environment configuration by configuring values available in environment variables.
static bool TryGetTheme(string ThemeId, out ThemeDefinition Definition)
Tries to get the theme definition, given its ID.
override string ConfigPrivilege
Minimum required privilege for a user to be allowed to change the configuration defined by the class.
override string Resource
Resource to be redirected to, to perform the configuration.
const string GATEWAY_THEME_ID
ID of theme to use.
override Task UnregisterSetup(HttpServer WebServer)
Unregisters the setup object.
override Task ConfigureSystem()
Is called during startup to configure the system.
static ThemeConfiguration Instance
Current instance of configuration.
Contains properties for a theme.
string Title
A human readable title for the theme.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
Represents an HTTP request.
Definition: HttpRequest.cs:18
HttpRequestHeader Header
Request header.
Definition: HttpRequest.cs:134
bool HasData
If the request has data.
Definition: HttpRequest.cs:74
string Host
Host reference. (Value of Host header, without the port number)
Definition: HttpRequest.cs:215
async Task< object > DecodeDataAsync()
Decodes data sent in request.
Definition: HttpRequest.cs:95
Base class for all HTTP resources.
Definition: HttpResource.cs:23
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:21
Implements an HTTP server.
Definition: HttpServer.cs:36
bool Unregister(HttpResource Resource)
Unregisters a resource from the server.
Definition: HttpServer.cs:1438
async Task SetETagSalt(string NewSalt)
Sets a new salt value used when calculating ETag values.
Definition: HttpServer.cs:751
The server has not found anything matching the Request-URI. No indication is given of whether the con...
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
static async Task Update(object Object)
Updates an object in the database.
Definition: Database.cs:626
Contains information about a language.
Definition: Language.cs:17
Task< string > GetStringAsync(Type Type, int Id, string Default)
Gets the string value of a string ID. If no such string exists, a string is created with the default ...
Definition: Language.cs:209
Contains information about a namespace in a language.
Definition: Namespace.cs:17
Static class managing persistent host settings. Host settings default to runtime settings if host-spe...
Definition: HostSettings.cs:18
static Task< Dictionary< string, object > > GetHostValuesAsync(string Key)
Gets available settings for a given key, indexed by host.
static async Task< bool > SetAsync(string Host, string Key, string Value)
Sets a string-valued setting.
Definition: HostSettings.cs:77
Interface for objects that contain a reference to a host.
string Host
Host reference.
Interface for system configurations. The gateway will scan all module for system configuration classe...