4 SGN::Controller::AJAX::Calendar - a REST controller class to provide the
5 backend for displaying, adding, deleting, dragging, modifying, and requesting more info about events. All calendar related functions are here.
9 Calendar events are saved in the projectprop table value field as a tuple of the format {"2007-09-21T00:00:00","2007-09-21T00:00:00","N/A","#"} which correspond to the start datetime, end datetime, description, and web url, respectively.
11 The calendar can display events for projects (breeding programs and their trials) which a user has a role for in the sp_person_roles table.
16 Nicolas Morales <nm529@cornell.edu>
23 package SGN
::Controller
::AJAX
::Calendar
;
32 use SGN
::Model
::Cvterm
;
35 BEGIN { extends
'Catalyst::Controller::REST' }
38 default => 'application/json',
40 map => { 'application/json' => 'JSON' },
44 =head2 /ajax/calendar/populate/personal/{view}
46 Usage: When the calendar is loaded and when controls (such as next month or year) are used, this function is called to get event data. Arguments are the calendar views which are either month or agendaWeek.
49 [{"event_description":"N/A","end_drag":"2015-10-28T00:00:00","event_url":"#","allDay":1,"end_display":"2015-10-28","project_id":89,"property":"Planting Event","p_description":"Plants assayed at Zaria in 2002/03","cvterm_url":"/cvterm/76941/view","start_drag":"2015-10-28T00:00:00","end":"2015-10-29T00:00:00","start_display":"2015-10-28","projectprop_id":2735,"cvterm_id":76941,"title":"Cassava Zaria 2002/03","project_url":"/breeders_toolbox/trial/89/","start":"2015-10-28T00:00:00"},{"event_description":"N/A","end_drag":"2015-10-23T00:00:00","event_url":"#","allDay":1,"end_display":"2015-10-23","project_id":599,"property":"Presentation Event","p_description":"Test Bootstrap2","cvterm_url":"/cvterm/76946/view","start_drag":"2015-10-22T00:00:00","end":"2015-10-24T00:00:00","start_display":"2015-10-22","projectprop_id":2729,"cvterm_id":76946,"title":"TestBootstrap2","project_url":"/breeders_toolbox/trial/599/","start":"2015-10-22T00:00:00"}]
50 Args: The calendar view being displayed, either month or agendaWeek
57 sub calendar_events_personal
: Path
('/ajax/calendar/populate/personal') : ActionClass
('REST') { }
58 sub calendar_events_personal_GET
: Args
(1) {
62 if (!$c->user()) {$c->detach();}
63 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
64 my @roles = $c->user->get_roles();
66 my $calendar_funcs = CXGN
::Calendar
->new({
67 bcs_schema
=> $schema,
68 sp_person_id
=> $c->user->get_object->get_sp_person_id,
71 my $search_rs = $calendar_funcs->get_calendar_events_personal($c);
72 $c->stash->{rest
} = $calendar_funcs->populate_calendar_events($search_rs, $view);
75 =head2 /ajax/calendar/drag_or_resize
77 Usage: When an event is added using the day_dialog_add_event_form, this function is called to save it to the database.
80 Args: event_start, event_end, event_description, event_url, event_project_select, event_type_select
86 sub add_event
: Path
('/ajax/calendar/add_event') : ActionClass
('REST') { }
90 my $params = $c->req->params();
92 if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter')) ) {
93 $c->stash->{rest
} = {status
=> 3};
97 my $calendar_funcs = CXGN
::Calendar
->new({});
99 #A time::piece object is returned from format_time(). Calling ->datetime on this object return an ISO8601 datetime string. This is what is saved in the db.
100 my $format_start = $calendar_funcs->format_time($params->{event_start
})->datetime;
102 #If an event end is given, then it is converted to an ISO8601 datetime string to be saved. If none is given then the end will be the same as the start.
104 if ($params->{event_end
} eq '') {$format_end = $format_start;} else {$format_end = $calendar_funcs->format_time($params->{event_end
})->datetime;}
106 #If no description or URL given, then default values will be given.
107 if ($params->{event_description
} eq '') {$params->{event_description
} = 'N/A';}
108 if ($params->{event_url
} eq '') {$params->{event_url
} = '#';} else {$params->{event_url
} = 'http://www.'.$params->{event_url
};}
110 my $schema = $c->dbic_schema('Bio::Chado::Schema');
111 my $rs = $schema->resultset('Project::Projectprop');
112 my $count = $rs->search({ project_id
=>$params->{event_project_select
}, type_id
=>$params->{event_type_select
} })->count;
114 if (my $insert = $rs->create({project_id
=>$params->{event_project_select
}, type_id
=>$params->{event_type_select
}, rank
=>$count, value
=>[$format_start, $format_end, $params->{event_description
}, $params->{event_url
}] })) {
115 $c->stash->{rest
} = {status
=> 1,};
117 $c->stash->{rest
} = {status
=> 2,};
121 =head2 /ajax/calendar/delete_event
123 Usage: To delete an event
126 Args: event_projectprop_id
132 sub delete_event
: Path
('/ajax/calendar/delete_event') : ActionClass
('REST') { }
133 sub delete_event_POST
{
137 if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter')) ) {
138 $c->stash->{rest
} = {status
=> 3};
142 my $projectprop_id = $c->req->param("event_projectprop_id");
143 my $schema = $c->dbic_schema('Bio::Chado::Schema');
144 if (my $delete = $schema->resultset('Project::Projectprop')->find({projectprop_id
=>$projectprop_id})->delete) {
145 $c->stash->{rest
} = {status
=> 1,};
147 $c->stash->{rest
} = {status
=> 0,};
151 =head2 /ajax/calendar/drag_or_resize
153 Usage: When an event is dragged to a new date a value of drag = 1 is passed to the function. When an event is simply resized a value of drag = 0 is passed to the function. This function saves the new start and end date to the db and updates the calendar display and mouseover.
156 Args: start_drag, delta, end_drag, drag, view, allday, projectprop_id, description, url
162 sub drag_or_resize_event
: Path
('/ajax/calendar/drag_or_resize') : ActionClass
('REST') { }
163 sub drag_or_resize_event_POST
{
166 my $params = $c->req->params();
168 if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter')) ) {
169 $c->stash->{rest
} = {status
=> 3};
173 my $calendar_funcs = CXGN
::Calendar
->new({});
175 #First we process the start datetime.
176 #A time::piece object is returned from format_time(). Delta is the number of seconds that the date was changed. Calling ->epoch on the time::piece object returns a string representing number of sec since epoch.
177 my $formatted_start = $calendar_funcs->format_time($params->{start_drag
} )->epoch;
179 #If the event is being dragged to a new start, then the delta is added to the start here. When resizing, the start is not changed, only the end is changed.
180 if ($params->{drag
} == 1) {
181 $formatted_start += $params->{delta
};
184 #The string representing the new number of sec since epoch is parsed into a time::piece object.
185 $formatted_start = Time
::Piece
->strptime($formatted_start, '%s');
187 # $new_start is what is saved to db. $new_start_display is what is displayed on mouseover.
188 my $new_start = $formatted_start->datetime;
189 my $new_start_display = $calendar_funcs->format_display_date($formatted_start);
191 #Next we process the end datetime. Whether the event is being dragged or resized, the end = end + delta.
192 my $formatted_end = $calendar_funcs->format_time($params->{end_drag
} )->epoch;
193 $formatted_end += $params->{delta
};
194 $formatted_end = Time
::Piece
->strptime($formatted_end, '%s');
196 # $new_end is what is saved in db.
197 my $new_end = $formatted_end->datetime;
198 my $new_end_time = $calendar_funcs->calendar_end_display($formatted_end, $params->{view
}, $params->{allday
} );
199 my $new_end_display = $calendar_funcs->format_display_date($formatted_end);
201 my $schema = $c->dbic_schema('Bio::Chado::Schema');
202 if (my $update_rs = $schema->resultset('Project::Projectprop')->find({projectprop_id
=>$params->{projectprop_id
} }, columns
=>['value'])->update({value
=>[$new_start, $new_end, $params->{description
}, $params->{url
}] })) {
204 $c->stash->{rest
} = {success
=> 1, start
=>$new_start, start_drag
=>$new_start, start_display
=>$new_start_display, end
=>$new_end_time, end_drag
=>$new_end, end_display
=>$new_end_display};
206 $c->stash->{rest
} = {error
=> 1,};
210 =head2 /ajax/calendar/edit_event
212 Usage: When an event is editted using the edit_event_form
215 Args: edit_event_start, edit_event_end, edit_event_description, edit_event_url, edit_event_projectprop_id, edit_event_project_select, edit_event_type_select
221 sub edit_event
: Path
('/ajax/calendar/edit_event') : ActionClass
('REST') { }
222 sub edit_event_POST
{
226 if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter')) ) {
227 $c->stash->{rest
} = {status
=> 3};
231 my $params = $c->req->params();
232 my $calendar_funcs = CXGN
::Calendar
->new({});
234 #A time::piece object is returned from format_time(). Calling ->datetime on this object return an ISO8601 datetime string. This is what is saved in the db.
235 my $format_start = $calendar_funcs->format_time($params->{edit_event_start
})->datetime;
237 #If an event end is given, then it is converted to an ISO8601 datetime string to be saved. If none is given then the end will be the same as the start.
239 if ($params->{edit_event_end
} eq '') {$format_end = $format_start;} else {$format_end = $calendar_funcs->format_time($params->{edit_event_end
})->datetime;}
241 #If no description or URL given or end date given, then default values will be given.
242 if ($params->{edit_event_description
} eq '') {$params->{edit_event_description
} = 'N/A';}
243 if ($params->{edit_event_url
} eq '') {$params->{edit_event_url
} = '#';}
245 my $schema = $c->dbic_schema('Bio::Chado::Schema');
246 if (my $update_rs = $schema->resultset('Project::Projectprop')->find({projectprop_id
=>$params->{edit_event_projectprop_id
} }, columns
=>['project_id', 'type_id', 'value'])->update({project_id
=>$params->{edit_event_project_select
}, type_id
=>$params->{edit_event_type_select
}, value
=>[$format_start, $format_end, $params->{edit_event_description
}, $params->{edit_event_url
}] })) {
247 $c->stash->{rest
} = {status
=> 1,};
249 $c->stash->{rest
} = {error
=> 1,};
254 #When a day is clicked or when an event is being editted, this function is called to populate the add_event project name and property type dropdowns.
255 sub day_click_personal
: Path
('/ajax/calendar/dayclick/personal') : ActionClass
('REST') { }
256 sub day_click_personal_GET
{
260 my $person_id = $c->user->get_object->get_sp_person_id;
262 my @roles = $c->user->get_roles();
265 my $q="SELECT project_id, name FROM project WHERE name=?";
266 my $sth = $c->dbc->dbh->prepare($q);
268 while (my ($project_id, $name) = $sth->fetchrow_array ) {
269 push(@projects, {project_id
=>$project_id, project_name
=>$name});
271 my $q="SELECT subject_project_id, project.name FROM project_relationship JOIN cvterm ON (type_id=cvterm_id) JOIN project ON (subject_project_id=project_id) WHERE object_project_id=? and cvterm.name='breeding_program_trial_relationship'";
272 my $sth = $c->dbc->dbh->prepare($q);
273 $sth->execute($project_id);
274 while (my ($trial_id, $trial_name) = $sth->fetchrow_array ) {
275 push(@projects, {project_id
=>$trial_id, project_name
=>$trial_name});
280 my @calendar_projectprop_names = (['project_planting_date', 'project_property'], ['project_harvest_date', 'project_property'], ['Fertilizer Event', 'calendar'], ['Meeting Event', 'calendar'], ['Planning Event', 'calendar'], ['Presentation Event', 'calendar'], ['Phenotyping Event', 'calendar'], ['Genotyping Event', 'calendar'] );
282 my $schema = $c->dbic_schema('Bio::Chado::Schema');
283 my @projectprop_types;
284 foreach (@calendar_projectprop_names) {
285 my $term = SGN
::Model
::Cvterm
->get_cvterm_row($schema, $_->[0], $_->[1] );
287 push(@projectprop_types, {cvterm_id
=>$term->cvterm_id(), cvterm_name
=>$term->name() });
289 push(@projectprop_types, {cvterm_id
=>'', cvterm_name
=>'Error: Missing cvterm '.$_->[0].' : '.$_->[1].' in database.'});
293 $c->stash->{rest
} = {project_list
=> \
@projects, projectprop_list
=> \
@projectprop_types};