Nginx: Replacing response text, with text from another text/JSON file - json

In the following HTML file served via NGINX:
<html>
<body>Today is {{day}}</body>
</html>
I have the following JSON file:
{
"year": "2015",
"month": "July",
"day": "Thursday"
}
I would like the output to be modified by NGINX to the following:
<html>
<body>Today is Thursday</body>
</html>
I have looked into searching the response text via regex and replacing it, using the module: NGINX using: http://nginx.org/en/docs/http/ngx_http_sub_module.html
The question is, how do I read the JSON file located on the same server as NGINX, and map the replacements?
P.s.: If needed, I can make amends to using plain text file for the mappings, instead of JSON file.

As a reference for other searchers, you can use the SSI module of NGINX for this.
You would need the variables in your NGINX config:
location = /today.html {
ssi on;
set $year '2015';
set $month 'July';
set $day 'Thursday';
root /var/www/default;
}
And in the template file (/var/www/default/today.html):
<html>
<body>Today is <!--# echo var="day" --></body>
</html>
I can make amends to using plain text file for the mappings, instead of JSON file
I don't now if you can do this via JSON, but it should be possible with plain text files. You can include the plain text file in the template (docs):
<html>
<body>
<!--# include file="day.txt" -->
</body>
</html>
Where day.txt should contain
Thursday
You can also include a script that return the current day, so you don't need to update day.txt.

Related

How to remove a file if it is not used by another file

