diff --git a/ln.templates.service/HttpTemplateEndpoints.cs b/ln.templates.service/HttpTemplateEndpoints.cs index bc7aee7..af3e115 100644 --- a/ln.templates.service/HttpTemplateEndpoints.cs +++ b/ln.templates.service/HttpTemplateEndpoints.cs @@ -96,6 +96,42 @@ namespace ln.templates.service return HttpResponse.InternalServerError(); } + + [Map(HttpMethod.GET, "/resources$")] + public HttpResponse GetResources() + { + JSONArray templates = JSONMapper.DefaultMapper.ToJson(_templateService.ListResources()) as JSONArray; + return HttpResponse.OK().Content(templates); + } + [Map(HttpMethod.GET, "/resources/(?.*)$")] + public HttpResponse GetResourceFile( + [HttpArgumentSource(HttpArgumentSource.PARAMETER)]string resourcePath + ) + { + var resourceStream = _templateService.GetResource(resourcePath); + if (resourceStream) + return HttpResponse.OK().Content(resourceStream.Value); + if (resourceStream.Is(out FileNotFoundException e)) + return HttpResponse.NotFound().Content(e.FileName); + + return HttpResponse.InternalServerError(); + } + + [Map(HttpMethod.POST, "/resources/(?.*)$")] + public HttpResponse PostResourceFile( + [HttpArgumentSource(HttpArgumentSource.PARAMETER)]string resourcePath, + [HttpArgumentSource(HttpArgumentSource.CONTENT)]Stream postContent + ) + { + var result = _templateService.StoreResource(resourcePath, postContent); + if (result) + return HttpResponse.NoContent(); + if (result.Is(out FileNotFoundException e)) + return HttpResponse.NotFound().Content(e.FileName); + + return HttpResponse.InternalServerError().Content(e.ToString()); + } + } } \ No newline at end of file diff --git a/ln.templates.service/README.md b/ln.templates.service/README.md new file mode 100644 index 0000000..92e6b38 --- /dev/null +++ b/ln.templates.service/README.md @@ -0,0 +1,8 @@ +# ln.templates.service + +command line arguments: + + -s default: "./storage" + -p default: 8890 + +Please see [api.REST.md](api.REST.md) for list of HTTP REST endpoints. diff --git a/ln.templates.service/TemplateService.cs b/ln.templates.service/TemplateService.cs index af41357..080afd7 100644 --- a/ln.templates.service/TemplateService.cs +++ b/ln.templates.service/TemplateService.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using Jint.Native.Object; +using ln.bootstrap; using ln.patterns; using ln.templates.service.render; @@ -19,6 +20,7 @@ namespace ln.templates.service Initialize(); Resolver = new RecursiveResolver(Path.Combine(StoragePath, "templates")); + TempFileStream.DefaultPath = Path.Combine(StoragePath, "tmp"); } private void Initialize() @@ -26,7 +28,7 @@ namespace ln.templates.service EnsureDirectory(""); EnsureDirectory("templates"); EnsureDirectory("resources"); - EnsureDirectory("spool"); + EnsureDirectory("tmp"); EnsureDirectory("out"); } @@ -119,6 +121,32 @@ namespace ln.templates.service return templateFileNames.ToArray(); } + + public String[] ListResources() + { + List resourceFileNames = new List(); + Queue subdirs = new Queue(); + string resourcePath = Path.Combine(StoragePath, "resources"); + + subdirs.Enqueue(resourcePath); + while (subdirs.Count > 0) + { + string currentSubDir = subdirs.Dequeue(); + + foreach (var file in Directory.GetFiles(currentSubDir)) + { + resourceFileNames.Add(Path.GetRelativePath(resourcePath, file)); + } + + foreach (var directory in Directory.GetDirectories(currentSubDir)) + { + subdirs.Enqueue(directory); + } + } + + return resourceFileNames.ToArray(); + } + public bool RenderTemplate(string templatePath, ObjectInstance o, out Stream templateStream) => RenderTemplate(templatePath, o).TryGetValue(out templateStream); @@ -182,5 +210,41 @@ namespace ln.templates.service ); } + public Optional GetResource(string resourcePath) + { + string finalPath = Path.GetFullPath(Path.Combine(StoragePath, "resources", resourcePath)); + if (finalPath.StartsWith(StoragePath)) + return new FileStream(finalPath, FileMode.Open, FileAccess.Read); + + return new FileNotFoundException("", resourcePath); + } + + public Optional StoreResource(string resourcePath, Stream resourceStream) + { + string finalPath = Path.GetFullPath(Path.Combine(StoragePath, "resources", resourcePath)); + if (finalPath.StartsWith(StoragePath)) + { + string finalDirectory = Path.GetDirectoryName(finalPath); + if (!Directory.Exists(finalDirectory)) + { + Span finalDirectoryParts = Path.GetRelativePath(StoragePath,finalDirectory).Split(Path.DirectorySeparatorChar); + string currentPath = StoragePath; + for (int n = 0; n < finalDirectoryParts.Length; n++) + { + currentPath = Path.Combine(currentPath, finalDirectoryParts[n]); + if (!Directory.Exists(currentPath)) + Directory.CreateDirectory(currentPath); + } + } + + using (FileStream fs = new FileStream(finalPath, FileMode.Create)) + resourceStream.CopyTo(fs); + + return true; + } + + return new ArgumentOutOfRangeException("path","illegal path to resource file"); + } + } } diff --git a/ln.templates.service/api.REST.md b/ln.templates.service/api.REST.md index 7d851b3..e3d0076 100644 --- a/ln.templates.service/api.REST.md +++ b/ln.templates.service/api.REST.md @@ -22,3 +22,9 @@ Optional JSON object may be posted to be used as globals for this rendering. Renders the template identified by which must end in .html to PDF Optional JSON object may be posted to be used as globals for this rendering. +### GET /resources +Retrieve JSON list of all resource files available + +### GET, POST /resources/ +Retrieve or store resource file within resources path used for providing css etc. + diff --git a/ln.templates.service/ln.templates.service.csproj b/ln.templates.service/ln.templates.service.csproj index 66ff0e5..171b5ca 100644 --- a/ln.templates.service/ln.templates.service.csproj +++ b/ln.templates.service/ln.templates.service.csproj @@ -12,7 +12,7 @@ - +