aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Somerville <matthew@mysociety.org>2020-06-16 16:25:07 +0100
committerM Somerville <matthew-github@dracos.co.uk>2020-11-11 10:29:20 +0000
commitc0f9b0dcb1fc7cecb4b98ad82715600f73707bf0 (patch)
tree52631c2abc794598fc1b99bc436b7647f103a14a
parent613f45c6514ace275b3a49a5d50f7b83ed536b5f (diff)
[Waste] ICal generation, with Data::ICal.
-rw-r--r--cpanfile2
-rw-r--r--cpanfile.snapshot46
-rw-r--r--perllib/Data/ICal/Entry/Event7986.pm18
-rw-r--r--perllib/Data/ICal/RFC7986.pm17
-rw-r--r--perllib/FixMyStreet/App/Controller/Waste.pm38
-rw-r--r--templates/web/base/waste/bin_days.html2
6 files changed, 122 insertions, 1 deletions
diff --git a/cpanfile b/cpanfile
index 4485314b0..cf7250e21 100644
--- a/cpanfile
+++ b/cpanfile
@@ -136,6 +136,8 @@ feature 'uk', 'FixMyStreet.com specific requirements' => sub {
requires 'SOAP::Lite', '1.20';
# TfL
requires 'Net::Subnet';
+ # Bromley
+ requires 'Data::ICal';
};
feature 'zurich', 'Zueri wie neu specific requirements' => sub {
diff --git a/cpanfile.snapshot b/cpanfile.snapshot
index cdb785a26..92a8535a3 100644
--- a/cpanfile.snapshot
+++ b/cpanfile.snapshot
@@ -947,6 +947,14 @@ DISTRIBUTIONS
perl 5.006
strict 0
warnings 0
+ Class-ReturnValue-0.55
+ pathname: J/JE/JESSE/Class-ReturnValue-0.55.tar.gz
+ provides:
+ Class::ReturnValue 0.55
+ requirements:
+ Devel::StackTrace 0
+ ExtUtils::MakeMaker 0
+ Test::More 0
Class-Singleton-1.4
pathname: A/AB/ABW/Class-Singleton-1.4.tar.gz
provides:
@@ -1723,6 +1731,36 @@ DISTRIBUTIONS
requirements:
ExtUtils::MakeMaker 6.42
perl 5.006
+ Data-ICal-0.24
+ pathname: B/BP/BPS/Data-ICal-0.24.tar.gz
+ provides:
+ Data::ICal 0.24
+ Data::ICal::Entry undef
+ Data::ICal::Entry::Alarm undef
+ Data::ICal::Entry::Alarm::Audio undef
+ Data::ICal::Entry::Alarm::Display undef
+ Data::ICal::Entry::Alarm::Email undef
+ Data::ICal::Entry::Alarm::None undef
+ Data::ICal::Entry::Alarm::Procedure undef
+ Data::ICal::Entry::Alarm::URI undef
+ Data::ICal::Entry::Event undef
+ Data::ICal::Entry::FreeBusy undef
+ Data::ICal::Entry::Journal undef
+ Data::ICal::Entry::TimeZone undef
+ Data::ICal::Entry::TimeZone::Daylight undef
+ Data::ICal::Entry::TimeZone::Standard undef
+ Data::ICal::Entry::Todo undef
+ Data::ICal::Property 0.06
+ requirements:
+ Class::Accessor 0
+ Class::ReturnValue 0
+ ExtUtils::MakeMaker 6.36
+ MIME::QuotedPrint 0
+ Test::LongString 0
+ Test::More 0
+ Test::NoWarnings 0
+ Test::Warn 0
+ Text::vFile::asData 0
Data-OptList-0.110
pathname: R/RJ/RJBS/Data-OptList-0.110.tar.gz
provides:
@@ -7931,6 +7969,14 @@ DISTRIBUTIONS
Text::Unidecode 0.04
requirements:
ExtUtils::MakeMaker 0
+ Text-vFile-asData-0.08
+ pathname: R/RC/RCLAMP/Text-vFile-asData-0.08.tar.gz
+ provides:
+ Text::vFile::asData 0.08
+ requirements:
+ Class::Accessor::Chained 0
+ ExtUtils::MakeMaker 0
+ Test::More 0.88
Throwable-0.200013
pathname: R/RJ/RJBS/Throwable-0.200013.tar.gz
provides:
diff --git a/perllib/Data/ICal/Entry/Event7986.pm b/perllib/Data/ICal/Entry/Event7986.pm
new file mode 100644
index 000000000..ae627861a
--- /dev/null
+++ b/perllib/Data/ICal/Entry/Event7986.pm
@@ -0,0 +1,18 @@
+package Data::ICal::Entry::Event7986;
+
+use parent 'Data::ICal::Entry::Event';
+
+sub optional_unique_properties {
+ return (
+ shift->SUPER::optional_unique_properties,
+ "color",
+ );
+}
+
+sub optional_repeatable_properties {
+ return (
+ shift->SUPER::optional_repeatable_properties,
+ "conference", "image",
+ );
+}
+
diff --git a/perllib/Data/ICal/RFC7986.pm b/perllib/Data/ICal/RFC7986.pm
new file mode 100644
index 000000000..01f9d354e
--- /dev/null
+++ b/perllib/Data/ICal/RFC7986.pm
@@ -0,0 +1,17 @@
+package Data::ICal::RFC7986;
+
+use parent 'Data::ICal';
+
+sub optional_unique_properties {
+ qw( calscale method
+ uid last-modified url refresh-interval source color
+ );
+}
+
+# name/description are only repeatable to provide
+# translations with language param
+sub optional_repeatable_properties {
+ qw( name description categories image );
+}
+
+1;
diff --git a/perllib/FixMyStreet/App/Controller/Waste.pm b/perllib/FixMyStreet/App/Controller/Waste.pm
index a31c359f1..e606b1d8c 100644
--- a/perllib/FixMyStreet/App/Controller/Waste.pm
+++ b/perllib/FixMyStreet/App/Controller/Waste.pm
@@ -92,6 +92,44 @@ sub bin_days : Chained('uprn') : PathPart('') : Args(0) {
my ($self, $c) = @_;
}
+sub calendar : Chained('uprn') : PathPart('calendar.ics') : Args(0) {
+ my ($self, $c) = @_;
+ $c->res->header(Content_Type => 'text/calendar');
+ require Data::ICal::RFC7986;
+ require Data::ICal::Entry::Event;
+ my $calendar = Data::ICal::RFC7986->new(
+ calname => 'Bin calendar',
+ rfc_strict => 1,
+ auto_uid => 1,
+ );
+ $calendar->add_properties(
+ prodid => '//FixMyStreet//Bin Collection Calendars//EN',
+ method => 'PUBLISH',
+ 'refresh-interval' => [ 'P1D', { value => 'DURATION' } ],
+ 'x-published-ttl' => 'P1D',
+ calscale => 'GREGORIAN',
+ 'x-wr-timezone' => 'Europe/London',
+ source => [ $c->uri_for_action($c->action, [ $c->stash->{uprn} ]), { value => 'URI' } ],
+ url => $c->uri_for_action('waste/bin_days', [ $c->stash->{uprn} ]),
+ );
+
+ my $events = $c->cobrand->bin_future_collections;
+ my $stamp = DateTime->now->strftime('%Y%m%dT%H%M%SZ');
+ foreach (@$events) {
+ my $event = Data::ICal::Entry::Event->new;
+ $event->add_properties(
+ summary => $_->{summary},
+ description => $_->{desc},
+ dtstamp => $stamp,
+ dtstart => [ $_->{date}->ymd(''), { value => 'DATE' } ],
+ dtend => [ $_->{date}->add(days=>1)->ymd(''), { value => 'DATE' } ],
+ );
+ $calendar->add_entry($event);
+ }
+
+ $c->res->body($calendar->as_string);
+}
+
sub construct_bin_request_form {
my $c = shift;
diff --git a/templates/web/base/waste/bin_days.html b/templates/web/base/waste/bin_days.html
index 0b51e9a47..e5a1d41c5 100644
--- a/templates/web/base/waste/bin_days.html
+++ b/templates/web/base/waste/bin_days.html
@@ -71,7 +71,7 @@
<div class="aside-download">
<h3>Download your collection schedule</h3>
<ul>
- <li><a href="#">Add to your calendar (.ics file)</a></li>
+ <li><a href="[% c.uri_for_action('waste/calendar', [ uprn ]) %]">Add to your calendar (.ics file)</a></li>
</ul>
</div>
[% IF any_report_allowed OR any_request_allowed %]