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");
15 Nicolas Morales <nm529@cornell.edu>
21 package CXGN
::Calendar
;
25 use SGN
::Model
::Cvterm
;
32 isa
=> 'Bio::Chado::Schema',
36 has
'sp_person_id' => (
47 sub check_value_format
{
52 #Events saved through the calendar will have this format
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 elsif ($value =~ /^\d\d\d\d\/\d\d\
/\d\d\s\d\d:\d\d:\d\d$/) {
58 $value = $self->format_time($value)->datetime;
59 return '{"'.$value.'","'.$value.'","","#"}';
61 #Historical dates in teh database often have this format
62 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)/) {
63 $value = $self->format_time($value)->datetime;
64 return '{"'.$value.'","'.$value.'","","#"}';
74 sub parse_calendar_array
{
76 my $raw_value = shift;
78 $raw_value =~ tr/{}"//d;
79 my @calendar_array = split(/,/, $raw_value);
80 return @calendar_array;
83 #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.
84 sub format_display_date
{
87 my $formatted_time = shift;
89 if ($formatted_time->hms('') == '000000') {
90 $date_display = $formatted_time->strftime("%Y-%B-%d");
92 $date_display = $formatted_time->strftime("%Y-%B-%d %H:%M:%S");
97 #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.
98 sub calendar_end_display
{
100 my $formatted_time = shift;
105 $end_time = $formatted_time->epoch;
106 if ($view eq 'month' || ($view eq 'agendaWeek' && $allday == 1)) {
107 $end_time += ONE_DAY
;
109 $end_time = Time
::Piece
->strptime($end_time, '%s')->datetime;
113 #On the agendaWeek view, events with start dates with 00:00:00 time are displayed as allDay=true.
114 sub determine_allday
{
117 my $formatted_time = shift;
119 if ($formatted_time->hms('') == '000000') {
127 #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 teh database.
130 my $input_time = shift;
132 #print STDERR $input_time."\n";
136 if ($input_time =~ /^\d{4}-\d\d-\d\d$/) {
137 #print STDERR '1 '.$input_time."\n";
138 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%m-%d');
140 if ($input_time =~ /^\d\d\d\d\/\d\d\
/\d\d\s\d\d:\d\d:\d\d$/) {
141 #print STDERR '2 '.$input_time."\n";
142 $formatted_time = Time
::Piece
->strptime($input_time, '%Y/%m/%d %H:%M:%S');
144 if ($input_time =~ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})$/) {
145 #print STDERR '3 '.$input_time."\n";
146 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%m-%dT%H:%M:%S');
148 if ($input_time =~ /^(\d{4})-(Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d{2})$/) {
149 #print STDERR '4 '.$input_time."\n";
150 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%b-%d');
152 if ($input_time =~ /^(\d{4})-(Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d{1})$/) {
153 my $single_digit_date = substr($input_time, -1);
154 my $input_time_1 = substr($input_time, 0, -1);
155 $input_time = $input_time_1.'0'.$single_digit_date;
156 #print STDERR '5 '.$input_time."\n";
157 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%b-%d');
159 if ($input_time =~ /^(\d{4})-(January|February|March|April|May|June|July|August|September|October|November|December)-(\d{2})$/) {
160 #print STDERR '6 '.$input_time."\n";
161 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%B-%d');
163 if ($input_time =~ /^(\d{4})-(January|February|March|April|May|June|July|August|September|October|November|December)-(\d{1})$/) {
164 my $single_digit_date = substr($input_time, -1);
165 my $input_time_1 = substr($input_time, 0, -1);
166 $input_time = $input_time_1.'0'.$single_digit_date;
167 #print STDERR '7 '.$input_time."\n";
168 $formatted_time = Time
::Piece
->strptime($input_time, '%Y-%B-%d');
170 return $formatted_time;
174 sub get_calendar_events_personal
{
176 my $schema = $self->bcs_schema;
177 my $dbh = $schema->storage->dbh;
178 my $person_id = $self->sp_person_id;
179 my @roles = @
{$self->roles};
180 #print STDERR Dumper \@roles;
182 my @search_project_ids = '-1';
184 my $q="SELECT project_id FROM project WHERE name=?";
185 my $sth = $dbh->prepare($q);
187 while (my ($project_id) = $sth->fetchrow_array ) {
188 push(@search_project_ids, $project_id);
190 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'";
191 my $sth = $dbh->prepare($q);
192 $sth->execute($project_id);
193 while (my ($trial) = $sth->fetchrow_array ) {
194 push(@search_project_ids, $trial);
199 @search_project_ids = map{$_='me.project_id='.$_; $_} @search_project_ids;
200 my $search_projects = join(" OR ", @search_project_ids);
201 my $search_rs = $schema->resultset('Project::Project')->search(
203 {join=>{'projectprops'=>{'type'=>'cv'}},
204 '+select'=> ['projectprops.projectprop_id', 'type.name', 'projectprops.value', 'type.cvterm_id'],
205 '+as'=> ['pp_id', 'cv_name', 'pp_value', 'cvterm_id'],
208 $search_rs = $search_rs->search([$search_projects]);
212 sub populate_calendar_events
{
214 my $search_rs = shift;
228 while (my $result = $search_rs->next) {
230 #Check if project property value is an event, and if it is not, then skip to next result.
231 my $calendar_formatted_value = $self->check_value_format($result->get_column('pp_value'));
232 if (!$calendar_formatted_value) {
236 #print STDERR $calendar_formatted_value;
238 @calendar_array = $self->parse_calendar_array($calendar_formatted_value);
239 if (!$calendar_array[0]) {
243 #We begin with the start datetime, or the first element in the @calendar_array.
244 #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.
245 $formatted_time = $self->format_time($calendar_array[0]);
246 $start_time = $formatted_time->datetime;
247 $start_display = $self->format_display_date($formatted_time);
249 #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().
250 if ($view eq 'month') {
252 } elsif ($view eq 'agendaWeek') {
253 $allday = $self->determine_allday($formatted_time);
256 #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.
257 $formatted_time = $self->format_time($calendar_array[1]);
258 $end_time = $self->calendar_end_display($formatted_time, $view, $allday);
259 $end_display = $self->format_display_date($formatted_time);
261 #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.
262 $end_drag = $formatted_time->datetime;
264 #To display the project name and project properties nicely in the mouseover and more info, we capitalize the first letter of each word.
265 $title = $result->name;
266 #$title =~ s/([\w']+)/\u\L$1/g;
267 $property = $result->get_column('cv_name');
268 $property =~ s/([\w']+)/\u\L$1/g;
270 #Variables are pushed into the event array and will become properties of Fullcalendar events, like event.start, event.cvterm_url, etc.
271 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]});
276 #Takes an event string, which is the value stored in the database for events, and return a nice start date.
277 sub display_start_date
{
281 my $checked_value = $self->check_value_format($value);
282 if ($checked_value) {
283 my @calendar_array = $self->parse_calendar_array($checked_value);
284 if ($calendar_array[0]) {
285 my $formatted_time = $self->format_time($calendar_array[0]);
286 my $start_display = $self->format_display_date($formatted_time);
287 return $start_display;
296 #Takes an event string, which is the value stored in the database for events, and return a nice end date.
297 sub display_end_date
{
301 my $checked_value = $self->check_value_format($value);
302 if ($checked_value) {
303 my @calendar_array = $self->parse_calendar_array($checked_value);
304 if ($calendar_array[1]) {
305 my $formatted_time = $self->format_time($calendar_array[1]);
306 my $end_display = $self->format_display_date($formatted_time);
316 #Takes an event string, which is the value stored in the database for events, and returns the description.
317 sub display_description
{
321 my $checked_value = $self->check_value_format($value);
322 if ($checked_value) {
323 my @calendar_array = $self->parse_calendar_array($checked_value);
324 if ($calendar_array[2]) {
325 my $description = $calendar_array[2];
335 #Takes an event string, which is the value stored in the database for events, and returns the url.
340 my $checked_value = $self->check_value_format($value);
341 if ($checked_value) {
342 my @calendar_array = $self->parse_calendar_array($checked_value);
343 if ($calendar_array[3]) {
344 my $url = $calendar_array[3];