clean
[sgn.git] / lib / SGN / Controller / AJAX / Organism.pm
blob66be2b7afbe3132e40ffc7a7af6d22b724851f86
1 package SGN::Controller::AJAX::Organism;
2 use Moose;
3 use List::MoreUtils qw | any |;
4 use YAML::Any;
5 use JSON::Any;
6 use Data::Dumper;
8 BEGIN { extends 'Catalyst::Controller::REST' }
11 __PACKAGE__->config(
12 default => 'application/json',
13 stash_key => 'rest',
14 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
18 =head2 autocomplete
20 Public Path: /organism/autocomplete
22 Autocomplete an organism species name. Takes a single GET param,
23 C<term>, responds with a JSON array of completions for that term.
25 =cut
27 sub autocomplete :Path('/organism/autocomplete') :ActionClass('REST') {}
29 sub autocomplete_GET :Args(0) {
30 my ( $self, $c ) = @_;
32 my $term = $c->req->param('term');
34 # trim and regularize whitespace
35 $term =~ s/(^\s+|\s+)$//g;
36 $term =~ s/\s+/ /g;
38 my $s = $c->dbic_schema('Bio::Chado::Schema','sgn_chado')
39 ->resultset('Organism::Organism');
41 my @results = $s->search({ species => { ilike => '%'.$term.'%' }},
42 { rows => 15 },
44 ->get_column('species')
45 ->all;
47 $c->stash->{rest} = \@results;
52 =head2 project_metadata
54 Usage: Action to update metadata information about sequencing
55 projects
56 Desc: Stores the sequencing metadata for each accession in an
57 organismprop, using a JSON data structure for storing the
58 different fields.
59 Side Effects: stores/updates/deletes metadata information
61 =cut
63 sub project_metadata :Chained('/organism/find_organism') :PathPart('metadata') :Args(0) {
64 my $self = shift;
65 my $c = shift;
67 my $action = $c->req->param('action');
69 #object id is a combination of prop_id and organism_id, separated by a "-"
70 my $organism = $c->stash->{organism};
71 my ($prop_id, undef) = split "-", $c->req->param('object_id') || '';
72 my $organism_id = $organism->organism_id;
73 my $login_user_id = 0;
74 my $login_user_can_modify = 0;
76 $c->stash->{json} = JSON::Any->new();
78 if($c->user()) {
79 $login_user_id = $c->user()->get_object()->get_sp_person_id();
80 $login_user_can_modify = any { $_ =~ /curator|sequencer|submitter/i } ($c->user()->roles());
83 # 1. get all the props associated with the organism
84 # 2. if it is a view, render them all
85 # 3. if it is an edit, render them, but render the selected prop_id as an editable
86 # 4. if it is a store, store the selected prop_id, display everything as static
87 # 5. if it is a delete, delete the selected prop_id, display everthing as static
89 my $form;
90 my $html = "";
92 if (!$action) { $action = 'view'; }
93 if ($login_user_can_modify && ($action ne 'view')) {
94 if (!$login_user_id) {
95 $self->status_bad_request( $c, message => 'Must be logged in to edit' );
96 return;
98 if ($action eq 'confirm_delete') {
99 $organism->search_related('organismprops',{ organismprop_id=>$prop_id })->delete;
102 if ($action eq 'store') {
103 my $props = $c->req->parameters();
104 my %props = $self->project_metadata_prop_list();
105 my $store_props = {};
106 foreach my $p (keys(%props )) {
107 $store_props->{$p}=$props->{$p};
109 my $json = $c->stash->{json}->objToJson($store_props);
111 $form = $self->metadata_form($c, $json, $prop_id, $organism_id);
113 $form->process($c->req());
115 if ($form->submitted_and_valid()) {
116 if ($prop_id) {
117 my $prop = $organism->find_related( 'organismprops', {
118 organismprop_id => $prop_id,
120 unless( $prop ) {
121 $self->status_bad_request(
122 $c, message =>
123 'no such organismprop',
125 return;
127 $prop->update({ value => $json });
129 else {
130 $organism->create_organismprops(
131 { 'organism_sequencing_metadata' => $json },
132 { autocreate => 1,
133 cv_name => 'local',
134 definitions => { organism_sequencing_metadata => "metadata about this organism's sequencing status" },
138 $c->forward('/organism/invalidate_organism_tree_cache');
140 else {
141 $self->status_bad_request( $c, message => 'Form is not valid' );
142 return;
147 my @proplist = $self->get_organism_metadata_props( $c );
149 foreach my $p (@proplist) {
151 if (exists($p->{organismprop_id}) && defined $prop_id && $prop_id eq $p->{organismprop_id} && $action eq "edit") {
152 if ($login_user_can_modify) {
153 #make the form editable
154 $form = $self->metadata_form($c, $p->{json}, $prop_id, $organism_id);
155 $html .= $form->render();
156 $html .= "<hr />\n";
159 else {
160 $html .= $self->metadata_static($c, $p->{json});
161 $html .= "<hr />\n";
164 if ($login_user_can_modify) {
165 # add appropriate edit and delete links
166 $html .= "<a href=\"javascript:organismObjectName.setObjectId('$p->{organismprop_id}-$organism_id'); organismObjectName.printForm('edit'); \">Edit</a> <a href=\"javascript:organismObjectName.setObjectId('$p->{organismprop_id}-$organism_id'); organismObjectName.printDeleteDialog();\">Delete</a><hr />";
171 if ($login_user_can_modify && $action eq 'new') {
172 $form = $self->metadata_form($c, undef, undef, $organism_id);
173 $html .= $form->render();
174 $html .= qq | <br /><a href="javascript:organismObjectName.render();">Cancel</a><br /><br /> | ;
176 elsif ($login_user_can_modify) {
177 $html .= "<br /><a href=\"javascript:organismObjectName.setObjectId('-$organism_id' ); organismObjectName.printForm('new');\">New</a>";
180 if ( $action eq 'new' || $action eq 'view' || !$action || !$login_user_can_modify) {
181 $self->status_ok(
183 entity => { login_user_id => $login_user_id,
184 editable_form_id => 'organism_project_metadata_form',
185 is_owner => $login_user_can_modify,
186 html => $html,
190 elsif ($action eq 'store') {
191 $self->status_ok( $c, entity => [ 'success' ] );
194 else {
196 ### get project metadata information for that organism
197 $self->status_ok( $c, entity => {
198 login_user_id => $login_user_id,
199 editable_form_id => 'organism_project_metadata_form',
200 is_owner => $login_user_can_modify,
201 html => $html,
206 sub metadata_form {
207 my ($self, $c, $json, $prop_id, $organism_id) = @_;
209 my $data = {};
210 if ($json) {
211 #print STDERR "CONVERTING JSON...\n";
212 $data = $c->stash->{json}->jsonToObj($json); }
213 else {
214 #print STDERR "No JSON data provided...\n";
218 my $object_id = ($prop_id || '')."-".$organism_id;
219 my $form = HTML::FormFu->new(Load(<<YAML));
220 method: POST
221 attributes:
222 name: organism_project_metadata_form
223 id: organism_project_metadata_form
224 elements:
225 - type: Hidden
226 name: action
227 value: store
228 - type: Hidden
229 name: object_id
230 value: $object_id
231 YAML
235 my %fields = $self->project_metadata_prop_list();
237 foreach my $k (keys %fields) {
239 $form->element( { type=>'Text', name=>$k, label=>$fields{$k}, value=>$data->{$k}, size=>30 });
243 return $form;
246 sub metadata_static {
247 my $self = shift;
248 my $c = shift;
249 my $json = shift;
251 if (!$json) { return; }
253 my %props = %{$c->{stash}->{json}->jsonToObj($json)};
255 my %fields = $self->project_metadata_prop_list();
257 my $static = '<table>';
259 foreach my $k (keys %fields) {
260 no warnings 'uninitialized';
261 $static .= '<tr><td>'.$fields{$k}.'</td><td>&nbsp;</td><td><b>'.$props{$k}.'</b></td></tr>';
264 $static .= '</table>';
265 return $static;
269 =head2 project_metadata_prop_list()
271 defines the prop list as a hash. the key is the name of the property (stored in cvterm as a 'local' cv and referenced through 'type_id' and the value is the display text for that property.
273 =cut
275 sub project_metadata_prop_list {
276 return ("genome_project_sequencing_center" => "Sequencing Center",
277 "genome_project_sequenced_accessions" => "Accession",
278 "genome_project_dates" => "Project start, end",
279 "genome_project_funding_agencies" => "Funding Agencies",
280 "genome_project_url" => "Project URL",
281 "genome_project_genbank_link" => "Genbank link",
282 "genome_project_contact_person" => "Contact (name, email)",
283 "genome_project_seed_source" => "Seed source",
288 sub get_organism_metadata_props {
289 my ( $self, $c ) = @_;
291 my $props = $c->stash->{organism}
292 ->search_related('organismprops',
293 { 'type.name' => 'organism_sequencing_metadata' },
294 { join => 'type', prefetch => 'type' },
297 return map
298 { +{ organismprop_id => $_->organismprop_id, json => $_->value, name => $_->type->name } }
299 $props->all;
303 =head2 verify_name
305 Public Path: /organism/verify_name
307 Verifies that a species name exists in the database. Returns false if the species name is not found.
309 =cut
311 sub verify_name :Path('/organism/verify_name') :ActionClass('REST') {}
313 sub verify_name_GET :Args(0) {
314 my ( $self, $c ) = @_;
315 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
316 my $species_name = $c->req->param('species_name');
317 my $organism;
318 $organism = $schema->resultset("Organism::Organism")->find({species => $species_name});
319 if (!$organism) {
320 $c->stash->{rest} = {error => "Species name $species_name not found." };
321 return;
323 else {
324 $c->stash->{rest} = {success => "1",};