I have to clean the directory and its subdirectories by removing all unused files. (A file is considered unused if it is not linked to in any
of the HTML files or if it is not specified explicitly that this file is in use). A file can be linked in an HTML file by either href or img src.
For example, I have an I.html,1.html,2.html and 1 folder. In I.html file, an href uses 1.html and 1 directory, but 2.html is not used by any other files. So, how can I remove the unused 2.html file?
use strict;
use warnings;
my($path,$regexExpression) = #ARGV;
my $fileNames = "data.txt";
my #abc= ();
if(not defined $path){
die "File directory not given, please try again \n"
}
print "added file ";
if (not defined $regexExpression) {
$regexExpression="*";
print "--Taking default Regular Expression. \n"
}
if (defined $regexExpression) {
print "The regular Expression : $regexExpression \n";
my $directorypathx= `pwd`;
my ($listofFileNames) = findFilesinDir($path);
my ($listofLinks) = readallHrefInaFile();
my ($listofImage) = readImageFile();
print $listofLinks;
}
sub findFilesinDir{
print "inside subroutines ", $path,"\n";
my($pathName) = #_;
my $fileNames =`find '$pathName' -name '$regexExpression' | sort -h -r > $fileNames ` ;
if (-l $fileNames){
return $fileNames;
}
}
sub readallHrefInaFile{
my $getAllLinks = ` grep -Eo "<a .*href=.*>" $path*.html | uniq ` ;
push (#abc,$getAllLinks);
}
sub readImageFile{
print "image files \n";
my $getAllImage = ` grep -Eo "<img .*src=.*>" $path*.html | uniq `;
push (#abc,$getAllImage);
}
print #abc;
I.html
<html>
<head>
<title>Index</title>
</head>
<body>
<h1>Index</h1>
1
<h1>Downloads</h1>
Compressed craters
<hr>
</body>
</html>
1.html
<html>
<head>
<title>1</title>
</head>
<body>
<h1>1</h1>
<img src="images/1-1.gif" />
<img src="images/1-2.gif" />
<hr>
</body>
</html>
The overall approach you show is reasonable, but there is a lot to say about the code itself. The place to do that would be code review and I encourage you to submit your code there as well.
One overall comment I'd make is that there is no reason to reach so often for external tools; your program uses external grep and find and sort and pwd. We can practically always do the whole job with an abundance of tools that Perl provides.
Here is a simple example for what you need, where most of work is done using modules.
The list of files to search for in our HTML is assembled using File::Find::Rule, recursively under $dir. Another option is the core File::Find module.
Even as HTML parsing appears simple in this case, it is much better to use a module for that as well, instead of a regex. The HTML::TreeBuilder is a bit of a standard for what you need here. That module itself uses others, the workhorse being HTML::Element
The following program works with one HTML file ($source_file), for which we need to find files under a given directory ($dir) which are not used in either an href attribute or a src attribute in img tag. These files need be deleted (that line is commented out).
use warnings;
use strict;
use feature 'say';
use File::Find::Rule;
use HTML::TreeBuilder;
my ($dir, $source_file) = #ARGV;
die "Usage: $0 dir-name file-name\n" if not $dir or not $source_file;
my #files = File::Find::Rule->file->in($dir);
#say for #files;
foreach my $file (#files) {
next if $file eq $source_file; # not the file itself!
say "Processing $file...";
my $tree = HTML::TreeBuilder->new_from_file($source_file);
my $esc_file = quotemeta $file;
my #in_href = $tree->look_down( 'href', qr/$esc_file/ );
my #in_img_src = $tree->look_down( _tag => 'img', 'src', qr/$esc_file/ );
if (#in_href == 0 and #in_img_src == 0) {
say "\tthis file is not used in 'href' or 'img-src' in $source_file";
# To delete it uncomment the next line -- after all is fully tested
#unlink $file or warn "Can't unlink $file: $!";
}
}
The statement that actually removes files, using unlink, is of course commented out. Enable that only once you have thoroughly checked the final version of the script, and have made backups.
Notes
Refine what files you are looking for by adding "rules" with File::Find::Rule
I use quotemeta on filenames, which escapes all special characters in them; otherwise something may sneak in that would throw off the regex used by look_down
The code above simply parses twice through each file, assembling the lists of elements found for href attribute and then for src attribute (in img tag). This can be done in one pass, by using sub { } specification for criteria in look_down
The script must be invoked with the directory name and the main HTML file name. Please change that for proper command line parsing, and more sophisticated use, with Getopt::Long
A whole lot more can be fine tuned here, both with searching for files and in parsing HTML; there is a lot of information in modules' documentation, and yet more in many posts around this site.
The code is tested for simple cases; please adjust to your realistic needs.
Here is a full example of usage.
I place this script (script.pl) in a directory with a file I.html and a directory www.
The I.html file:
<!DOCTYPE html>
<html> <head> <title>Test handling of unused files</title> </head>
<body>
Used file from www
<img src="www/images/used.jpg" alt="no_image_really">
</body>
</html>
The directory www has files used.html and another.html, and a subdirectory images with files used.jpg and another.jpg in it, so altogether we have
.
├── script.pl
├── I.html
└── www
├── used.html
├── another.html
└── images
├── used.jpg
└── another.jpg
There is no need for any content in any of files in www for this test. This is only a minimal setup; I've added more files and directories, and tags to I.html, to test.
Then I run script.pl www I.html and get the expected output.

Using the Author field of R Markdown in footer.html

R Markdown allows to add a footer to your html output. The YAML header allows to give an author name using a specific field.
I would like to use this author name in my footer.html file, but cannot figure out how to achieve that.
Here is a minimal example:
fic.rmd:
---
title: "title"
author: "Mister-A"
output:
html_document:
include:
after_body: footer.html
---
content
And in the same folder the footer.html file:
I am - #author-name-field-that-I-don't-konw-how-to-get -
Any help or advice would me much appreciated. Thank you very much.
If you want to be able to use the YAML parameters within sections of the report, you need to alter the base pandoc template. You can find all of them here
The basic structure of making this work is to put the variable surrounded by dollar signs to use the YAML variable in the output document. So for example $author$ is required in this case.
Solution
We can create a copy of the pandoc template for HTML in our local directory using the following command. This is the same file as here.
# Copies the RMkarkdown template to the local directory so we can edit it
file.copy(rmarkdown:::rmarkdown_system_file("rmd/h/default.html"), to = "template.html")
In the template.html, we need to add the pandoc tags. To add a footer, we want to add code to the buttom of the document. This is line 457 in the current template but this may change in future versions, so we want to put it after the include-after tag:
$for(include-after)$
$include-after$
$endfor$
<hr />
<p style="text-align: center;">I am $author$</p>
$if(theme)$
$if(toc_float)$
</div>
</div>
$endif$
Finally, the R Markdown file looks like:
---
title: "title"
author: "Mister-A"
output:
html_document:
template: template5.html
---
This is some text
As a possible extension of this, you may want to check out this post on designing a stylish footer.

Conditionally comment html script statement across mulitple websites

I have several websites each with multiple pages. Each of these pages has multiple scripts in them for various functions. There is a specific script that Im trying to comment out across all the sites.
The script I want to comment out has a target word I can use as a conditional to isolate it from the rest . I would like to use that word to target the script and wrap all of it (approx. 10 lines / including the <script> tags themselves) in a comment.
I have considered using regex, but it seems the multi-line and complex nature of script syntax may put this situation out of reach for a regex solution. Im not versed in regex, so I could be wrong.
Here is a rough idea of what needs to be commented out. What I want to keep are other similar script blocks without the conditional word (in this example "oranges.com"):
<script type='text/javascript'>
window.__wtw_lucky_site_id = 15001;
(function() {
var wa = document.createElement('script'); wa.type = 'text/javascript'; wa.async = true;
wa.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://ww7632') + '.oranges.com/w.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(wa, s);
})();
</script>
I suppose it would also be worth mentioning that I will be accessing and manipulating these files via ssh so preferably the solution would be compatible with that in some fashion.
You could do this with Perl (where the script you want to comment has stuff in it):
$ cat test.xml
<html>
<script>
stuff
</script>
<script>
other things
</script>
<body>
<h1>Hello, world!</h1>
</body>
</html>
$ perl -0pe 's/<script([^>]*>.*?stuff.*?)<\/script>/<!-- script\1<\/script -->/smg' test.xml
<html>
<!-- script>
stuff
</script -->
<script>
other things
</script>
<body>
<h1>Hello, world!</h1>
</body>
</html>
For reference, see here. This is a pretty quick and dirty solution. You could also write a script to essentially parse the XML with any number of libraries, loop over the elements, and modify the XML.
There may be an XSLT method, but I was not able to find one that looked particularly straight-forward.
Try the following perl solution on your files :
perl -0777 -p -e 's/(<script.*?orange.*?<\/script>)/\/\*\1\*\///s' file
The perl will match all multi-line patterns with the following format:
<script ...
...
</script>
It then checks to see if the word orange occurs on any of the lines within the matched pattern. If it does, the back reference \1 replaces the matched pattern with itself, only difference is that /* is added at the start and */ is added at the end. So the output would look like:
/*<script ...
...
</script>*/
Alternatively
You may also use a python script to achieve the same result:
import sys
import re
file = sys.argv[1]
f = open(file, 'r')
a = f.read() #read file into string
change = re.sub('(<script.*?orange.*?<\/script>)', r'/*\1*/', a, flags=re.DOTALL) #flag DOTALL includes newline
print(change)
You can run the script as so:
python script.py file > newfile
cat newfile > file
This overwrites the contents of your file with the desired output.

Razor Markdown based on DTO type not using _Layout.cshtml

I'm using ServiceStack Markdown Razor to render a DTO, but it is not using _Layout.cshtml. I am following the convention wherein the name of the Markdown file is the same as the response type.
My source tree looks like this:
Services/
ExampleService.cs
Transfer/
Example.cs
Views/
Shared/
_Layout.cshtml
Example.md
ExampleService.cs
public class ExampleService : IService
{
public Example Get(ExampleRequest request)
{
return new Example { Greeting = "Hello, MD!" };
}
}
Thus, if I visit .../html/reply/ExampleRequest I see the rendered Markdown which has access to the #Model. But, it does not use the available _Layout.cshtml (even if I move it to the same directory).
Is this supported? If so, how is it configured?
Automatically use the nearest _Layout.cshtml
I can't tell if this is supported any longer. It appears that /Views/Shared/_Layout.shtml is the file to use as your default template. The other option to define a layout/template page is to use the #Layout or #template syntax as you noted above.
#RenderBody() is not supported,
Correct. This is intentional as noted here
Rather then using a magic method like #RenderBody() we treat the output Body of View as just another variable storing the output a in a variable called 'Body'.
At the top of the Markdown file include an #Layout directive.
Also, in the _Layout.cshtml file use <!--#Body--> instead of #RenderBody(). This is shown below and described on the Markdown Features page under the section "Layout/MasterPage Scenarios - The Basics".
Example.md
#Layout Views/Shared/_Layout.cshtml
## #Model.Greeting
It is the year #DateTime.Now.Year
_Layout.cshtml
<!doctype html>
<html lang="en-us">
<head>
<title>Markdown Razor Example</title>
</head>
<body>
<!--#Body-->
</body>
</html>
Editorial
That said, this approach is undesirable because it deviates from the two relevant conventions used in the RazorRockstars example:
Automatically use the nearest _Layout.cshtml
#RenderBody() is not supported, and using #Body causes a startup error when trying to compile _Layout.cshtml early.

How to use HTML in grails messages.properties for mail sending

In grails, I use a GSP template to render an HTML email sent out with the mail plug-in. This works fine, however the GSP template uses a param which is in turn retrieved from my messages.properties file. Now I want to use HTML, e.g. <br/> inside the messages.properties, but it in the mail it appears as text and the tag is not interpreted.
I already tried to use .decodeHTML() on the parameter in the GSP, but it didn't work.
Where do I have to encode / decode or is it possible at all to use HTML tags inside messages.properties?
<%# page contentType="text/html"%>
<html>
<body>
${variableWithHTMLTextFromMessagesProperties}
</body>
</html>
Can you not do the localisation in the GSP using the message tag, similar to the following? Controller -
sendMail {
to "my#email.com"
subject "cheese"
html g.render(template:"myTemplate")
}
And then in your _myTemplate.gsp -
<%# page contentType="text/html" %>
<html><head></head>
<body>
<p>test: <g:message code="a.test"/></p>
</body>
</html>
And then in messages.properties -
a.test=this <br/><br/> is a test
This way works fine for me (Grails 1.3.1, mail 0.9), I get 2 line breaks in the html email received. Any reason you can't do it this way?
Found the solution here. Easiest way is just to use <%=variableWithHTMLTextFromMessagesProperties%> instead of ${variableWithHTMLTextFromMessagesProperties}. This stops the HTML escaping.
I made my own solution with a custom taglib.
def htmlMessage = { attrs, body ->
out << g.message(attrs, body).decodeHTML()
}
Then to define a message, it has to be with escaped html:
my.html.message={0,choice,0#There is no elements|1#There is <strong>1</strong> element|1<There are <strong>{0}</strong> elements}
For html just:
<g:htmlMessage code="my.html.message" args="[qElements]" />
The result is an i18n html generated with number in strong font. Like this:
"There are 9 elements"
From the docs:
<g:encodeAs codec="HTML">
Profile for user ${user.name} is:
<g:render template="/fragments/showprofile"/>
</g:encodeAs>