LP#1849212: (follow-up) avoid open-ils.courses drone starvation
[Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Courses.pm
1 package OpenILS::Application::Courses;
2
3 use strict;
4 use warnings;
5
6 use OpenSRF::AppSession;
7 use OpenILS::Application;
8 use base qw/OpenILS::Application/;
9
10 use OpenILS::Utils::CStoreEditor qw/:funcs/;
11 use OpenILS::Utils::Fieldmapper;
12 use OpenILS::Application::AppUtils;
13 my $U = "OpenILS::Application::AppUtils";
14
15 use OpenSRF::Utils::Logger qw/$logger/;
16
17 __PACKAGE__->register_method(
18     method          => 'attach_electronic_resource_to_course',
19     api_name        => 'open-ils.courses.attach.electronic_resource',
20     signature => {
21         desc => 'Attaches a bib record for an electronic resource to a course',
22         params => [
23             {desc => 'Authentication token', type => 'string'},
24             {desc => 'Record id', type => 'number'},
25             {desc => 'Course id', type => 'number'},
26             {desc => 'Relationship', type => 'string'}
27         ],
28         return => {desc => '1 on success, event on failure'}
29     });
30 sub attach_electronic_resource_to_course {
31     my ($self, $conn, $authtoken, $record, $course, $relationship) = @_;
32     my $e = new_editor(authtoken=>$authtoken, xact=>1);
33     return $e->die_event unless $e->checkauth;
34     return $e->die_event unless
35         $e->allowed('MANAGE_RESERVES');
36
37     my $located_uris = $e->search_asset_call_number({
38         record => $record,
39         deleted => 'f',
40         label => '##URI##' })->[0];
41     my $bib = $e->retrieve_biblio_record_entry([
42         $record, {
43             flesh => 1,
44             flesh_fields => {'bre' => ['source']}
45         }
46     ]);
47     return $e->event unless (($bib->source && $bib->source->transcendant) || $located_uris);
48     _attach_bib($e, $course, $record, $relationship, 0);
49
50     return 1;
51 }
52
53 __PACKAGE__->register_method(
54     method          => 'attach_brief_bib_to_course',
55     api_name        => 'open-ils.courses.attach.biblio_record',
56     signature => {
57         desc => 'Creates a new bib record with the provided XML, and attaches it to a course',
58         params => [
59             {desc => 'Authentication token', type => 'string'},
60             {desc => 'XML', type => 'string'},
61             {desc => 'Course id', type => 'number'},
62             {desc => 'Relationship', type => 'string'}
63         ],
64         return => {desc => '1 on success, event on failure'}
65     });
66 sub attach_brief_bib_to_course {
67     my ($self, $conn, $authtoken, $marcxml, $course, $relationship) = @_;
68     my $e = new_editor(authtoken=>$authtoken, xact=>1);
69     return $e->die_event unless $e->checkauth;
70     return $e->die_event unless $e->allowed('MANAGE_RESERVES');
71     return $e->die_event unless $e->allowed('CREATE_MARC');
72
73     my $bib_source_id = $U->ou_ancestor_setting_value($self->{ou}, 'circ.course_materials_brief_record_bib_source');
74     my $bib_source_name;
75     if ($bib_source_id) {
76         $bib_source_name = $e->retrieve_config_bib_source($bib_source_id)->source;
77     } else {
78         # The default value from the seed data
79         $bib_source_name = 'Course materials module';
80     }
81
82     my $bib_create = OpenSRF::AppSession
83         ->create('open-ils.cat')
84         ->request('open-ils.cat.biblio.record.xml.create',
85             $authtoken, $marcxml, $bib_source_name)
86         ->gather(1);
87     _attach_bib($e, $course, $bib_create->id, $relationship, 1) if ($bib_create);
88     return 1;
89 }
90
91 # Shared logic for both e-resources and brief bibs
92 sub _attach_bib {
93     my ($e, $course, $record, $relationship, $temporary) = @_;
94     my $acmcm = Fieldmapper::asset::course_module_course_materials->new;
95     $acmcm->course($course);
96     $acmcm->record($record);
97     $acmcm->relationship($relationship);
98     $acmcm->temporary_record($temporary);
99     $e->create_asset_course_module_course_materials( $acmcm ) or return $e->die_event;
100     $e->commit;
101 }
102
103 __PACKAGE__->register_method(
104     method          => 'fetch_course_materials',
105     autoritative    => 1,
106     stream          => 1,
107     api_name        => 'open-ils.courses.course_materials.retrieve',
108     signature       => q/
109         Returns an array of course materials.
110         @params args     : Supplied object to filter search.
111     /);
112
113 __PACKAGE__->register_method(
114     method          => 'fetch_course_materials',
115     autoritative    => 1,
116     stream          => 1,
117     api_name        => 'open-ils.courses.course_materials.retrieve.fleshed',
118     signature       => q/
119         Returns an array of course materials, each fleshed out with information
120         from the item and the course_material object.
121         @params args     : Supplied object to filter search.
122     /);
123
124 sub fetch_course_materials {
125     my ($self, $conn, $args) = @_;
126     my $e = new_editor();
127     my $materials;
128
129     if ($self->api_name =~ /\.fleshed/) {
130         my $fleshing = {
131             'flesh' => 2, 'flesh_fields' => {
132                 'acmcm' => ['item', 'record', 'original_circ_modifier',
133                     'original_location', 'original_status'],
134                 'acp' => ['call_number', 'circ_lib', 'location', 'status'],
135                 'bre' => ['wide_display_entry'],
136             }
137         };
138         $materials = $e->search_asset_course_module_course_materials([$args, $fleshing]);
139     } else {
140         $materials = $e->search_asset_course_module_course_materials($args);
141     }
142     $conn->respond($_) for @$materials;
143     $conn->respond_complete();
144     return undef;
145 }
146
147 __PACKAGE__->register_method(
148     method          => 'fetch_courses',
149     autoritative    => 1,
150     api_name        => 'open-ils.courses.courses.retrieve',
151     signature       => q/
152         Returns an array of course materials.
153         @params course_id: The id of the course we want to retrieve
154     /);
155
156 sub fetch_courses {
157     my ($self, $conn, @course_ids) = @_;
158     my $e = new_editor();
159
160     return unless @course_ids;
161     my $targets = ();
162     foreach my $course_id (@course_ids) {
163         my $target = $e->retrieve_asset_course_module_course($course_id);
164         push @$targets, $target;
165     }
166
167     return $targets;
168 }
169
170 __PACKAGE__->register_method(
171     method          => 'fetch_course_users',
172     autoritative    => 1,
173     api_name        => 'open-ils.courses.course_users.retrieve',
174     signature       => q/
175         Returns an array of course users.
176         @params course_id: The id of the course we want to retrieve from
177     /);
178 __PACKAGE__->register_method(
179     method          => 'fetch_course_users',
180     autoritative    => 1,
181     api_name        => 'open-ils.courses.course_users.retrieve.staff',
182     signature       => q/
183         Returns an array of course users.
184         @params course_id: The id of the course we want to retrieve from
185     /);
186
187 sub fetch_course_users {
188     my ($self, $conn, $course_id) = @_;
189     my $e = new_editor();
190
191     return $e->json_query({
192         select => {
193             acmcu => ['id'],
194             acmr => [{column => 'name', alias => 'usr_role'}],
195             au => [{column => 'id', alias => 'patron_id'},
196                 'first_given_name', 'second_given_name',
197                 'family_name', 'pref_first_given_name',
198                 'pref_second_given_name', 'pref_family_name',
199                 'pref_suffix', 'pref_prefix'],
200         },
201         from => { acmcu => {'acmr' => {}, 'au' => {}} },
202         where => {
203             '+acmcu' => { course => $course_id },
204             '+acmr' => {'is_public' => 't'}
205         },
206     });
207
208 }
209
210 __PACKAGE__->register_method(
211     method          => 'detach_material',
212     api_name        => 'open-ils.courses.detach_material',
213     signature => {
214         desc => 'Detaches a material from a course',
215         params => [
216             {desc => 'Authentication token', type => 'string'},
217             {desc => 'Course material id', type => 'number'},
218         ],
219         return => {desc => '1 on success, event on failure'}
220     });
221 sub detach_material {
222     my ($self, $conn, $authtoken, $acmcm_id) = @_;
223     my $e = new_editor(authtoken=>$authtoken, xact=>1);
224     return $e->die_event unless $e->checkauth;
225     return $e->die_event unless
226         $e->allowed('MANAGE_RESERVES');
227     my $acmcm = $e->retrieve_asset_course_module_course_materials($acmcm_id)
228         or return $e->die_event;
229     my $bre_id_to_delete = $acmcm->temporary_record ? $acmcm->record : 0;
230     if ($bre_id_to_delete) {
231         # delete any attached located URIs
232         my $located_uri_cn_ids = $e->search_asset_call_number(
233             {record=>$bre_id_to_delete}, {idlist=>1});
234
235         for my $cn_id (@$located_uri_cn_ids) {
236             $e->delete_asset_call_number(
237                 $e->retrieve_asset_call_number($cn_id))
238                 or return $e->die_event;
239         }
240         OpenSRF::AppSession
241             ->create('open-ils.cat')
242             ->request('open-ils.cat.biblio.record_entry.delete',
243                 $authtoken, $bre_id_to_delete);
244     }
245     if ($acmcm->item) {
246         _resetItemFields($e, $authtoken, $acmcm);
247     } 
248
249     $e->delete_asset_course_module_course_materials($acmcm) or return $e->die_event;
250     $e->commit;
251     return 1;
252 }
253
254 sub _resetItemFields {
255     my ($e, $authtoken, $acmcm) = @_;
256     my $cat_sess = OpenSRF::AppSession->connect('open-ils.cat');
257     my $acp = $e->retrieve_asset_copy($acmcm->item);
258     my $course_lib = $e->retrieve_asset_course_module_course($acmcm->course)->owning_lib;
259     if ($acmcm->original_status) {
260         $acp->status($acmcm->orginal_status);
261     }
262     if ($acmcm->original_circ_modifier) {
263         $acp->status($acmcm->orginal_circ_modifier);
264     }
265     if ($acmcm->original_location) {
266         $acp->status($acmcm->orginal_location);
267     }
268     $e->update_asset_copy($acmcm);
269     if ($acmcm->original_callnumber) {
270         my $existing_acn = $e->retrieve_asset_call_number($acp->call_number);
271         # Let's attach to an existing call number, if one exists with the original label
272         # and other appropriate specifications
273         my $acn_id = cat_sess->request('open-ils.cat.call_number.find_or_create',
274             $authtoken, $acmcm->original_callnumber,
275             $existing_acn->record, $course_lib,
276             $existing_acn->prefix, $existing_acn->suffix,
277             $existing_acn->label_class)->acn_id;
278         cat_sess->request('open-ils.cat.transfer_copies_to_volume',
279             $authtoken, $acn_id, [$acp->id]);
280     }
281 }
282
283
284
285 1;
286