diff --git a/.idea/templateLanguages.xml b/.idea/templateLanguages.xml
new file mode 100644
index 0000000..7302b77
--- /dev/null
+++ b/.idea/templateLanguages.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Makefile.PL b/Makefile.PL
index 9260e20..7f281c2 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -6,9 +6,10 @@ use ExtUtils::MakeMaker;
WriteMakefile(
VERSION => '0.01',
PREREQ_PM => {
- 'Mojolicious' => '9.27',
- 'Email::MIME' => '1.952',
- 'Email::Sender::Simple' => '2.500'
+ 'Mojolicious' => '9.27',
+ 'Email::MIME' => '1.952',
+ 'Email::Sender::Simple' => '2.500',
+ 'File::ChangeNotify' => '0.31',
},
test => {TESTS => 't/*.t'}
);
diff --git a/lib/unix_dog.pm b/lib/unix_dog.pm
index 2e621fd..975d396 100644
--- a/lib/unix_dog.pm
+++ b/lib/unix_dog.pm
@@ -32,6 +32,10 @@ sub startup ($self) {
$r->post('/account')->to('Account#update_account');
$r->get('/users')->to('Main#user_pages');
+
+ $r->get('/announcements')->to('Main#announcements');
+ $r->get('/announcements.rss')->to('Main#announcement_feed');
+ $r->get('/announcement/#filename')->to('Main#get_announcement');
}
1;
diff --git a/lib/unix_dog/Controller/Main.pm b/lib/unix_dog/Controller/Main.pm
index c87a95c..5a1dee8 100644
--- a/lib/unix_dog/Controller/Main.pm
+++ b/lib/unix_dog/Controller/Main.pm
@@ -5,6 +5,11 @@ use experimental 'signatures';
use Mojo::Base 'Mojolicious::Controller', -signatures;
use Net::LDAPS;
+use File::ChangeNotify;
+use File::stat;
+use File::Basename;
+use Time::Piece;
+use Scalar::Util qw(looks_like_number);
sub index ($self) {
$self->render();
@@ -25,6 +30,9 @@ Mojo::IOLoop->recurring(60 => sub {
$cache->set(users => []);
});
+my $acache = Mojo::Cache->new(max_keys => 1);
+my $filewatcher;
+
sub user_pages ($self) {
my $config = $self->config;
my $connStr = $config->{'ldap'}->{'uri'};
@@ -60,4 +68,166 @@ sub user_pages ($self) {
});
}
+
+sub announcements ($self) {
+ if (!defined $acache->get('announcements')) {
+ setup_filewatch($self->config->{'announce'}->{'path'});
+ } else {
+ check_files();
+ }
+
+ my %announcements = %{$acache->get('announcements')};
+ my $page = $self->param('page');
+ if (!defined $page) {
+ $page = 0;
+ }
+
+ if (!looks_like_number($page) || $page < 0) {
+ return $self->reply->not_found;
+ }
+
+
+ my $total_items = scalar(keys %announcements);
+ my $items_per_page = 5;
+
+ my $start_index = $page * $items_per_page;
+ my $end_index = $start_index + $items_per_page-1;
+
+ if ($start_index >= $total_items) {
+ return $self->reply->not_found;
+ }
+
+ my $next_page = -1;
+ if ($end_index >= $total_items) {
+ $end_index = $total_items-1;
+ } elsif ($end_index != $total_items-1){
+ $next_page = $page + 1;
+ }
+
+
+
+ $self->stash(
+ announcements => \%announcements,
+ total_items => $total_items,
+ items_per_page => $items_per_page,
+ page => $page,
+ start_index => $start_index,
+ end_index => $end_index,
+ next_page => $next_page,
+ );
+ $self->render();
+}
+
+sub get_announcement ($self) {
+ if (!defined $acache->get('announcements')) {
+ setup_filewatch($self->config->{'announce'}->{'path'});
+ } else {
+ check_files();
+ }
+
+ my $announcements = $acache->get('announcements');
+ my $filename = $self->param('filename');
+ if (!defined $announcements->{$filename}) {
+ return $self->reply->not_found;
+ }
+ my $entry = $announcements->{$filename};
+ $self->render(text => $entry->{'raw'}, format => 'txt');
+}
+
+sub announcement_feed ($self) {
+ if (!defined $acache->get('announcements')) {
+ setup_filewatch($self->config->{'announce'}->{'path'});
+ } else {
+ check_files();
+ }
+
+ my $announcements = $acache->get('announcements');
+ my @chosen = sort (keys %$announcements);
+
+ if (scalar(@chosen) > 5) {
+ @chosen = @chosen[0..4];
+ }
+
+ my @elements;
+
+ for my $key (@chosen) {
+ push @elements, $announcements->{$key};
+ }
+
+ $self->stash(items => \@elements);
+ $self->render('main/announcements', format => 'rss');
+}
+
+sub setup_filewatch($path) {
+ opendir my $dir, $path or die "Could not open directory!";
+ my @files = readdir $dir;
+ closedir $dir;
+
+ my %announcements;
+
+ for my $filename (@files) {
+ if ($filename eq "." || $filename eq "..") {
+ next;
+ }
+
+ my $entry = get_entry($path.$filename);
+ if (!defined $entry) {
+ say "Invalid entry at $filename";
+ next;
+ }
+
+ $announcements{$filename} = $entry;
+ }
+ $acache->set(announcements => \%announcements);
+
+ $filewatcher = File::ChangeNotify->instantiate_watcher(
+ directories => [$path],
+ );
+}
+
+sub check_files {
+ for my $event ($filewatcher->new_events) {
+ if ($event->path =~ /\.txt$/) {
+ my $filename = basename($event->path);
+ if ($event->type eq 'create' || $event->type eq 'modify') {
+ my $entry = get_entry($event->path);
+ if (!defined $entry) {
+ say "Invalid entry at $filename";
+ delete $acache->get('announcements')->{$filename};
+ next;
+ }
+ $acache->get('announcements')->{$filename} = get_entry($event->path);
+ } elsif ($event->type eq 'delete') {
+ delete $acache->get('announcements')->{$filename};
+ }
+ }
+ }
+}
+
+sub get_entry($fullpath) {
+ open FH, '<', $fullpath or die "Could not open file! $!";
+ read FH, my $announce_content, -s FH;
+ close FH;
+ my $filestat = stat($fullpath);
+ my $announce_text;
+ my $announce_title;
+ if ($announce_content =~ /-----BEGIN PGP SIGNED MESSAGE-----\nHash: \w+\n\n(.+?)\n\n(.*)\n-----BEGIN PGP SIGNATURE-----/s) {
+ $announce_title = $1;
+ $announce_text = $2;
+ }
+
+ if (!defined $announce_title || !defined $announce_content || length $announce_title == 0 || length $announce_content == 0) {
+ return undef;
+ }
+
+
+ return {
+ raw => $announce_content,
+ text => $announce_text,
+ date => $filestat->mtime,
+ filename => basename($fullpath),
+ title => $announce_title,
+ };
+}
+
1;
diff --git a/public/css/main.css b/public/css/main.css
index 0cd9af1..437b9c4 100644
--- a/public/css/main.css
+++ b/public/css/main.css
@@ -140,6 +140,10 @@ textarea {
padding: 10px;
}
+pre {
+ white-space: pre-wrap;
+}
+
#header-content a:link {
text-decoration: none;
color: black;
diff --git a/templates/layouts/default.html.ep b/templates/layouts/default.html.ep
index 2c27912..c4ce056 100644
--- a/templates/layouts/default.html.ep
+++ b/templates/layouts/default.html.ep
@@ -3,8 +3,9 @@
<%= title %>
-
-
+
+
+
@@ -19,11 +20,12 @@