Utils.pm 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package Trog::Utils;
  2. use strict;
  3. use warnings;
  4. no warnings 'experimental';
  5. use feature qw{signatures state};
  6. use UUID;
  7. use HTTP::Tiny::UNIX();
  8. use Plack::MIME;
  9. use Mojo::File;
  10. use File::LibMagic;
  11. use Ref::Util qw{is_hashref};
  12. use Trog::Log qw{WARN};
  13. use Trog::Config();
  14. =head1 Trog::Utils
  15. Odds and ends which are needed in more than one place and belong to no
  16. particular subsystem.
  17. =head1 FUNCTIONS
  18. =head2 coerce_array(SCALAR|ARRAYREF param) = ARRAYREF
  19. Deal with Params which may or may not be arrays.
  20. Query parameters arrive as a bare scalar when the caller passed one of
  21. something and as an arrayref when they passed several, which means every
  22. consumer would otherwise have to check. Returns an empty arrayref for anything
  23. false, so the result is always safe to dereference.
  24. =cut
  25. sub coerce_array ($param) {
  26. my $p = $param || [];
  27. $p = [$param] if $param && ( ref $param ne 'ARRAY' );
  28. return $p;
  29. }
  30. =head2 strip_and_trunc(STRING s) = STRING
  31. Flatten a chunk of post body into something fit for a meta description or
  32. preview blurb -- tags stripped, truncated to 280 characters.
  33. Returns undef when handed nothing, rather than an empty string.
  34. =cut
  35. sub strip_and_trunc ($s) {
  36. return unless $s;
  37. $s =~ s/<[^>]*>//g;
  38. return substr $s, 0, 280;
  39. }
  40. =head2 uuid() = STRING
  41. A fresh UUID. Thin wrapper around UUID::uuid(), so that callers don't have to
  42. care which of the several UUID modules we ended up using.
  43. =cut
  44. sub uuid {
  45. return UUID::uuid();
  46. }
  47. #Stuff that isn't in upstream finders
  48. my %extra_types = (
  49. '.docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  50. );
  51. =head2 mime_type(STRING file) = STRING
  52. Figure out a file's Content-Type.
  53. Tries the extension first, as that's cheap and right nearly all of the time,
  54. and only falls back to libmagic sniffing the file's contents when the extension
  55. tells us nothing. %extra_types patches in the handful of types the upstream
  56. finders don't know about.
  57. Returns undef if even libmagic can't say.
  58. =cut
  59. sub mime_type ($file) {
  60. # Use libmagic and if that doesn't work try guessing based on extension.
  61. my $mt;
  62. my $mf = Mojo::File->new($file);
  63. my $ext = '.' . $mf->extname();
  64. $mt = Plack::MIME->mime_type($ext) if $ext;
  65. $mt ||= $extra_types{$ext} if exists $extra_types{$ext};
  66. return $mt if $mt;
  67. # If all else fails, time for libmagic
  68. state $magic = File::LibMagic->new;
  69. my $maybe_ct = $magic->info_from_filename($file);
  70. $mt = $maybe_ct->{mime_type} if ( is_hashref($maybe_ct) && $maybe_ct->{mime_type} );
  71. return $mt;
  72. }
  73. 1;