Bump the changelog for the 0.7.5 release
[email-reminder.git] / EmailReminder / EventList.pm
blobc33b1c1d8521bac423f98d86dfc64266fa2013ee
1 # This file is part of Email-Reminder.
3 # Email-Reminder is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License as
5 # published by the Free Software Foundation; either version 3 of the
6 # License, or (at your option) any later version.
8 # Email-Reminder is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with Email-Reminder; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 # 02110-1301, USA.
18 package EmailReminder::EventList;
20 # Holds all user information and events.
22 # Events are stored in the proper EventStore and they can be accessed
23 # using this class. The main XML parsing and generation happen here.
25 use strict;
26 use warnings;
28 use Email::Valid;
29 use XML::DOM;
31 use EmailReminder::AnniversaryEvent;
32 use EmailReminder::AnniversaryStore;
33 use EmailReminder::BirthdayEvent;
34 use EmailReminder::BirthdayStore;
35 use EmailReminder::MonthlyEvent;
36 use EmailReminder::MonthlyStore;
37 use EmailReminder::Utils;
38 use EmailReminder::WeeklyEvent;
39 use EmailReminder::WeeklyStore;
40 use EmailReminder::YearlyEvent;
41 use EmailReminder::YearlyStore;
43 # XML tags, attributes and values
45 my $EMAIL_TAG = 'email';
46 my $EVENT_TAG = 'event';
47 my $EVENTS_TAG = 'events';
48 my $FIRST_NAME_TAG = 'first_name';
49 my $LAST_NAME_TAG = 'last_name';
50 my $USER_TAG = 'email-reminder_user';
51 my $AUTHOR_WISHES_TAG = 'send_author_wishes';
53 my $TYPE_ATTR = 'type';
55 sub new
57 my ($class, $filename, $create) = @_;
59 my $self = { "NEXT_EVENT_ID" => 0,
60 "LOADED_FILENAME" => $filename,
61 "XML_DOC" => undef,
62 "EVENTS_NODE" => undef,
63 "STORES" => {},
66 bless $self, $class;
68 $self->process_file($create);
70 return $self;
73 sub process_file
75 my ($self, $create, $readonly) = @_;
77 # Make sure the config file exists and is readable
78 my $filename = $self->{LOADED_FILENAME};
79 unless (-e $filename) {
80 if ($create and open my $config_fh, '>:utf8', "$filename") {
81 print $config_fh '<?xml version="1.0"?><email-reminder_user/>';
82 close $config_fh;
84 else {
85 die "File '$filename' does not exist and it is impossible to create it.\n";
88 unless (-r $filename) {
89 die "File '$filename' exists but is not readable.\n";
91 if (!$readonly && !(-w $filename)) {
92 warn "WARNING: File '$filename' is not writable, your changes will be lost!\n";
95 # Start parsing the XML file
96 my $parser = XML::DOM::Parser->new();
97 my $doc;
98 eval {
99 $doc = $parser->parsefile($filename);
101 unless (defined($doc)) {
102 die "File '$filename' is an invalid XML file. Fix it or delete it.\n";
104 $self->{XML_DOC} = $doc;
106 # Read user info
107 my $user = $doc->getElementsByTagName($USER_TAG)->item(0);
108 unless (defined($user)) {
109 die "File '$filename' is an invalid XML file. Fix it or delete it.\n";
111 $self->{USER_NODE} = $user;
113 # Read events
114 my $events = $doc->getElementsByTagName($EVENTS_TAG)->item(0);
115 return unless defined($events);
116 $self->{EVENTS_NODE} = $events;
118 foreach my $event_node ($events->getElementsByTagName($EVENT_TAG)) {
119 my $type = $event_node->getAttribute($TYPE_ATTR);
120 my $event = $self->create_event($type, $event_node);
121 next unless defined($event);
123 # Add to proper EventStore
124 my $store = $self->get_model($type);
125 $store->add_event($event);
127 return 1;
130 sub create_event
132 my ($self, $type, $event_node) = @_;
134 if (!defined($event_node))
136 $event_node = $self->{XML_DOC}->createElement($EVENT_TAG);
137 $event_node->setAttribute($TYPE_ATTR, $type);
139 my $events = $self->{EVENTS_NODE};
140 unless (defined($events))
142 $events = $self->{XML_DOC}->createElement($EVENTS_TAG);
143 $self->{USER_NODE}->appendChild($events);
144 $self->{EVENTS_NODE} = $events;
146 $events->appendChild($event_node);
149 my $event;
150 my $id = $self->{NEXT_EVENT_ID}++;
152 if ($type eq EmailReminder::BirthdayEvent->get_type()) {
153 $event = EmailReminder::BirthdayEvent->new($event_node, $id);
155 elsif ($type eq EmailReminder::AnniversaryEvent->get_type()) {
156 $event = EmailReminder::AnniversaryEvent->new($event_node, $id);
158 elsif ($type eq EmailReminder::MonthlyEvent->get_type()) {
159 $event = EmailReminder::MonthlyEvent->new($event_node, $id);
161 elsif ($type eq EmailReminder::WeeklyEvent->get_type()) {
162 $event = EmailReminder::WeeklyEvent->new($event_node, $id);
164 elsif ($type eq EmailReminder::YearlyEvent->get_type()) {
165 $event = EmailReminder::YearlyEvent->new($event_node, $id);
168 return $event;
171 sub save
173 my $self = shift;
174 my $verbose = shift;
175 my $filename = shift || $self->{LOADED_FILENAME};
177 my $xml_document = $self->{XML_DOC}->toString();
178 print $xml_document if $verbose;
180 # Overwrite the file
181 if (open my $out_fh, '>:utf8', "$filename") {
182 print $out_fh $xml_document;
183 print "Sucessfully wrote reminders to '$filename'\n" if $verbose;
184 close $out_fh;
186 else {
187 print STDERR "Cannot write to file '$filename', your changes have been lost.\n";
190 return 1;
193 sub get_model
195 my ($self, $type) = @_;
197 my $store = $self->{STORES}->{$type};
198 unless (defined($store)) {
199 if ($type eq EmailReminder::AnniversaryEvent->get_type()) {
200 $store = EmailReminder::AnniversaryStore->new();
202 elsif ($type eq EmailReminder::BirthdayEvent->get_type()) {
203 $store = EmailReminder::BirthdayStore->new();
205 elsif ($type eq EmailReminder::MonthlyEvent->get_type()) {
206 $store = EmailReminder::MonthlyStore->new();
208 elsif ($type eq EmailReminder::WeeklyEvent->get_type()) {
209 $store = EmailReminder::WeeklyStore->new();
211 elsif ($type eq EmailReminder::YearlyEvent->get_type()) {
212 $store = EmailReminder::YearlyStore->new();
215 $store->init();
216 $self->{STORES}->{$type} = $store;
219 return $store;
222 sub get_events
224 my $self = shift;
226 my @events = ();
227 foreach my $store (values(%{$self->{STORES}})) {
228 push(@events, @{$store->get_events()});
231 return @events;
234 sub add_event
236 my ($self, $event_type) = @_;
237 my $event = $self->create_event($event_type);
238 return 0 unless defined($event);
240 $event->set_name("<New Event>");
241 $event->set_reminders([0]); # default reminder: same day
243 return $self->{STORES}->{$event_type}->add_event($event);
246 # View/edit user properties
248 sub _get_user_fname {
249 my $self = shift;
250 return EmailReminder::Utils::get_node_value($self->{USER_NODE}, $FIRST_NAME_TAG) || '';
253 sub _get_user_lname {
254 my $self = shift;
255 return EmailReminder::Utils::get_node_value($self->{USER_NODE}, $LAST_NAME_TAG) || '';
258 sub get_user_name
260 my $self = shift;
262 my $fname = $self->_get_user_fname;
263 my $lname = $self->_get_user_lname;
265 if (!$fname && !$lname) {
266 # Get name from UNIX password file
267 my @pwinfo = getpwuid($>);
268 my $fullname = $pwinfo[6];
269 $fullname =~ s/[^0-9A-Za-z_\- ]//g;
270 my @name_parts = split(/ /, $fullname);
272 $fname = $name_parts[0];
273 $lname = $name_parts[-1] if @name_parts > 1;
274 } elsif (!$fname) {
275 $fname = $lname;
276 $lname = '';
279 return ($fname, $lname);
282 sub get_user_email
284 my $self = shift;
285 return EmailReminder::Utils::get_node_value($self->{USER_NODE}, $EMAIL_TAG) || "";
288 sub set_user_fname
290 my ($self, $new_fname) = @_;
291 return EmailReminder::Utils::set_node_value($self->{USER_NODE}, $FIRST_NAME_TAG, $new_fname);
294 sub set_user_lname
296 my ($self, $new_lname) = @_;
297 return EmailReminder::Utils::set_node_value($self->{USER_NODE}, $LAST_NAME_TAG, $new_lname);
300 sub get_author_wishes
302 my $self = shift;
303 return EmailReminder::Utils::get_node_value($self->{USER_NODE}, $AUTHOR_WISHES_TAG);
306 sub set_author_wishes
308 my ($self, $new_author_wishes) = @_;
309 return EmailReminder::Utils::set_node_value($self->{USER_NODE}, $AUTHOR_WISHES_TAG, $new_author_wishes);
312 # Return 0 if the email was ignored (invalid)
313 sub set_user_email
315 my ($self, $new_email) = @_;
316 if (!$new_email || Email::Valid->address($new_email)) {
317 return EmailReminder::Utils::set_node_value($self->{USER_NODE}, $EMAIL_TAG, $new_email);
318 } else {
319 return 0;