4 CXGN::Calendar - helper class for calendar
8 my $calendar_funcs = CXGN::Calendar->new( { } );
9 $calendar_funcs->check_value_format("2012/01/01 00:00:00");
20 package CXGN
::Calendar
;
24 use SGN
::Model
::Cvterm
;
31 isa
=> 'Bio::Chado::Schema',
35 has
'sp_person_id' => (
46 sub check_value_format
{
51 #Events saved through the calendar will have this format
52 # "YYYY-MM-DDTHH:MM:SS"
53 if ($value =~ /^{"\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d","\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d","/) {
56 #Dates saved through the trial 'Add Harvest Date' or 'Add Planting Date' will have this format
57 # "YYYY/MM/DD HH:MM:SS"
58 elsif ($value =~ /^\d\d\d\d\/\d\d\
/\d\d\s\d\d:\d\d:\d\d$/) {
59 $value = $self->format_time($value)->datetime;
60 return '{"'.$value.'","'.$value.'","","#"}';
62 #Harvest and Planting Dates uploaded via Upload Trial Design files will have this format
64 elsif ($value =~ /^\d{4}-\d\d-\d\d$/) {
65 $value = $self->format_time($value)->datetime;
66 return '{"'.$value.'","'.$value.'","","#"}';
68 #Historical dates in the database often have this format
70 elsif ($value =~ /^(\d{4})-(Jan|January|Feb|February|March|Mar|April|Apr|May|June|Jun|July|Jul|August|Aug|September|Sep|October|Oct|November|Nov|December|Dec)-(\d)/) {
71 $value = $self->format_time($value)->datetime;
72 return '{"'.$value.'","'.$value.'","","#"}';
82 sub parse_calendar_array
{
84 my $raw_value = shift;
86 $raw_value =~ tr/{}"//d;
87 my @calendar_array = split(/,/, $raw_value);
88 return @calendar_array;
91 #Displaying 00:00:00 time on mouseover and mouseclick is ugly, so this sub is used to determine date display format, given a datetime string.
92 sub format_display_date
{
95 my $formatted_time = shift;
97 if ($formatted_time->hms('') == '000000') {
98 $date_display = $formatted_time->strftime("%Y-%B-%d");
100 $date_display = $formatted_time->strftime("%Y-%B-%d %H:%M:%S");
102 return $date_display;
105 #FullCalendar's end datetime is exclusive for allday events in the month view. Since all events in the month view are allday = 1, a full day must be added so that it is displayed correctly on the calendar. In the agendaWeek view, not all events are allday = 1, so the end is only modified for allday events.
106 sub calendar_end_display
{
108 my $formatted_time = shift;
113 $end_time = $formatted_time->epoch;
114 if ($view eq 'month' || ($view eq 'agendaWeek' && $allday == 1)) {
115 $end_time += ONE_DAY
;
117 $end_time = Time
::Piece
->strptime($end_time, '%s')->datetime;
121 #On the agendaWeek view, events with start dates with 00:00:00 time are displayed as allDay=true.
122 sub determine_allday
{
125 my $formatted_time = shift;
127 if ($formatted_time->hms('') == '000000') {
135 #This function is used to return a Time::Piece object, which is useful for format consistency. It can take a variety of formats, which is important to match historic date data in the database.
138 my $input_time = shift;
140 #print STDERR $input_time."\n";
144 if ($input_time =~ /^\d{4}-\d\d-\d\d$/) {
145 #print STDERR '1 '.$input_time."\n";
146 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%m-%d');
148 if ($input_time =~ /^\d\d\d\d\/\d\d\
/\d\d\s\d\d:\d\d:\d\d$/) {
149 #print STDERR '2 '.$input_time."\n";
150 $formatted_time = Time
::Piece
->strptime($input_time, '%Y/%m/%d %H:%M:%S');
152 if ($input_time =~ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})$/) {
153 #print STDERR '3 '.$input_time."\n";
154 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%m-%dT%H:%M:%S');
156 if ($input_time =~ /^(\d{4})-(Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d{2})$/) {
157 #print STDERR '4 '.$input_time."\n";
158 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%b-%d');
160 if ($input_time =~ /^(\d{4})-(Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d{1})$/) {
161 my $single_digit_date = substr($input_time, -1);
162 my $input_time_1 = substr($input_time, 0, -1);
163 $input_time = $input_time_1.'0'.$single_digit_date;
164 #print STDERR '5 '.$input_time."\n";
165 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%b-%d');
167 if ($input_time =~ /^(\d{4})-(January|February|March|April|May|June|July|August|September|October|November|December)-(\d{2})$/) {
168 #print STDERR '6 '.$input_time."\n";
169 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%B-%d');
171 if ($input_time =~ /^(\d{4})-(January|February|March|April|May|June|July|August|September|October|November|December)-(\d{1})$/) {
172 my $single_digit_date = substr($input_time, -1);
173 my $input_time_1 = substr($input_time, 0, -1);
174 $input_time = $input_time_1.'0'.$single_digit_date;
175 #print STDERR '7 '.$input_time."\n";
176 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%B-%d');
178 return $formatted_time;
182 sub get_calendar_events_personal
{
184 my $schema = $self->bcs_schema;
185 my $dbh = $schema->storage->dbh;
186 my $person_id = $self->sp_person_id;
187 my @roles = @
{$self->roles};
188 #print STDERR Dumper \@roles;
190 my @search_project_ids = '-1';
192 my $q="SELECT project_id FROM project WHERE name=?";
193 my $sth = $dbh->prepare($q);
195 while (my ($project_id) = $sth->fetchrow_array ) {
196 push(@search_project_ids, $project_id);
198 my $q="SELECT subject_project_id FROM project_relationship JOIN cvterm ON (type_id=cvterm_id) WHERE object_project_id=? and cvterm.name='breeding_program_trial_relationship'";
199 my $sth = $dbh->prepare($q);
200 $sth->execute($project_id);
201 while (my ($trial) = $sth->fetchrow_array ) {
202 push(@search_project_ids, $trial);
207 @search_project_ids = map{$_='me.project_id='.$_; $_} @search_project_ids;
208 my $search_projects = join(" OR ", @search_project_ids);
209 my $search_rs = $schema->resultset('Project::Project')->search(
211 {join=>{'projectprops'=>{'type'=>'cv'}},
212 '+select'=> ['projectprops.projectprop_id', 'type.name', 'projectprops.value', 'type.cvterm_id'],
213 '+as'=> ['pp_id', 'cv_name', 'pp_value', 'cvterm_id'],
216 $search_rs = $search_rs->search([$search_projects]);
220 sub populate_calendar_events
{
222 my $search_rs = shift;
236 while (my $result = $search_rs->next) {
238 #Check if project property value is an event, and if it is not, then skip to next result.
239 my $calendar_formatted_value = $self->check_value_format($result->get_column('pp_value'));
240 if (!$calendar_formatted_value) {
244 #print STDERR $calendar_formatted_value;
246 @calendar_array = $self->parse_calendar_array($calendar_formatted_value);
247 if (!$calendar_array[0]) {
251 #We begin with the start datetime, or the first element in the @calendar_array.
252 #A time::piece object is returned from format_time(). Calling ->datetime on this object returns an ISO8601 datetime string. This string is what is used as the calendar event's start. Using format_display_date(), a nice date to display on mouse over is returned.
253 $formatted_time = $self->format_time($calendar_array[0]);
254 $start_time = $formatted_time->datetime;
255 $start_display = $self->format_display_date($formatted_time);
257 #Because fullcalendar does not allow event resizing of allDay=false events in the month view, the allDay parameter must be set depending on the view. The allDay parameter for the agendaWeek view is important and is set using determine_allday().
258 if ($view eq 'month') {
260 } elsif ($view eq 'agendaWeek') {
261 $allday = $self->determine_allday($formatted_time);
264 #Then we process the end datetime, which is the second element in the calendar_array. calendar_end_display determines what the calendar should display as the end, and format_display_date() returns a nice date to display on mouseover.
265 $formatted_time = $self->format_time($calendar_array[1]);
266 $end_time = $self->calendar_end_display($formatted_time, $view, $allday);
267 $end_display = $self->format_display_date($formatted_time);
269 #Because FullCallendar's end date is exclusive, an end datetime with 00:00:00 will be displayed as one day short on the calendar, and so corrections to the event's end must be made. To facilitate event dragging, an event.end_drag property is used.
270 $end_drag = $formatted_time->datetime;
272 #To display the project name and project properties nicely in the mouseover and more info, we capitalize the first letter of each word.
273 $title = $result->name;
274 #$title =~ s/([\w']+)/\u\L$1/g;
275 $property = $result->get_column('cv_name');
276 $property =~ s/([\w']+)/\u\L$1/g;
278 #Variables are pushed into the event array and will become properties of Fullcalendar events, like event.start, event.cvterm_url, etc.
279 push(@events, {projectprop_id
=>$result->get_column('pp_id'), title
=>$title, property
=>$property, start
=>$start_time, start_drag
=>$start_time, start_display
=>$start_display, end
=>$end_time, end_drag
=>$end_drag, end_display
=>$end_display, project_id
=>$result->project_id, project_url
=>'/breeders_toolbox/trial/'.$result->project_id.'/', cvterm_id
=>$result->get_column('cvterm_id'), cvterm_url
=>'/cvterm/'.$result->get_column('cvterm_id').'/view', allDay
=>$allday, p_description
=>$result->description, event_description
=>$calendar_array[2], event_url
=>$calendar_array[3]});
284 #Takes an event string, which is the value stored in the database for events, and return a nice start date.
285 sub display_start_date
{
289 my $checked_value = $self->check_value_format($value);
290 if ($checked_value) {
291 my @calendar_array = $self->parse_calendar_array($checked_value);
292 if ($calendar_array[0]) {
293 my $formatted_time = $self->format_time($calendar_array[0]);
294 my $start_display = $self->format_display_date($formatted_time);
295 return $start_display;
304 #Takes an event string, which is the value stored in the database for events, and return a nice end date.
305 sub display_end_date
{
309 my $checked_value = $self->check_value_format($value);
310 if ($checked_value) {
311 my @calendar_array = $self->parse_calendar_array($checked_value);
312 if ($calendar_array[1]) {
313 my $formatted_time = $self->format_time($calendar_array[1]);
314 my $end_display = $self->format_display_date($formatted_time);
324 #Takes an event string, which is the value stored in the database for events, and returns the description.
325 sub display_description
{
329 my $checked_value = $self->check_value_format($value);
330 if ($checked_value) {
331 my @calendar_array = $self->parse_calendar_array($checked_value);
332 if ($calendar_array[2]) {
333 my $description = $calendar_array[2];
343 #Takes an event string, which is the value stored in the database for events, and returns the url.
348 my $checked_value = $self->check_value_format($value);
349 if ($checked_value) {
350 my @calendar_array = $self->parse_calendar_array($checked_value);
351 if ($calendar_array[3]) {
352 my $url = $calendar_array[3];