seedlot upload with accession synonyms. seedlot upload works to update existing seedlots
[sgn.git] / lib / SGN / Controller / AJAX / Organism.pm
blobedcd5e7635b5855b1a13a3ea0cb97646c2d11f85
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 URI::Encode;
7 use Data::Dumper;
9 BEGIN { extends 'Catalyst::Controller::REST' }
12 __PACKAGE__->config(
13 default => 'application/json',
14 stash_key => 'rest',
15 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
19 =head2 autocomplete
21 Public Path: /organism/autocomplete
23 Autocomplete an organism species name. Takes a single GET param,
24 C<term>, responds with a JSON array of completions for that term.
26 =cut
28 sub autocomplete :Path('/organism/autocomplete') :ActionClass('REST') {}
30 sub autocomplete_GET :Args(0) {
31 my ( $self, $c ) = @_;
33 my $term = $c->req->param('term');
35 # trim and regularize whitespace
36 $term =~ s/(^\s+|\s+)$//g;
37 $term =~ s/\s+/ /g;
39 my $s = $c->dbic_schema('Bio::Chado::Schema','sgn_chado')
40 ->resultset('Organism::Organism');
42 my @results = $s->search({ species => { ilike => '%'.$term.'%' }},
43 { rows => 15 },
45 ->get_column('species')
46 ->all;
48 $c->stash->{rest} = \@results;
53 =head2 project_metadata
55 Usage: Action to update metadata information about sequencing
56 projects
57 Desc: Stores the sequencing metadata for each accession in an
58 organismprop, using a JSON data structure for storing the
59 different fields.
60 Side Effects: stores/updates/deletes metadata information
62 =cut
64 sub project_metadata :Chained('/organism/find_organism') :PathPart('metadata') :Args(0) {
65 my $self = shift;
66 my $c = shift;
68 my $action = $c->req->param('action');
70 #object id is a combination of prop_id and organism_id, separated by a "-"
71 my $organism = $c->stash->{organism};
72 my ($prop_id, undef) = split "-", $c->req->param('object_id') || '';
73 my $organism_id = $organism->organism_id;
74 my $login_user_id = 0;
75 my $login_user_can_modify = 0;
77 $c->stash->{json} = JSON::Any->new();
79 if($c->user()) {
80 $login_user_id = $c->user()->get_object()->get_sp_person_id();
81 $login_user_can_modify = any { $_ =~ /curator|sequencer|submitter/i } ($c->user()->roles());
84 # 1. get all the props associated with the organism
85 # 2. if it is a view, render them all
86 # 3. if it is an edit, render them, but render the selected prop_id as an editable
87 # 4. if it is a store, store the selected prop_id, display everything as static
88 # 5. if it is a delete, delete the selected prop_id, display everthing as static
90 my $form;
91 my $html = "";
93 if (!$action) { $action = 'view'; }
94 if ($login_user_can_modify && ($action ne 'view')) {
95 if (!$login_user_id) {
96 $self->status_bad_request( $c, message => 'Must be logged in to edit' );
97 return;
99 if ($action eq 'confirm_delete') {
100 $organism->search_related('organismprops',{ organismprop_id=>$prop_id })->delete;
103 if ($action eq 'store') {
104 my $props = $c->req->parameters();
105 my %props = $self->project_metadata_prop_list();
106 my $store_props = {};
107 foreach my $p (keys(%props )) {
108 $store_props->{$p}=$props->{$p};
110 my $json = $c->stash->{json}->objToJson($store_props);
112 $form = $self->metadata_form($c, $json, $prop_id, $organism_id);
114 $form->process($c->req());
116 if ($form->submitted_and_valid()) {
117 if ($prop_id) {
118 my $prop = $organism->find_related( 'organismprops', {
119 organismprop_id => $prop_id,
121 unless( $prop ) {
122 $self->status_bad_request(
123 $c, message =>
124 'no such organismprop',
126 return;
128 $prop->update({ value => $json });
130 else {
131 $organism->create_organismprops(
132 { 'organism_sequencing_metadata' => $json },
133 { autocreate => 1,
134 cv_name => 'local',
135 definitions => { organism_sequencing_metadata => "metadata about this organism's sequencing status" },
139 $c->forward('/organism/invalidate_organism_tree_cache');
141 else {
142 $self->status_bad_request( $c, message => 'Form is not valid' );
143 return;
148 my @proplist = $self->get_organism_metadata_props( $c );
150 foreach my $p (@proplist) {
152 if (exists($p->{organismprop_id}) && defined $prop_id && $prop_id eq $p->{organismprop_id} && $action eq "edit") {
153 if ($login_user_can_modify) {
154 #make the form editable
155 $form = $self->metadata_form($c, $p->{json}, $prop_id, $organism_id);
156 $html .= $form->render();
157 $html .= "<hr />\n";
160 else {
161 $html .= $self->metadata_static($c, $p->{json});
162 $html .= "<hr />\n";
165 if ($login_user_can_modify) {
166 # add appropriate edit and delete links
167 $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 />";
172 if ($login_user_can_modify && $action eq 'new') {
173 $form = $self->metadata_form($c, undef, undef, $organism_id);
174 $html .= $form->render();
175 $html .= qq | <br /><a href="javascript:organismObjectName.render();">Cancel</a><br /><br /> | ;
177 elsif ($login_user_can_modify) {
178 $html .= "<br /><a href=\"javascript:organismObjectName.setObjectId('-$organism_id' ); organismObjectName.printForm('new');\">New</a>";
181 if ( $action eq 'new' || $action eq 'view' || !$action || !$login_user_can_modify) {
182 $self->status_ok(
184 entity => { login_user_id => $login_user_id,
185 editable_form_id => 'organism_project_metadata_form',
186 is_owner => $login_user_can_modify,
187 html => $html,
191 elsif ($action eq 'store') {
192 $self->status_ok( $c, entity => [ 'success' ] );
195 else {
197 ### get project metadata information for that organism
198 $self->status_ok( $c, entity => {
199 login_user_id => $login_user_id,
200 editable_form_id => 'organism_project_metadata_form',
201 is_owner => $login_user_can_modify,
202 html => $html,
207 sub metadata_form {
208 my ($self, $c, $json, $prop_id, $organism_id) = @_;
210 my $data = {};
211 if ($json) {
212 #print STDERR "CONVERTING JSON...\n";
213 $data = $c->stash->{json}->jsonToObj($json); }
214 else {
215 #print STDERR "No JSON data provided...\n";
219 my $object_id = ($prop_id || '')."-".$organism_id;
220 my $form = HTML::FormFu->new(Load(<<YAML));
221 method: POST
222 attributes:
223 name: organism_project_metadata_form
224 id: organism_project_metadata_form
225 elements:
226 - type: Hidden
227 name: action
228 value: store
229 - type: Hidden
230 name: object_id
231 value: $object_id
232 YAML
236 my %fields = $self->project_metadata_prop_list();
238 foreach my $k (keys %fields) {
240 $form->element( { type=>'Text', name=>$k, label=>$fields{$k}, value=>$data->{$k}, size=>30 });
244 return $form;
247 sub metadata_static {
248 my $self = shift;
249 my $c = shift;
250 my $json = shift;
252 if (!$json) { return; }
254 my %props = %{$c->{stash}->{json}->jsonToObj($json)};
256 my %fields = $self->project_metadata_prop_list();
258 my $static = '<table>';
260 foreach my $k (keys %fields) {
261 no warnings 'uninitialized';
262 $static .= '<tr><td>'.$fields{$k}.'</td><td>&nbsp;</td><td><b>'.$props{$k}.'</b></td></tr>';
265 $static .= '</table>';
266 return $static;
270 =head2 project_metadata_prop_list()
272 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.
274 =cut
276 sub project_metadata_prop_list {
277 return ("genome_project_sequencing_center" => "Sequencing Center",
278 "genome_project_sequenced_accessions" => "Accession",
279 "genome_project_dates" => "Project start, end",
280 "genome_project_funding_agencies" => "Funding Agencies",
281 "genome_project_url" => "Project URL",
282 "genome_project_genbank_link" => "Genbank link",
283 "genome_project_contact_person" => "Contact (name, email)",
284 "genome_project_seed_source" => "Seed source",
289 sub get_organism_metadata_props {
290 my ( $self, $c ) = @_;
292 my $props = $c->stash->{organism}
293 ->search_related('organismprops',
294 { 'type.name' => 'organism_sequencing_metadata' },
295 { join => 'type', prefetch => 'type' },
298 return map
299 { +{ organismprop_id => $_->organismprop_id, json => $_->value, name => $_->type->name } }
300 $props->all;
304 =head2 verify_name
306 Public Path: /organism/verify_name
308 Verifies that a species name exists in the database. Returns false if the species name is not found.
310 =cut
312 sub verify_name :Path('/organism/verify_name') :ActionClass('REST') {}
314 sub verify_name_GET :Args(0) {
315 my ( $self, $c ) = @_;
316 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
317 my $uri = URI::Encode->new();
318 my $species_name = $uri->decode($c->req->param('species_name'));
319 my $organism;
320 $organism = $schema->resultset("Organism::Organism")->find({species => $species_name});
321 if (!$organism) {
322 $c->stash->{rest} = {error => "Species name $species_name not found." };
323 return;
325 else {
326 $c->stash->{rest} = {success => "1",};