Ver código fonte

add post aliases

George S. Baugh 4 anos atrás
pai
commit
a9fead032c

+ 47 - 14
bin/migrate2.pl

@@ -1,9 +1,13 @@
+#!/usr/bin/perl
+
 use strict;
 use warnings;
 
 # Migrate early on tcms3 flatfile sites to 'all posts are series code' (august 2021) code
 
-use lib '../lib';
+use FindBin;
+
+use lib "$FindBin::Bin/../lib";
 
 use Trog::Config;
 use Trog::Data;
@@ -13,6 +17,9 @@ use UUID::Tiny;
 use Trog::SQLite;
 use Trog::SQLite::TagIndex;
 
+# Kill the post index
+unlink "$FindBin::Bin/../data/posts.db";
+
 sub uuid { return UUID::Tiny::create_uuid_as_string(UUID::Tiny::UUID_V1, UUID::Tiny::UUID_NS_DNS); }
 
 # Modify these variables to suit your installation.
@@ -21,6 +28,7 @@ my @extra_series = (
      {
             "aclname"    => "blog",
             "acls"       => [],
+            aliases      => [],
             "callback"   => "Trog::Routes::HTML::series",
             method       => 'GET',
             "data"       => "Blog",
@@ -37,6 +45,7 @@ my @extra_series = (
         {
             "aclname"    => "video",
             "acls"       => [],
+            aliases      => [],
             "callback"   => "Trog::Routes::HTML::series",
             method       => 'GET',
             "data"       => "Videos",
@@ -53,6 +62,7 @@ my @extra_series = (
         {
             "aclname"    => "files",
             "acls"       => [],
+            aliases      => [],
             "callback"   => "Trog::Routes::HTML::series",
             method       => 'GET',
             "data"       => "Downloads",
@@ -71,9 +81,6 @@ my @extra_series = (
 my $conf = Trog::Config::get();
 my $search_info = Trog::Data->new($conf);
 
-# Kill the post index
-unlink "../data/posts.db";
-
 my @all = $search_info->get( raw => 1, limit => 0 );
 
 my %posts;
@@ -84,23 +91,46 @@ foreach my $post (@all) {
 }
 
 foreach my $timestamp (keys(%posts)) {
-    my $file_to_kill = "../data/files/$timestamp";
+    my $file_to_kill = "$FindBin::Bin/../data/files/$timestamp";
     my $new_id = uuid();
     # Preserve old URLs
     foreach my $post (@{$posts{$timestamp}}) {
+        delete $post->{app};
+        delete $post->{preview_file};
+        delete $post->{wallpaper_file};
+
+        delete $post->{scheme};
+        delete $post->{route};
+        delete $post->{domain};
+
         $post->{id}         = $new_id;
-        $post->{local_href} = "/posts/$timestamp";
-        $post->{callback}   = "Trog::Routes::HTML::series";
+        $post->{local_href} = "/posts/$new_id";
+        $post->{aliases}    = ["/posts/$timestamp"];
+        $post->{callback}   = "Trog::Routes::HTML::posts";
         $post->{method}     = 'GET';
-        @{$post->{tags}} = grep { defined $_ } @{$post->{tags}};
+        @{$post->{tags}}    = grep { defined $_ } @{$post->{tags}};
 
         $post->{content_type} //= 'text/html';
-        $post->{form}       = 'microblog.tx';
-        $post->{form}       = 'blog.tx' if grep {$_ eq 'blog' } @{$post->{tags}};
-        $post->{form}       = 'file.tx' if $post->{content_type} =~ m/^video\//;
-        $post->{form}       = 'file.tx' if $post->{content_type} =~ m/^audio\//;
-        $post->{form}       = 'file.tx' if $post->{content_type} =~ m/^image\//;
-        $post->{form}       = 'profile.tx' if grep {$_ eq 'about' } @{$post->{tags}};
+        $post->{form}         = 'microblog.tx';
+        $post->{form}         = 'blog.tx' if grep {$_ eq 'blog' } @{$post->{tags}};
+        $post->{form}         = 'file.tx' if $post->{content_type} =~ m/^video\//;
+        $post->{form}         = 'file.tx' if $post->{content_type} =~ m/^audio\//;
+        $post->{form}         = 'file.tx' if $post->{content_type} =~ m/^image\//;
+        if (grep {$_ eq 'about' } @{$post->{tags}}) {
+            $post->{form}       = 'profile.tx';
+            $post->{local_href} = "/users/$post->{user}";
+            $post->{callback}   = "Trog::Routes::HTML::users";
+        }
+        if (grep {$_ eq 'series' } @{$post->{tags}}) {
+            $post->{form}       = 'series.tx';
+            $post->{callback}   = "Trog::Routes::HTML::series";
+            $post->{child_form} = 'microblog.tx';
+            $post->{child_form} = 'blog.tx' if $post->{title} =~ m/^blog/i;
+            $post->{child_form} = 'file.tx' if $post->{title} =~ m/^video\//;
+            $post->{child_form} = 'file.tx' if $post->{title} =~ m/^audio\//;
+            $post->{child_form} = 'file.tx' if $post->{title} =~ m/^image\//;
+        }
+
         $search_info->write([$post]);
         unlink $file_to_kill if -f $file_to_kill;
     }
@@ -115,6 +145,7 @@ my $series = [
         {
             "aclname"    => "series",
             "acls"       => [],
+            aliases      => [],
             "callback"   => "Trog::Routes::HTML::series",
             method       => 'GET',
             "data"       => "Series",
@@ -131,6 +162,7 @@ my $series = [
         {
             "aclname"    => "about",
             "acls"       => [],
+            aliases      => [],
             "callback"   => "Trog::Routes::HTML::series",
             method       => 'GET',
             "data"       => "About",
@@ -147,6 +179,7 @@ my $series = [
         {
             "aclname"      => "admin",
             acls           => [],
+            aliases        => [],
             "callback"     => "Trog::Routes::HTML::config",
             'method'       => 'GET',
             "content_type" => "text/plain",

+ 9 - 2
lib/TCMS.pm

@@ -41,6 +41,8 @@ my %routes = %Trog::Routes::HTML::routes;
 @routes{keys(%Trog::Routes::JSON::routes)} = values(%Trog::Routes::JSON::routes);
 @routes{keys(%roots)} = values(%roots);
 
+my %aliases = $data->aliases();
+
 #1MB chunks
 my $CHUNK_SIZE = 1024000;
 
@@ -87,6 +89,10 @@ sub app {
     $query = URL::Encode::url_params_mixed($env->{QUERY_STRING}) if $env->{QUERY_STRING};
 
     my $path = $env->{PATH_INFO};
+
+    # Translate alias paths into their actual path
+    $path = $aliases{$path} if exists $aliases{$path};
+
     # Collapse multiple slashes in the path
     $path =~ s/[\/]+/\//g;
 
@@ -158,8 +164,9 @@ sub app {
 
     $query->{user}         = $active_user;
     $query->{domain}       = $env->{HTTP_X_FORWARDED_HOST} || $env->{HTTP_HOST};
-    $query->{route}        = $env->{REQUEST_URI};
-    $query->{route}        =~ s/\?\Q$env->{QUERY_STRING}\E//;
+    $query->{route}        = $path;
+    #$query->{route}        = $env->{REQUEST_URI};
+    #$query->{route}        =~ s/\?\Q$env->{QUERY_STRING}\E//;
     $query->{scheme}       = $env->{'psgi.url_scheme'} // 'http';
     $query->{social_meta}  = 1;
     $query->{primary_post} = {};

+ 4 - 0
lib/Trog/Data/FlatFile.pm

@@ -86,6 +86,10 @@ sub routes ($self) {
     return Trog::SQLite::TagIndex::routes();
 }
 
+sub aliases ($self) {
+    return Trog::SQLite::TagIndex::aliases();
+}
+
 sub write($self,$data) {
     foreach my $post (@$data) {
         my $file = "$datastore/$post->{id}";

+ 18 - 2
lib/Trog/DataModule.pm

@@ -104,7 +104,7 @@ sub _fixup ($self, @filtered) {
         my $is_user_page = grep { $_ eq 'about' } @{$subj->{tags}};
         if (!exists $subj->{local_href}) {
             $subj->{local_href} = "/posts/$subj->{id}";
-            $subj->{local_href} = "/users/$subj->{title}" if $is_user_page;
+            $subj->{local_href} = "/users/$subj->{user}" if $is_user_page;
         }
         if (!exists $subj->{callback}) {
             $subj->{callback} = "Trog::Routes::HTML::posts";
@@ -339,7 +339,7 @@ You should override this, it is a stub here.
 
 sub delete ($self) { die 'stub' }
 
-=head2 routes()
+=head2 routes() = HASH
 
 Returns the routes to each post.
 You should override this for performance reasons, as it's just a wrapper around get() by defualt.
@@ -351,4 +351,20 @@ sub routes($self) {
     return %routes;
 }
 
+=head2 aliases() = HASH
+
+Returns the aliases for each post, indexed by aliases.
+You should override this for performance reasons, as it's just a wrapper around get() by defualt.
+
+=cut
+
+sub aliases($self) {
+    my @posts = $self->get( limit => 0, acls => ['admin'] );
+    my %aliases;
+    foreach my $post (@posts) {
+        @aliases{@{$post->{aliases}}} = $post->{local_href};
+    }
+    return %aliases;
+}
+
 1;

+ 2 - 1
lib/Trog/Routes/HTML.pm

@@ -766,11 +766,12 @@ sub users ($query, $render_cb) {
     $query->{exclude_tags} = ['about'];
 
     my @posts = _post_helper({ limit => 10000 }, ['about'], $query->{acls});
-    my @user = grep { $_->{title} eq $query->{username} } @posts;
+    my @user = grep { $_->{user} eq $query->{username} } @posts;
     $query->{id} = $user[0]->{id};
     $query->{title} = $user[0]->{title};
     $query->{user_obj} = $user[0];
     $query->{primary_post} = $posts[0];
+    $query->{in_series} = 1;
     return posts($query,$render_cb);
 }
 

+ 19 - 2
lib/Trog/SQLite/TagIndex.pm

@@ -30,12 +30,21 @@ sub posts_for_tags (@tags) {
 
 sub routes {
     my $dbh = _dbh();
-    my $rows = $dbh->selectall_arrayref("SELECT route, method, callback FROM all_routes",{ Slice => {} });
+    my $rows = $dbh->selectall_arrayref("SELECT id, route, method, callback FROM all_routes",{ Slice => {} });
     return () unless ref $rows eq 'ARRAY' && @$rows;
-    my %routes = map { $_->{route} => { method => $_->{method}, callback => $_->{callback} } } @$rows;
+
+    my %routes = map { $_->{route} => $_ } @$rows;
     return %routes;
 }
 
+sub aliases {
+    my $dbh = _dbh();
+    my $rows = $dbh->selectall_arrayref("SELECT actual,alias FROM aliases", { Slice => {} });
+    return () unless ref $rows eq 'ARRAY' && @$rows;
+    my %aliases = map { $_->{alias} => $_->{actual} } @$rows;
+    return %aliases;
+}
+
 sub add_post ($post,$data_obj) {
     my $dbh = _dbh();
     build_routes($data_obj,[$post]);
@@ -83,6 +92,14 @@ sub build_routes($data_obj,$posts=[]) {
 
     my @routes = map { ($_->{local_href}, $_->{method_id}, $_->{callback_id} ) } @$posts;
     Trog::SQLite::bulk_insert($dbh,'routes', [qw{route method_id callback_id}], 'IGNORE', @routes); 
+
+    # Now, compile the post aliases
+    my %routes_actual = routes();
+    foreach my $post (@$posts) {
+        next unless @{$post->{aliases}};
+        my $route = $post->{local_href};
+        Trog::SQLite::bulk_insert($dbh, 'post_aliases', [qw{route_id alias}], 'IGNORE', map { ($routes_actual{$route}{id}, $_) } @{$post->{aliases}} );
+    }
 }
 
 # Ensure the db schema is OK, and give us a handle

+ 9 - 1
schema/flatfile.schema

@@ -16,6 +16,7 @@ CREATE VIEW IF NOT EXISTS posts AS SELECT p.post_id AS id, p.post_time AS create
 /* The intention is to read this entirely into memory at app startup     */
 /* This should not incur significant costs, even with millions of posts. */
 CREATE TABLE IF NOT EXISTS routes (
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
     route TEXT NOT NULL UNIQUE,
     method_id TEXT NOT NULL REFERENCES methods(id) ON DELETE RESTRICT,
     callback_id TEXT NOT NULL REFERENCES callbacks(id) ON DELETE RESTRICT
@@ -33,7 +34,14 @@ CREATE TABLE IF NOT EXISTS callbacks (
     callback TEXT NOT NULL UNIQUE
 );
 
-CREATE VIEW IF NOT EXISTS all_routes AS SELECT r.route AS route, m.method AS method, c.callback AS callback FROM routes AS r JOIN methods AS m ON m.id=r.method_id JOIN callbacks AS c ON c.id=r.callback_id;
+CREATE VIEW IF NOT EXISTS all_routes AS SELECT r.id AS id, r.route AS route, m.method AS method, c.callback AS callback FROM routes AS r JOIN methods AS m ON m.id=r.method_id JOIN callbacks AS c ON c.id=r.callback_id;
 
 /* Fill the methods table with the HTTP verbs */
 INSERT OR IGNORE INTO methods (method) VALUES ('GET'),('POST'),('DELETE'),('PUT'),('HEAD'),('PATCH'),('CONNECT'),('OPTIONS'),('TRACE');
+
+CREATE TABLE IF NOT EXISTS post_aliases (
+    route_id INTEGER NOT NULL REFERENCES routes(id) ON DELETE CASCADE,
+    alias TEXT NOT NULL UNIQUE
+);
+
+CREATE VIEW IF NOT EXISTS aliases AS SELECT r.route AS actual, a.alias AS alias FROM routes AS r JOIN post_aliases AS a ON r.id=a.route_id;

+ 2 - 6
www/templates/posts.tx

@@ -50,11 +50,7 @@
     :     next;
     : }
     :if ( $tiled ) {
-        : if ($post.is_profile) {
-        <a href="/users/<: $post.user :>" class="tile">
-        : } else {
-        <a href="<: $route :>/<: $post.id :>" class="tile">
-        : }
+        <a href="<: $post.local_href :>" class="tile">
         : if ($post.is_video) {
             <video preload="none" class="responsive" controls poster="<: $post.preview :>" >
                 <source src="<: $post.href :>" type="<: $post.content_type :>" />
@@ -123,7 +119,7 @@
                 <div style="background-image:url(<: $post.href :>);" class="responsive preview"></div>
             : }
             : if ( $post.is_profile ) {
-                <a href="/users/<: $post.title :>" title="<: $post.title :> poasts">
+                <a href="<: $post.local_href :>" title="<: $post.title :> poasts">
                 <div style="background-image:url(<: $post.wallpaper :>);" class="banner profile">
                     <div style="background-image:url(<: $post.preview :>);" class="circle portrait"></div>
             : }