spsp

Repository for the "Simplified Perl Status Poster" (SPSP).
git clone git://git.samirparikh.com/spsp
Log | Files | Refs | README

spsp.cgi (7974B) - raw


      1 #!/usr/local/bin/perl -T
      2 
      3 # "Simplified Perl Status Poster"
      4 # 
      5 # MIT License
      6 # 
      7 # Copyright (c) 2023 Samir Parikh
      8 # 
      9 # Permission is hereby granted, free of charge, to any person obtaining a copy
     10 # of this software and associated documentation files (the "Software"), to deal
     11 # in the Software without restriction, including without limitation the rights
     12 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     13 # copies of the Software, and to permit persons to whom the Software is
     14 # furnished to do so, subject to the following conditions:
     15 # 
     16 # The above copyright notice and this permission notice shall be included in all
     17 # copies or substantial portions of the Software.
     18 # 
     19 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     24 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     25 # SOFTWARE.
     26 
     27 use warnings;
     28 use strict;
     29 use lib "/home/compiler/perl5/lib/perl5";
     30 use JSON;
     31 use POSIX   qw( strftime );
     32 use Data::Dumper;
     33 use CGI;
     34 use Text::Markdown;
     35 use File::Spec::Functions;
     36 use feature qw( signatures );
     37 no warnings qw( experimental::signatures );
     38 
     39 #   declare constants
     40 ### path to spsp directory
     41 my $SPSP_PATH                   = "/home/compiler/programs/spsp";
     42 
     43 ### file to store json-formatted post history in reverse chronological order
     44 my $POST_DATA_FILENAME          = "$SPSP_PATH/html/post_data";
     45 
     46 ### temporary file used to create updated post_data json file
     47 my $POST_DATA_TEMP_FILENAME     = "$SPSP_PATH/html/post_data_temp.$$";
     48 
     49 ### HTML file for all fo our posts
     50 my $POSTS_HTML_FILENAME         = "$SPSP_PATH/html/posts.html";
     51 my $POSTS_REL_PATH_FILENAME     = "/posts.html";
     52 
     53 ### temporary HTML file we use to update posts.html based on data from post_data
     54 my $POSTS_TEMP_HTML_FILENAME    = "$SPSP_PATH/html/posts_temp.html.$$";
     55 
     56 ### path for new HTML file for our most recent post
     57 my $NEW_POST_HTML_PATH          = "$SPSP_PATH/html/";
     58 
     59 ### length of random ID assigned to each post
     60 my $ID_LENGTH                   = 4;
     61 
     62 ### hash key constants
     63 my $ID                          = "id";
     64 my $TITLE                       = "title";
     65 my $STATUS                      = "status";
     66 my $TIMESTAMP                   = "timestamp";
     67 
     68 ### HTML constants
     69 my $HTML_TITLE                  = "SPSP";
     70 my $APPLICATION                 = "Simple Perl Status Poster";
     71 my $AUTHOR                      = "Samir Parikh";
     72 my $HEADING                     = "Samir's Updates";
     73 
     74 my $cgi                         = CGI->new;
     75 my $markdown_to_html            = Text::Markdown->new;
     76 
     77 sub generate_post_id ( $id_length )
     78 {
     79     my @characters = (0 .. 9, "a" .. "z");
     80     return join '', map $characters[ rand @characters ], 1 .. $id_length;
     81 }
     82 
     83 ### check to see if post_data file exists.  If not, create it
     84 unless ( -e $POST_DATA_FILENAME )
     85 {
     86     open my $post_data_filehandle, '>>', $POST_DATA_FILENAME
     87         or die "Cannot open $POST_DATA_FILENAME for appending: $!\n";
     88     
     89     close $post_data_filehandle or die "Error closing $POST_DATA_FILENAME: $!\n";
     90 }
     91 
     92 ### open post data file for reading
     93 open my $post_data_filehandle, '<', $POST_DATA_FILENAME
     94     or die "Cannot open $POST_DATA_FILENAME for reading: $!\n";
     95 
     96 ### read all current posts into @posts
     97 my $json_posts = JSON->new;
     98 my @posts      = do {
     99                         local $/;
    100                         @{ $json_posts->decode( <$post_data_filehandle> ) };
    101                     };
    102 
    103 ### close post data file
    104 close $post_data_filehandle or die "Cannot close $POST_DATA_FILENAME: $!\n";
    105 
    106 ### assemble the new post into a hash
    107 my $new_post  = {
    108                 $ID         => generate_post_id( $ID_LENGTH ),
    109                 $TITLE      => scalar $cgi->param( $TITLE ), 
    110                 $STATUS     => scalar $cgi->param( $STATUS ),
    111                 $TIMESTAMP  => strftime "%a %d %b %Y %H:%M %Z", localtime,
    112 };
    113 
    114 ### prepend new post to the array of posts
    115 unshift @posts => $new_post;
    116 
    117 # write updated posts to temporary file
    118 ### open temporary file for writing
    119 open my $temp_filehandle, '>', $POST_DATA_TEMP_FILENAME
    120     or die "Cannot open $POST_DATA_TEMP_FILENAME for writing: $!\n";
    121 
    122 my $posts = $json_posts->pretty->encode( \@posts );
    123 print $temp_filehandle $posts;
    124 
    125 ### close the temporary file
    126 close $temp_filehandle or die "Error closing $POST_DATA_TEMP_FILENAME: $!\n";
    127 
    128 ### delete original post data file
    129 unlink $POST_DATA_FILENAME
    130     or die "Cannot delete original $POST_DATA_FILENAME: $!\n";
    131 
    132 ### Rename temporary file to replace original post data file
    133 rename $POST_DATA_TEMP_FILENAME, $POST_DATA_FILENAME
    134     or die "Cannot rename $POST_DATA_TEMP_FILENAME to $POST_DATA_FILENAME: $!\n";
    135 
    136 ### recreate new posts.html file by first opening and creating temporary file
    137 open $temp_filehandle, '>', $POSTS_TEMP_HTML_FILENAME
    138     or die "Cannot open $POSTS_TEMP_HTML_FILENAME for writing: $!\n";
    139 
    140 ### change default output filehandle
    141 select $temp_filehandle;
    142 
    143 print <<"EOF";
    144 <!DOCTYPE html>
    145 <html lang="en">
    146 
    147 <head>
    148     <title>$HTML_TITLE</title>
    149     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
    150     <meta name="viewport" content="width=device-width" >
    151     <meta name="author" content="$AUTHOR" >
    152     <link rel="icon" type="image/png" href="/assets/favicon.png" >
    153     <link href="styles/style.css" rel="stylesheet" type="text/css" >
    154 </head>
    155 
    156 <body>
    157 <h2>$APPLICATION</h2>
    158 <a href="$POSTS_REL_PATH_FILENAME"><h1>$HEADING</h1></a>
    159 <hr>
    160 EOF
    161 
    162 foreach my $post ( @posts )
    163 {
    164     print "<p><strong><a href=\"$post->{ $ID }.html\">$post->{ $TITLE }</a></strong>\n"
    165         unless ( $post->{ $TITLE } eq '' );
    166     my $html = $markdown_to_html->markdown( $post->{ $STATUS } );
    167     print $html, "\n";
    168     print "<p><a href=\"$post->{ $ID }.html\">$post->{ $TIMESTAMP }</a>\n";
    169     print "<hr>\n";
    170 }
    171 
    172 print "</body>\n";
    173 print "</html>\n";
    174 
    175 ### change back to default output filehandle
    176 select STDOUT;
    177 
    178 ### close the temporary file
    179 close $temp_filehandle or die "Error closing $POSTS_TEMP_HTML_FILENAME: $!\n";
    180 
    181 ### delete original posts.html file
    182 unlink $POSTS_HTML_FILENAME
    183     or die "Cannot delete original $POSTS_HTML_FILENAME: $!\n";
    184 
    185 ### rename temporary posts html file to replace original post data file
    186 rename $POSTS_TEMP_HTML_FILENAME, $POSTS_HTML_FILENAME
    187     or die "Cannot rename $POSTS_TEMP_HTML_FILENAME to $POSTS_HTML_FILENAME: $!\n";
    188 
    189 ### open filehandle to create HTML file for new post
    190 my $new_post_html = catfile( $NEW_POST_HTML_PATH, "$new_post->{ $ID }.html" );  
    191 open my $new_post_filehandle, '>', $new_post_html
    192     or die "Cannot open $new_post_html for writing: $!\n";
    193 
    194 ### change default output filehandle
    195 select $new_post_filehandle;
    196 
    197 print <<"EOF";
    198 <!DOCTYPE html>
    199 <html lang="en">
    200 
    201 <head>
    202     <title>$HTML_TITLE</title>
    203     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
    204     <meta name="viewport" content="width=device-width" >
    205     <meta name="author" content="$AUTHOR" >
    206     <link rel="icon" type="image/png" href="/assets/favicon.png" >
    207     <link href="styles/style.css" rel="stylesheet" type="text/css" >
    208 </head>
    209 
    210 <body>
    211 <h2>$APPLICATION</h2>
    212 <a href="$POSTS_REL_PATH_FILENAME"><h1>$HEADING</h1></a>
    213 <hr>
    214 EOF
    215 
    216 print "<p><strong><a href=\"$new_post->{ $ID }.html\">$new_post->{ $TITLE }</a></strong>\n"
    217     unless ( $new_post->{ $TITLE } eq '' );
    218 my $html = $markdown_to_html->markdown( $new_post->{ $STATUS } );
    219 print $html, "\n";
    220 print "<p><a href=\"$new_post->{ $ID }.html\">$new_post->{ $TIMESTAMP }</a>\n";
    221 print "<hr>\n";
    222 
    223 print "</body>\n";
    224 print "</html>\n";
    225 
    226 ### change back to default output filehandle
    227 select STDOUT;
    228 
    229 ### close the temporary file
    230 close $new_post_filehandle or die "Error closing $new_post_html: $!\n";
    231 
    232 print $cgi->redirect( $POSTS_REL_PATH_FILENAME );
    233 
    234 exit 0;