migrate6.pl 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #!/usr/bin/env perl
  2. # Display names
  3. use v5.36;
  4. use re '/aa';
  5. use FindBin;
  6. use lib "$FindBin::Bin/../lib";
  7. use Trog::SQLite;
  8. =head1 SYNOPSIS
  9. Display names.
  10. Adds the display_name column to the auth database's user table, then walks the
  11. flat file posts and converts profile posts from being titled with the user's
  12. login name to being titled with their display name, moving them from
  13. /users/<login> to /users/<display name> in the process.
  14. =head2 USAGE
  15. bin/migrate6.pl
  16. Run from the tCMS root. Rebuild the post index afterwards, as the profile
  17. posts have changed their local_href and the routes table still points at the
  18. old one -- the script says so when it has actually changed something.
  19. =head2 CAVEATS
  20. Historical, and not idempotent -- SQLite will refuse a second ALTER TABLE for a
  21. column which already exists, so re-running it dies rather than doing nothing.
  22. Post revisions are rewritten in place rather than through the data model, so
  23. take a backup of data/ before running it.
  24. Users with no display name set are skipped, which leaves their profile post
  25. where it was.
  26. =cut
  27. sub _dbh {
  28. my $file = 'schema/auth.schema';
  29. my $dbname = "config/auth.db";
  30. return Trog::SQLite::dbh( $file, $dbname );
  31. }
  32. my $dbh = _dbh();
  33. $dbh->do("ALTER TABLE user ADD COLUMN display_name TEXT DEFAULT NULL;");
  34. # Update all the profile type posts to have correct display names
  35. use Trog::Auth;
  36. use JSON::MaybeXS;
  37. use File::Slurper;
  38. use File::Slurper::Temp;
  39. use URI::Escape;
  40. use Data::Dumper;
  41. my $global_changes;
  42. opendir( my $dh, 'data/files' );
  43. while ( my $entry = readdir $dh ) {
  44. my $fname = "data/files/$entry";
  45. next unless -f $fname;
  46. my $contents = File::Slurper::read_binary($fname);
  47. my $decoded = JSON::MaybeXS::decode_json($contents);
  48. next unless List::Util::any { $_->{is_profile} } @$decoded;
  49. # If the title on the profile post responsds to a username, then let's change that to a display name
  50. my $made_changes;
  51. foreach my $revision (@$decoded) {
  52. my $user = $revision->{title};
  53. my $display_name = Trog::Auth::username2display($user);
  54. next unless $display_name;
  55. print "converting $user to display name $display_name\n";
  56. $revision->{title} = $display_name;
  57. $revision->{local_href} = "/users/$display_name";
  58. $made_changes = 1;
  59. }
  60. next unless $made_changes;
  61. print "Writing changes to $fname\n";
  62. my $encoded = JSON::MaybeXS::encode_json($decoded);
  63. # Temp:: rather than plain File::Slurper -- it writes to a tempfile and
  64. # renames over the target, so a crash partway can't leave a half written
  65. # post behind.
  66. File::Slurper::Temp::write_binary( $fname, $encoded );
  67. # Next, waste and rebuild the posts index for these user posts
  68. $global_changes = 1;
  69. }
  70. print "Changes made. Please rebuild the posts index.\n" if $global_changes;