Commit | Line | Data |
514dce63 |
1 | package Promulger::List; |
243baf4d |
2 | use Moo; |
2a007b5a |
3 | use autodie; |
514dce63 |
4 | |
f5baca29 |
5 | use autodie ':all'; |
514dce63 |
6 | use Carp; |
f5baca29 |
7 | use Path::Class; |
8 | use Fcntl ':flock'; |
9bfd7b60 |
9 | use Tie::File; |
0456162d |
10 | use File::Slurp qw/read_file write_file/; |
243baf4d |
11 | use Data::Dumper; |
0456162d |
12 | use Try::Tiny; |
1beca6d0 |
13 | use FindBin qw($Bin); |
243baf4d |
14 | $Data::Dumper::Purity = 1; |
514dce63 |
15 | |
21baaef0 |
16 | use Promulger::Config; |
17 | |
514dce63 |
18 | has listname => ( |
19 | is => 'ro', |
243baf4d |
20 | isa => sub { $_[0] =~ /^\w+$/ or die "listname must be a string" }, |
514dce63 |
21 | required => 1, |
22 | ); |
23 | |
24 | has active => ( |
25 | is => 'rw', |
243baf4d |
26 | isa => sub { ($_[0] == 0 || $_[0] == 1) or die "active must be 0 or 1" }, |
514dce63 |
27 | required => 1, |
243baf4d |
28 | default => sub { 1 }, |
514dce63 |
29 | ); |
30 | |
21baaef0 |
31 | has subscribers => ( |
32 | is => 'rw', |
243baf4d |
33 | isa => sub { ref $_[0] eq 'HASH' or die "subscribers must be a hashref" }, |
21baaef0 |
34 | required => 1, |
35 | default => sub { {} }, |
36 | ); |
37 | |
21baaef0 |
38 | sub resolve { |
9bfd7b60 |
39 | my ($self, $proto) = @_; |
21baaef0 |
40 | $proto =~ s/-request$//; |
d16aba7a |
41 | $proto =~ s/^owner-//; |
21baaef0 |
42 | my $path = find_path_for($proto); |
43 | my $maybe_list; |
0456162d |
44 | try { |
21baaef0 |
45 | $maybe_list = __PACKAGE__->load($path->stringify); |
0456162d |
46 | } catch { |
47 | die "oh noes: $_"; |
21baaef0 |
48 | }; |
49 | return $maybe_list; |
50 | } |
f5baca29 |
51 | |
21baaef0 |
52 | sub subscribe { |
9bfd7b60 |
53 | my ($self, $new) = @_; |
8ad89cb2 |
54 | return if $self->subscribers->{$new}; |
55 | $self->subscribers->{$new} = 1; |
56 | $self->store(find_path_for($self->listname)->stringify); |
57 | return 1; |
21baaef0 |
58 | } |
f5baca29 |
59 | |
21baaef0 |
60 | sub unsubscribe { |
9bfd7b60 |
61 | my ($self, $ex) = @_; |
8ad89cb2 |
62 | return unless exists $self->subscribers->{$ex}; |
63 | delete $self->subscribers->{$ex}; |
64 | $self->store(find_path_for($self->listname)->stringify); |
65 | return 1; |
21baaef0 |
66 | } |
f5baca29 |
67 | |
21baaef0 |
68 | # XXX implement ACLs and other shinies -- apeiron, 2010-03-13 |
69 | sub accept_posts_from { |
9bfd7b60 |
70 | my ($self, $sender) = @_; |
8ad89cb2 |
71 | return grep { $sender eq $_ } keys %{$self->subscribers}; |
21baaef0 |
72 | } |
f5baca29 |
73 | |
74 | sub setup { |
9bfd7b60 |
75 | my ($self) = @_; |
21baaef0 |
76 | my $config = Promulger::Config->config; |
514dce63 |
77 | my $name = $self->listname; |
9bfd7b60 |
78 | croak "${name} already a known list" if $self->resolve($name); |
21baaef0 |
79 | my $path = find_path_for($name); |
f5baca29 |
80 | |
7636373d |
81 | my $tie = tie my @aliases, 'Tie::File', $config->{aliases} |
82 | or die "cannot tie " . $config->{aliases} . ": $!"; |
9bfd7b60 |
83 | $tie->flock; |
84 | my @list_aliases = ($name, "${name}-request"); |
21baaef0 |
85 | |
d16aba7a |
86 | # XXX add a flag to determine whether to write the aliases file or no |
87 | # -- apeiron, 2012-07-18 |
9bfd7b60 |
88 | for my $list_alias (@list_aliases) { |
89 | if(grep { /^${list_alias}:/ } @aliases) { |
90 | croak "${list_alias} already in $config->{aliases}"; |
514dce63 |
91 | } |
9bfd7b60 |
92 | push @aliases, |
d16aba7a |
93 | qq(${list_alias}: "|$Bin msg -c $config->{config_file}"\n), |
94 | qq(${list_alias}-owner: "|$Bin msgbounce -c $config->{config_file}"\n); |
514dce63 |
95 | } |
21baaef0 |
96 | |
f5baca29 |
97 | $self->store($path->stringify); |
9bfd7b60 |
98 | } |
99 | |
100 | sub delete { |
101 | my ($self) = @_; |
102 | my $config = Promulger::Config->config; |
103 | my $name = $self->listname; |
104 | |
105 | my $tie = tie my @aliases, 'Tie::File', $config->{aliases}; |
106 | $tie->flock; |
107 | |
108 | my @list_aliases = ($name, "${name}-request"); |
109 | @aliases = grep { |
110 | $_ !~ /^$list_aliases[0]:/ && |
111 | $_ !~ /^$list_aliases[1]:/ |
112 | } @aliases; |
113 | |
8ad89cb2 |
114 | unlink find_path_for($self->listname)->stringify; |
514dce63 |
115 | } |
116 | |
21baaef0 |
117 | sub find_path_for { |
118 | my ($proto) = @_; |
119 | my $path = file(Promulger::Config->config->{list_home}, $proto . ".list"); |
9bfd7b60 |
120 | return $path; |
21baaef0 |
121 | } |
122 | |
243baf4d |
123 | sub store { |
124 | my ($self, $path) = @_; |
125 | my $dumped = 'do { my '. Dumper($self) . '; $VAR1; }'; |
126 | write_file($path, $dumped); |
127 | } |
128 | |
129 | sub load { |
130 | my ($class, $path) = @_; |
131 | return do $path; |
132 | } |
133 | |
0456162d |
134 | sub get_lists { |
135 | my ($self) = @_; |
136 | my $config = Promulger::Config->config; |
137 | my @lists = map { $_->basename} |
138 | grep { -f } dir($config->{list_home})->children; |
139 | s/\.list//g for @lists; |
140 | return @lists; |
141 | } |
142 | |
21baaef0 |
143 | 'http://mitpress.mit.edu/sicp/'; |