Procházet zdrojové kódy

more admin routes, start of acls

George S. Baugh před 5 roky
rodič
revize
a3abc3908f

+ 2 - 1
lib/Trog/Config.pm

@@ -5,9 +5,10 @@ use warnings;
 
 
 use Config::Simple;
 use Config::Simple;
 
 
+our $home_cfg = "$ENV{HOME}/.tcms/main.cfg";
+
 sub get {
 sub get {
     my $cf;
     my $cf;
-    my $home_cfg = "$ENV{HOME}/.tcms/main.cfg"; #XXX probably should pass this in and sanitize ENV
     $cf = Config::Simple->new($home_cfg) if -f $home_cfg;
     $cf = Config::Simple->new($home_cfg) if -f $home_cfg;
     return $cf if $cf;
     return $cf if $cf;
     $cf = Config::Simple->new('config/default.cfg');
     $cf = Config::Simple->new('config/default.cfg');

+ 72 - 12
lib/Trog/Routes/HTML.pm

@@ -18,13 +18,12 @@ $theme_dir = "themes/".$conf->param('general.theme') if $conf->param('general.th
 
 
 use lib 'www';
 use lib 'www';
 
 
-# TODO Things which should be themable
-our $landing_page = 'default.tx';
+our $landing_page  = 'default.tx';
 our $htmltitle     = 'title.tx';
 our $htmltitle     = 'title.tx';
 our $midtitle      = 'midtitle.tx';
 our $midtitle      = 'midtitle.tx';
-our $rightbar     = 'rightbar.tx';
-our $leftbar      = 'leftbar.tx';
-our $footbar      = 'footbar.tx';
+our $rightbar      = 'rightbar.tx';
+our $leftbar       = 'leftbar.tx';
+our $footbar       = 'footbar.tx';
 
 
 our %routes = (
 our %routes = (
     default => {
     default => {
@@ -159,27 +158,50 @@ sub index ($query, $input, $render_cb, $content = '', $i_styles = []) {
 
 
 These are things that issue returns other than 200, and are not directly accessible by users via any defined route.
 These are things that issue returns other than 200, and are not directly accessible by users via any defined route.
 
 
+=head2 notfound, forbidden, badrequest
+
+Implements the 4XX status codes.  Override templates named the same for theming this.
+
 =cut
 =cut
 
 
-sub notfound ($query,$input,$render_cb) {
-    $query->{code} = 404;
+sub _generic_route ($rname, $code, $title, $query,$input,$render_cb) {
+    $query->{code} = $code;
 
 
     my $processor = Text::Xslate->new(
     my $processor = Text::Xslate->new(
-        path   => _dir_for_resource('notfound.tx'),
+        path   => _dir_for_resource("$rname.tx"),
     );
     );
 
 
-    my $styles = _build_themed_styles('notfound.css');
-    my $content = $processor->render('notfound.tx', {
-        title    => "Return to Sender, Address unknown",
+    my $styles = _build_themed_styles("$rname.css");
+    my $content = $processor->render("$rname.tx", {
+        title    => $title,
         route    => $query->{route},
         route    => $query->{route},
+        styles   => $styles,
     });
     });
     return Trog::Routes::HTML::index($query, $input, $render_cb, $content, $styles);
     return Trog::Routes::HTML::index($query, $input, $render_cb, $content, $styles);
 }
 }
 
 
+sub notfound (@args) {
+    return _generic_route('notfound',404,"Return to sender, Address unknown", @args);
+}
+
+sub forbidden (@args) {
+    return _generic_route('forbidden', 403, "STAY OUT YOU RED MENACE", @args);
+}
+
+sub badrequest (@args) {
+    return _generic_route('badrequest', 400, "Bad Request", @args);
+}
+
+# TODO Rate limiting route
+
 =head1 NORMAL ROUTES
 =head1 NORMAL ROUTES
 
 
 These are expected to either return a 200, or redirect to something which does.
 These are expected to either return a 200, or redirect to something which does.
 
 
+=head2 setup
+
+One time setup page; should only display to the first user to visit the site which we presume to be the administrator.
+
 =cut
 =cut
 
 
 sub setup ($query, $input, $render_cb) {
 sub setup ($query, $input, $render_cb) {
@@ -190,6 +212,12 @@ sub setup ($query, $input, $render_cb) {
     });
     });
 }
 }
 
 
+=head2 login
+
+Sets the user cookie if the provided user exists, or sets up the user as an admin with the provided credentials in the event that no users exist.
+
+=cut
+
 sub login ($query, $input, $render_cb) {
 sub login ($query, $input, $render_cb) {
 
 
     # Redirect if we actually have a logged in user.
     # Redirect if we actually have a logged in user.
@@ -237,6 +265,12 @@ sub login ($query, $input, $render_cb) {
     }, @headers);
     }, @headers);
 }
 }
 
 
+=head2 config
+
+Renders the configuration page, or redirects you back to the login page.
+
+=cut
+
 sub config ($query, $input, $render_cb) {
 sub config ($query, $input, $render_cb) {
     if (!$query->{user}) {
     if (!$query->{user}) {
         $query->{to} = '/config';
         $query->{to} = '/config';
@@ -286,6 +320,12 @@ sub _get_data_models {
     return \@dmods
     return \@dmods
 }
 }
 
 
+=head2 config_save
+
+Implements /config/save route.  Saves what little configuration we actually use to ~/.tcms/tcms.conf
+
+=cut
+
 sub config_save ($query, $input, $render_cb) {
 sub config_save ($query, $input, $render_cb) {
     my $postdata = _input2postdata($input);
     my $postdata = _input2postdata($input);
     $conf->param( 'general.theme',      $postdata->{theme} )      if defined $postdata->{theme};
     $conf->param( 'general.theme',      $postdata->{theme} )      if defined $postdata->{theme};
@@ -293,7 +333,7 @@ sub config_save ($query, $input, $render_cb) {
 
 
     $query->{failure} = 1;
     $query->{failure} = 1;
     $query->{message} = "Failed to save configuration!";
     $query->{message} = "Failed to save configuration!";
-    if ($conf->save()) {
+    if ($conf->save($Trog::Config::home_config)) {
         $query->{failure} = 0;
         $query->{failure} = 0;
         $query->{message} = "Configuration updated succesfully.";
         $query->{message} = "Configuration updated succesfully.";
     }
     }
@@ -306,6 +346,12 @@ sub profile ($query, $input, $render_cb) {
     return config($query, $input, $render_cb);
     return config($query, $input, $render_cb);
 }
 }
 
 
+=head2 themeclone
+
+Clone a theme by copying a directory.
+
+=cut
+
 sub themeclone ($query, $input, $render_cb) {
 sub themeclone ($query, $input, $render_cb) {
     my $postdata = _input2postdata($input);
     my $postdata = _input2postdata($input);
     my ($theme, $newtheme) = ($postdata->{theme},$postdata->{newtheme});
     my ($theme, $newtheme) = ($postdata->{theme},$postdata->{newtheme});
@@ -322,6 +368,12 @@ sub themeclone ($query, $input, $render_cb) {
     return config($query, $input, $render_cb);
     return config($query, $input, $render_cb);
 }
 }
 
 
+=head2 post
+
+Display the route for making new posts.
+
+=cut
+
 sub post ($query, $input, $render_cb) {
 sub post ($query, $input, $render_cb) {
     if (!$query->{user}) {
     if (!$query->{user}) {
         $query->{to} = '/config';
         $query->{to} = '/config';
@@ -336,6 +388,7 @@ sub post ($query, $input, $render_cb) {
 
 
     return $render_cb->('post.tx', {
     return $render_cb->('post.tx', {
         title       => 'New Post',
         title       => 'New Post',
+        post_visibilities => ['public', 'private', 'unlisted'],
         stylesheets => $css,
         stylesheets => $css,
         scripts     => $js,
         scripts     => $js,
         posts       => $posts,
         posts       => $posts,
@@ -350,10 +403,17 @@ sub post ($query, $input, $render_cb) {
     });
     });
 }
 }
 
 
+#TODO actually do stuff
 sub post_save ($query, $input, $render_cb) {
 sub post_save ($query, $input, $render_cb) {
     return post($query, $input, $render_cb);
     return post($query, $input, $render_cb);
 }
 }
 
 
+=head2 posts
+
+Display multi or single posts, supports RSS and pagination.
+
+=cut
+
 sub posts ($query, $input, $render_cb) {
 sub posts ($query, $input, $render_cb) {
     my $tags = _coerce_array($query->{tag});
     my $tags = _coerce_array($query->{tag});
     my $posts = _post_helper($query, $tags);
     my $posts = _post_helper($query, $tags);

+ 2 - 2
www/server.psgi

@@ -78,7 +78,7 @@ my $app = sub {
 
 
     #Disallow any paths that are naughty ( starman auto-removes .. up-traversal)
     #Disallow any paths that are naughty ( starman auto-removes .. up-traversal)
     if (index($path,'/templates') == 0 || $path =~ m/.*\.psgi$/i ) {
     if (index($path,'/templates') == 0 || $path =~ m/.*\.psgi$/i ) {
-        return [ 403, [$content_types{plain}], ["STAY OUT YOU RED MENACE"]];
+        return Trog::Routes::HTML::forbidden($query,$env->{'psgi.input'}, \&_render);
     }
     }
 
 
     # If it's just a file, serve it up
     # If it's just a file, serve it up
@@ -102,7 +102,7 @@ my $app = sub {
 
 
     #TODO reject inappropriate content-lengths
     #TODO reject inappropriate content-lengths
     return Trog::Routes::HTML::notfound($query,$env->{'psgi.input'}, \&_render) unless exists $routes{$path};
     return Trog::Routes::HTML::notfound($query,$env->{'psgi.input'}, \&_render) unless exists $routes{$path};
-    return [ 400, [$content_types{plain}], ["BAD REQUEST"]] unless $routes{$path}{method} eq $env->{REQUEST_METHOD};
+    return Trog::Routes::HTML::badrequest($query,$env->{'psgi.input'}, \&_render) unless $routes{$path}{method} eq $env->{REQUEST_METHOD};
 
 
     @{$query}{keys(%{$routes{$path}{'data'}})} = values(%{$routes{$path}{'data'}}) if ref $routes{$path}{'data'} eq 'HASH' && %{$routes{$path}{'data'}};
     @{$query}{keys(%{$routes{$path}{'data'}})} = values(%{$routes{$path}{'data'}}) if ref $routes{$path}{'data'} eq 'HASH' && %{$routes{$path}{'data'}};
 
 

+ 3 - 0
www/templates/badrequest.tx

@@ -0,0 +1,3 @@
+400 Bad Request
+<br /><br />
+See the SiteMap <a href="/sitemap">here</a> as to the valid ways to communicate with this website.

+ 6 - 0
www/templates/blog.tx

@@ -1,5 +1,11 @@
 <form class="Submissions" action="/post/save" method="POST">
 <form class="Submissions" action="/post/save" method="POST">
     Title *<br /><input class="cooltext" type="text" name="title" placeholder="Iowa Man Destroys Moon" />
     Title *<br /><input class="cooltext" type="text" name="title" placeholder="Iowa Man Destroys Moon" />
+    Visibility<br />
+    <select class="cooltext" name="visibility">
+        : for $post_visibilities -> $visibility {
+            <option value="<: $visibility :>"><: $visibility :></option>
+        : }
+    </select>
     Content<br /><textarea class="cooltext" name="comment" placeholder="Potzrebie"></textarea>
     Content<br /><textarea class="cooltext" name="comment" placeholder="Potzrebie"></textarea>
     <input type="hidden" name="app" value="blog" />
     <input type="hidden" name="app" value="blog" />
     <input class="coolbutton" type="submit" value="Publish" text="Publish" />
     <input class="coolbutton" type="submit" value="Publish" text="Publish" />

+ 6 - 0
www/templates/file.tx

@@ -3,6 +3,12 @@
     File *<br /><input class="cooltext" type="file" name="file" />
     File *<br /><input class="cooltext" type="file" name="file" />
     <br /> TODO: Add "alternative" links, which scrape the appropriate icon for the alt link from the favicon<br />
     <br /> TODO: Add "alternative" links, which scrape the appropriate icon for the alt link from the favicon<br />
     Preview Image<br /><input type="file" class="cooltext" name="preview" placeholder="PROMO.JPG"></input>
     Preview Image<br /><input type="file" class="cooltext" name="preview" placeholder="PROMO.JPG"></input>
+    Visibility<br />
+    <select class="cooltext" name="visibility">
+        : for $post_visibilities -> $visibility {
+            <option value="<: $visibility :>"><: $visibility :></option>
+        : }
+    </select>
     Comments<br /><textarea class="cooltext" name="comment" placeholder="Potzrebie"></textarea>
     Comments<br /><textarea class="cooltext" name="comment" placeholder="Potzrebie"></textarea>
     <input type="hidden" name="app" value="file" />
     <input type="hidden" name="app" value="file" />
     <input class="coolbutton" type="submit" value="Publish" text="Publish" />
     <input class="coolbutton" type="submit" value="Publish" text="Publish" />

+ 3 - 0
www/templates/forbidden.tx

@@ -0,0 +1,3 @@
+403 Forbidden
+<br /><br />
+Log in <a href="/login?to=<: $route :>">here</a>.

+ 6 - 0
www/templates/microblog.tx

@@ -4,6 +4,12 @@
     Image<br /><input class="cooltext" type="text" name="IMG" placeholder="https://gifdump.tld/Advice_Dog.jpg" />
     Image<br /><input class="cooltext" type="text" name="IMG" placeholder="https://gifdump.tld/Advice_Dog.jpg" />
     Audio<br /><input class="cooltext" type="text" name="AUD" placeholder="https://soundclod.com/static.mp3"/>
     Audio<br /><input class="cooltext" type="text" name="AUD" placeholder="https://soundclod.com/static.mp3"/>
     Video<br /><input class="cooltext" type="text" name="VID" placeholder="https://youvimeo.tv/infomercial.mp4" />
     Video<br /><input class="cooltext" type="text" name="VID" placeholder="https://youvimeo.tv/infomercial.mp4" />
+    Visibility<br />
+    <select class="cooltext" name="visibility">
+        : for $post_visibilities -> $visibility {
+            <option value="<: $visibility :>"><: $visibility :></option>
+        : }
+    </select>
     Comments<br /><textarea class="cooltext" name="comment" placeholder="Potzrebie"></textarea>
     Comments<br /><textarea class="cooltext" name="comment" placeholder="Potzrebie"></textarea>
     <input type="hidden" name="app" value="microblog" />
     <input type="hidden" name="app" value="microblog" />
     <input class="coolbutton" type="submit" value="Publish" text="Publish" />
     <input class="coolbutton" type="submit" value="Publish" text="Publish" />