From 81a68b8893136f282cf6daa5f62a66ec35dd19af Mon Sep 17 00:00:00 2001 From: Dean Keeble Date: Tue, 3 Sep 2024 09:19:55 +0100 Subject: [PATCH 1/8] LIMS-1432: Add shelxt downstream view (#818) * add first attempt at shelx downstream view * populate model with parseable empty value * handle there being no file * tidy up the pasta * replace dimple specifics in html * add pdb file for ulgymol view * remove cruft * add the parent info to the shelxt model * bonus fix of apstatus not handling multiple results for sm * Apply suggestion: use ' rather than escaping " in query strings Co-authored-by: Mark W <24956497+ndg63276@users.noreply.github.com> * improve logic when file path is missing Co-authored-by: Mark W <24956497+ndg63276@users.noreply.github.com> * just return the answer Co-authored-by: Mark W <24956497+ndg63276@users.noreply.github.com> * replace `print` with - Co-authored-by: Mark W <24956497+ndg63276@users.noreply.github.com> * use in_array for checking if a key is in an array Co-authored-by: Mark W <24956497+ndg63276@users.noreply.github.com> * parentheses come in pairs * only try to plot maps if the plugin says it has maps --------- Co-authored-by: Mark W <24956497+ndg63276@users.noreply.github.com> --- api/src/Downstream/Type/Shelxt.php | 91 +++++++++++++++++++ client/src/js/modules/dc/views/downstream.js | 4 +- .../src/js/modules/dc/views/mapmodelview.js | 6 +- client/src/js/modules/dc/views/shelxt.js | 44 +++++++++ .../modules/types/sm/dc/views/apstatusitem.js | 25 +++-- client/src/js/templates/dc/dc_shelxt.html | 32 +++++++ 6 files changed, 192 insertions(+), 10 deletions(-) create mode 100644 api/src/Downstream/Type/Shelxt.php create mode 100644 client/src/js/modules/dc/views/shelxt.js create mode 100644 client/src/js/templates/dc/dc_shelxt.html diff --git a/api/src/Downstream/Type/Shelxt.php b/api/src/Downstream/Type/Shelxt.php new file mode 100644 index 000000000..466a6392b --- /dev/null +++ b/api/src/Downstream/Type/Shelxt.php @@ -0,0 +1,91 @@ +autoprocprogramid); + $filepath = $this->db->pq( + "SELECT app.filePath from autoprocprogramattachment app where autoprocprogramid = :1 and filename = 'shelxt_results.json' ", + $appid + ); + return $filepath; + } + + function _get_shelxt_results_png() { + $appid = array($this->autoprocprogramid); + $filepath = $this->db->pq( + "SELECT app.filepath, app.filename from autoprocprogramattachment app where autoprocprogramid = :1 and filename like '%.png%' ", + $appid + ); + return $filepath; + } + + function _get_pdb() { + $appid = array($this->autoprocprogramid); + $filepath = $this->db->pq( + "SELECT app.filepath, app.filename from autoprocprogramattachment app where autoprocprogramid = :1 and filename like '%.pdb%' ", + $appid + ); + if (sizeof($filepath)) { + return $filepath[0]["FILEPATH"] . "/" . $filepath[0]["FILENAME"]; + } else { + return; + } + } + + function results() { + $json_filepath = $this->_get_shelxt_results_json(); + if (sizeof($json_filepath)) { + $json_path = $json_filepath[0]["FILEPATH"] . "/shelxt_results.json" ; + $json_data = file_get_contents($json_path); + } else { + $json_data = "[]"; + } + $dat = array(); + $dat['BLOBS'] = 1; + $dat['SOLUTIONS'] = json_decode($json_data); + + // scaling_id should always be present, but just in case... + if (in_array('scaling_id', $this->process['PARAMETERS'])) { + $integrator = $this->_lookup_autoproc( + null, + $this->process['PARAMETERS']['scaling_id'] + ); + if ($integrator) { + $dat['PARENTAUTOPROCPROGRAM'] = $integrator['PROCESSINGPROGRAMS']; + $dat['PARENTAUTOPROCPROGRAMID'] = $integrator['AUTOPROCPROGRAMID']; + } + } + $results = new DownstreamResult($this); + $results->data = $dat; + + return $results; + } + + function images($n = 0) { + $png = $this->_get_shelxt_results_png(); + if (sizeof($png)) { + return $png[0]["FILEPATH"] . "/" . $png[0]["FILENAME"]; + } else { + return; + } + + } + + function mapmodel($n = 0, $map = false) { + $pdb = $this->_get_pdb(); + if (!$pdb) { + return; + } else { + return $pdb; + } + } +} diff --git a/client/src/js/modules/dc/views/downstream.js b/client/src/js/modules/dc/views/downstream.js index 5d0faf538..eb8d8e858 100644 --- a/client/src/js/modules/dc/views/downstream.js +++ b/client/src/js/modules/dc/views/downstream.js @@ -7,11 +7,12 @@ define(['backbone', 'marionette', 'modules/dc/views/dimple', 'modules/dc/views/mrbump', 'modules/dc/views/bigep', + 'modules/dc/views/shelxt', 'templates/dc/downstreamerror.html' ], function(Backbone, Marionette, TabView, DownStreams, DownstreamWrapper, TableView, - FastEP, DIMPLE, MrBUMP, BigEP, downstreamerror) { + FastEP, DIMPLE, MrBUMP, BigEP, Shelxt, downstreamerror) { var DownstreamsCollection = Backbone.Collection.extend() @@ -61,6 +62,7 @@ define(['backbone', 'marionette', 'Autobuild': BigEP, 'Crank2': BigEP, 'AutoSHARP': BigEP, + 'Shelxt': Shelxt, } if (model.get('PROCESS').PROCESSINGSTATUS != 1) { diff --git a/client/src/js/modules/dc/views/mapmodelview.js b/client/src/js/modules/dc/views/mapmodelview.js index 949ff0052..595135562 100644 --- a/client/src/js/modules/dc/views/mapmodelview.js +++ b/client/src/js/modules/dc/views/mapmodelview.js @@ -33,7 +33,9 @@ define(['marionette', loadMaps: function() { this.mapsToLoad = this.downstream.get('FEATURES').MAPMODEL[1]; this.mapsLoaded = 0 - this.doLoadMaps(1, this.onMapsLoaded.bind(this)) + if (this.mapsToLoad > 0) { + this.doLoadMaps(1, this.onMapsLoaded.bind(this)) + } }, @@ -167,4 +169,4 @@ define(['marionette', -}) \ No newline at end of file +}) diff --git a/client/src/js/modules/dc/views/shelxt.js b/client/src/js/modules/dc/views/shelxt.js new file mode 100644 index 000000000..0689acdb8 --- /dev/null +++ b/client/src/js/modules/dc/views/shelxt.js @@ -0,0 +1,44 @@ +define([ + 'marionette', 'templates/dc/dc_shelxt.html', 'utils', 'utils/xhrimage', 'jquery.mp' +], function(Marionette, template, utils, XHRImage) { + + return Marionette.ItemView.extend({ + template: template, + className: 'clearfix', + + ui: { + solutions: '.solutions', + blob: '.blobs img', + blobs: '.blobs', + }, + + showBlob: function() { + this.ui.blob.attr('src', this.blob.src).show() + this.ui.blobs.addClass('loaded').removeClass('pending') + }, + + onDomRefresh: function() { + this.ui.blobs.magnificPopup({ + delegate: 'a', type: 'image', + gallery: { + enabled: true, + navigateByImgClick: true, + } + }) + + this.ui.blob.hide() + if (this.model.get('BLOBS') > 0) { + this.blob = new XHRImage() + this.blob.onload = this.showBlob.bind(this) + this.ui.blobs.addClass('pending') + this.blob.load(app.apiurl+'/processing/downstream/images/'+this.model.get('AID')) + } + + if (!app.mobile()) { + this.ui.solutions.width(0.47*(this.options.holderWidth-14)) + } + }, + + }) + +}) diff --git a/client/src/js/modules/types/sm/dc/views/apstatusitem.js b/client/src/js/modules/types/sm/dc/views/apstatusitem.js index 9a70f5650..b87f2ebdf 100644 --- a/client/src/js/modules/types/sm/dc/views/apstatusitem.js +++ b/client/src/js/modules/types/sm/dc/views/apstatusitem.js @@ -9,14 +9,25 @@ define(['modules/dc/views/apstatusitem'], function(APStatusItem) { '', ''] - _.each(['autoproc','downstream'], function(ty, id) { - this.ui.holder.eq(id).empty() - _.each(res[ty], function(ap, n) { - if(ap != 0) - this.ui.holder.eq(id).append(n+' '+val[ap]+' ') - }, this) + _.each({ap: 'autoproc',dp: 'downstream'}, function(ty, id) { + this.ui[id].empty() + var allResults = [] + if (res[ty]) { + _.each(res[ty], function(ap, n) { + var ress = {} + _.each(ap, function(a) { + if (!(a in ress)) ress[a] = 0 + ress[a]++ + }) + allResults.push(n+': '+_.map(ress, function(c, st) { return c > 1 ? ''+c+'x '+val[st] : val[st]}).join(' ')) + }, this) + + this.ui[id].append(allResults.join('|')) + } else { + this.ui[id].append('No processing results') + } }, this) }, }) -}) \ No newline at end of file +}) diff --git a/client/src/js/templates/dc/dc_shelxt.html b/client/src/js/templates/dc/dc_shelxt.html new file mode 100644 index 000000000..a94d5a516 --- /dev/null +++ b/client/src/js/templates/dc/dc_shelxt.html @@ -0,0 +1,32 @@ +
+
+ <% _.each(_.range(BLOBS), function(i) { %> + + <% if (i == 0) { %> + Solution 1 + <% } %> + + <% }) %> + +
+ + + <% if (SOLUTIONS.length) { %> + <% _.each(SOLUTIONS, function(r, i) { %> + + <% _.each(r, function(j) { %> + + <% }) %> + + <% }) %> + <% } else { %> + + + + + + + <% } %> +
<%-j%>
Solutions
No Solutions Found
+ +
From b3e23620848a6ccbfe5380b7d318a09c9fd09188 Mon Sep 17 00:00:00 2001 From: Guilherme Francisco Date: Tue, 3 Sep 2024 09:20:15 +0100 Subject: [PATCH 2/8] LIMS-1436: Use auth provider provided logout URL when SSO is enabled (#822) * Make OIDC auth type more generic * Remove mention of CAS in redirect message * Redirect to upstream provider for logout --- .../Authentication/AuthenticationParent.php | 2 ++ api/src/Authentication/Type/CAS.php | 5 ++++ api/src/Authentication/Type/Combined.php | 5 ++++ api/src/Authentication/Type/Dummy.php | 5 ++++ api/src/Authentication/Type/LDAP.php | 5 ++++ api/src/Authentication/Type/OIDC.php | 5 ++++ api/src/Authentication/Type/Simple.php | 5 ++++ .../Controllers/AuthenticationController.php | 29 ++++++++++++------- client/src/js/app/components/header.vue | 2 +- client/src/js/app/router/router.js | 7 ----- client/src/js/app/store/modules/store.auth.js | 28 +++++------------- client/src/js/app/views/login.vue | 2 +- client/src/js/app/views/logout.vue | 28 ------------------ 13 files changed, 59 insertions(+), 69 deletions(-) delete mode 100644 client/src/js/app/views/logout.vue diff --git a/api/src/Authentication/AuthenticationParent.php b/api/src/Authentication/AuthenticationParent.php index 559051d10..c7262512e 100644 --- a/api/src/Authentication/AuthenticationParent.php +++ b/api/src/Authentication/AuthenticationParent.php @@ -16,4 +16,6 @@ public function check(); public function authorise(); public function authenticateByCode($code); + + public function logout(); } \ No newline at end of file diff --git a/api/src/Authentication/Type/CAS.php b/api/src/Authentication/Type/CAS.php index e7b24d2e7..0160dbe63 100644 --- a/api/src/Authentication/Type/CAS.php +++ b/api/src/Authentication/Type/CAS.php @@ -122,5 +122,10 @@ function validate($service, $ticket) return rtrim($resp); } + + function logout() + { + return false; + } } diff --git a/api/src/Authentication/Type/Combined.php b/api/src/Authentication/Type/Combined.php index 7a0fe7386..0a957a869 100644 --- a/api/src/Authentication/Type/Combined.php +++ b/api/src/Authentication/Type/Combined.php @@ -36,4 +36,9 @@ public function authorise() { public function authenticateByCode($code){ return $this->OIDCAuth->authenticateByCode($code); } + + public function logout() + { + return $this->OIDCAuth->logout(); + } } diff --git a/api/src/Authentication/Type/Dummy.php b/api/src/Authentication/Type/Dummy.php index d5878e9bb..2d53c0520 100644 --- a/api/src/Authentication/Type/Dummy.php +++ b/api/src/Authentication/Type/Dummy.php @@ -26,4 +26,9 @@ function authenticate($login, $password) { return true; } + + function logout() + { + return false; + } } diff --git a/api/src/Authentication/Type/LDAP.php b/api/src/Authentication/Type/LDAP.php index 669e92120..a727afc97 100644 --- a/api/src/Authentication/Type/LDAP.php +++ b/api/src/Authentication/Type/LDAP.php @@ -66,4 +66,9 @@ function authenticate($login, $password) } } } + + function logout() + { + return false; + } } diff --git a/api/src/Authentication/Type/OIDC.php b/api/src/Authentication/Type/OIDC.php index c4ea2fcba..9b844a2a9 100644 --- a/api/src/Authentication/Type/OIDC.php +++ b/api/src/Authentication/Type/OIDC.php @@ -135,4 +135,9 @@ function authenticateByCode($code) setcookie($cookie_key, $token, $cookieOpts); return $this->getUser($token); } + + function logout() + { + return $this->getProviderConfig()->end_session_endpoint; + } } diff --git a/api/src/Authentication/Type/Simple.php b/api/src/Authentication/Type/Simple.php index 6a355946c..c1e73de78 100644 --- a/api/src/Authentication/Type/Simple.php +++ b/api/src/Authentication/Type/Simple.php @@ -22,6 +22,11 @@ function check() return false; } + function logout() + { + return false; + } + function authenticate($login, $password) { $person = $this->db->pq("SELECT password FROM person WHERE login=:1", array($login)); diff --git a/api/src/Controllers/AuthenticationController.php b/api/src/Controllers/AuthenticationController.php index 0d9aef954..f6062657a 100644 --- a/api/src/Controllers/AuthenticationController.php +++ b/api/src/Controllers/AuthenticationController.php @@ -391,17 +391,24 @@ function authenticateByCode() // Logout function logout() { - global $cookie_key; - if (isset($_COOKIE[$cookie_key])) { - $cookieOpts = array ( - 'expires' => time() - 3600, - 'path' => '/', - 'secure' => true, - 'httponly' => true, - 'samesite' => 'Strict' - ); - - setcookie($cookie_key, null, $cookieOpts); + global $cookie_key, $cas_sso; + if($cas_sso) { + if (isset($_COOKIE[$cookie_key])) { + $cookieOpts = array ( + 'expires' => time() - 3600, + 'path' => '/', + 'secure' => true, + 'httponly' => true, + 'samesite' => 'Strict' + ); + + setcookie($cookie_key, null, $cookieOpts); + } + + header('Location: ' . $this->authenticateByType()->logout()); + $this->returnResponse(302, array('status' => "Redirecting to SSO provider")); + } else { + $this->returnError(501, "SSO not configured"); } } diff --git a/client/src/js/app/components/header.vue b/client/src/js/app/components/header.vue index c9d91de97..ac2758223 100644 --- a/client/src/js/app/components/header.vue +++ b/client/src/js/app/components/header.vue @@ -116,7 +116,7 @@ export default { this.$store.dispatch('auth/logout') .then(() => { if (this.sso) { - this.$router.push('/logout'); + window.location.assign(`${this.$store.getters.apiUrl}/authenticate/logout`); } else { this.$router.push('/'); } diff --git a/client/src/js/app/router/router.js b/client/src/js/app/router/router.js index b47f041cf..33ef36c22 100644 --- a/client/src/js/app/router/router.js +++ b/client/src/js/app/router/router.js @@ -15,7 +15,6 @@ import MarionetteApplication from 'app/marionette-application.js' import Home from 'app/views/home.vue' import Login from 'app/views/login.vue' -import Logout from 'app/views/logout.vue' import NotFound from 'app/views/notfound.vue' import NotAuthorised from 'app/views/notauthorised.vue' @@ -62,11 +61,6 @@ let routes = [ props: true, // this will mean redirect query also passed to login as prop component: Login, }, - { - path: '/logout', - name: 'logout', - component: Logout, - }, { path: '/notfound', alias: '/404', @@ -127,7 +121,6 @@ router.beforeEach((to, from, next) => { if (to.path === '/notfound') { next(); return } if (to.path === '/') { next(); return } if (to.path === '/login') { next(); return } - if (to.path === '/logout') { next(); return } // Make sure the store is initialised before proceeding further const init = store.dispatch('initialise') diff --git a/client/src/js/app/store/modules/store.auth.js b/client/src/js/app/store/modules/store.auth.js index aa125f8af..8c141106a 100644 --- a/client/src/js/app/store/modules/store.auth.js +++ b/client/src/js/app/store/modules/store.auth.js @@ -133,27 +133,13 @@ const auth = { }) }, - logout({commit, rootState}){ - return new Promise((resolve, reject) => { - // If sso need to call the logout URL - Backbone.ajax({ - url: rootState.apiUrl+'/authenticate/logout', - type: 'GET', - success: function() { - console.log("Logout successful") - commit('logout') - commit('proposal/setProposal', null, {root: true}) - commit('user/updateUser', {}, {root: true}) - resolve() - }, - error: function() { - // Even if an error we can set our local properties to logged out - console.log("Error returned from logout URL") - commit('logout') - commit('proposal/setProposal', null, {root: true}) - commit('user/updateUser', {}, {root: true}) - reject() - }}) + logout({commit}){ + return new Promise((resolve) => { + console.log("Logout successful") + commit('logout') + commit('proposal/setProposal', null, {root: true}) + commit('user/updateUser', {}, {root: true}) + resolve() }) }, }, diff --git a/client/src/js/app/views/login.vue b/client/src/js/app/views/login.vue index 58f4bf8d5..a30993499 100644 --- a/client/src/js/app/views/login.vue +++ b/client/src/js/app/views/login.vue @@ -127,7 +127,7 @@ export default { return this.$store.getters.apiUrl; }, logoutUrl: function () { - return `https://${this.$store.getters.sso_url}/logout`; + return `${this.$store.getters.apiUrl}/authenticate/logout`; }, }, diff --git a/client/src/js/app/views/logout.vue b/client/src/js/app/views/logout.vue deleted file mode 100644 index f648bb4c6..000000000 --- a/client/src/js/app/views/logout.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - From f11757dab99639cd2233e0e3fff62fc719a09174 Mon Sep 17 00:00:00 2001 From: Mark W <24956497+ndg63276@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:20:44 +0100 Subject: [PATCH 3/8] LIMS-1108: Improve message re international shipping (#721) Co-authored-by: Mark Williams --- api/config_sample.php | 2 ++ api/index.php | 3 ++- client/src/js/modules/shipment/views/shipment.js | 3 +++ client/src/js/templates/shipment/shipment.html | 6 ++++-- client/src/js/templates/shipment/shipmentadd.html | 4 +++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/api/config_sample.php b/api/config_sample.php index f75ece813..d38e2f0c1 100644 --- a/api/config_sample.php +++ b/api/config_sample.php @@ -239,6 +239,8 @@ $facility_courier_countries = array('United Kingdom'); // List of non dom eu free countries $facility_courier_countries_nde = array('France', 'Italy', 'Spain'); + // Link to help with international shipments + $facility_courier_countries_link = ''; $package_description = 'Dry shipper containing frozen crystals'; $dewar_weight = 18; diff --git a/api/index.php b/api/index.php index 4f884d58d..ace25a44c 100644 --- a/api/index.php +++ b/api/index.php @@ -68,7 +68,7 @@ function setupApplication($mode): Slim $app->get('/options', function () use ($app) { global $motd, $authentication_type, $cas_url, $cas_sso, $sso_url, $package_description, - $facility_courier_countries, $facility_courier_countries_nde, + $facility_courier_countries, $facility_courier_countries_nde, $facility_courier_countries_link, $dhl_enable, $scale_grid, $scale_grid_end_date, $preset_proposal, $timezone, $valid_components, $enabled_container_types, $ifsummary, $synchweb_version, $redirects, $shipping_service_app_url, $use_shipping_service_redirect, $use_shipping_service_redirect_incoming_shipments; @@ -83,6 +83,7 @@ function setupApplication($mode): Slim 'package_description' => $package_description, 'facility_courier_countries' => $facility_courier_countries, 'facility_courier_countries_nde' => $facility_courier_countries_nde, + 'facility_courier_countries_link' => $facility_courier_countries_link, 'dhl_enable' => $dhl_enable, 'scale_grid' => $scale_grid, 'scale_grid_end_date' => $scale_grid_end_date, diff --git a/client/src/js/modules/shipment/views/shipment.js b/client/src/js/modules/shipment/views/shipment.js index 7601d7d0e..6932f8645 100644 --- a/client/src/js/modules/shipment/views/shipment.js +++ b/client/src/js/modules/shipment/views/shipment.js @@ -43,6 +43,9 @@ define(['marionette', APIURL: app.apiurl, PROP: app.prop, DHL_ENABLE: app.options.get('dhl_enable'), + FACILITY_COURIER_COUNTRIES: app.options.get('facility_courier_countries'), + FACILITY_COURIER_COUNTRIES_NDE: app.options.get('facility_courier_countries_nde'), + FACILITY_COURIER_COUNTRIES_LINK: app.options.get('facility_courier_countries_link'), } }, diff --git a/client/src/js/templates/shipment/shipment.html b/client/src/js/templates/shipment/shipment.html index 6ee05bffb..a58058375 100644 --- a/client/src/js/templates/shipment/shipment.html +++ b/client/src/js/templates/shipment/shipment.html @@ -6,8 +6,10 @@

Shipment: <%-SHIPPI <% if (DHL_ENABLE) { %> <% if (DELIVERYAGENT_HAS_LABEL == '1') { %>

You can print your Air Waybill by clicking "Print Air Waybill" below

- <% } else if (COUNTRY && COUNTRY !="United Kingdom" ) { %> -

International shipping is currently disabled from this application. Please see here

+ <% } else if (COUNTRY && FACILITY_COURIER_COUNTRIES_NDE.includes(COUNTRY) ) { %> +

International shipping is not available through this application. If you're arranging your own shipping (e.g. industrial users), enter your tracking numbers below after booking and include printed return labels in the dewar case. European academic users, please see here.

+ <% } else if (COUNTRY && !FACILITY_COURIER_COUNTRIES.includes(COUNTRY) ) { %> +

International shipping is not available through this application. If you're arranging your own shipping, enter your tracking numbers below after booking and include printed return labels in the dewar case.

<% } else { %>

You can now book your shipment with DHL using "Create Air Waybill" below

<% } %> diff --git a/client/src/js/templates/shipment/shipmentadd.html b/client/src/js/templates/shipment/shipmentadd.html index 0860a72c9..3866fe012 100644 --- a/client/src/js/templates/shipment/shipmentadd.html +++ b/client/src/js/templates/shipment/shipmentadd.html @@ -2,7 +2,9 @@

Add New Shipment

-

Please note that international shipping is currently disabled from this application. Please see the link here

+<% if (FACILITY_COURIER_COUNTRIES_LINK) { %> +

Please note that international shipping is currently disabled from this application. Please see the link here.

+<% } %>
From 97d22afe060e0806b097bcd1e745683ffe55a3e8 Mon Sep 17 00:00:00 2001 From: Mark W <24956497+ndg63276@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:21:07 +0100 Subject: [PATCH 4/8] LIMS-1396: Use shipping service callback URL to only send emails once shipment is booked (#814) * LIMS-1396: Use shipping service callback URL to only send emails once shipment is booked * LIMS-1396: Update shipping status when updating dewar status --------- Co-authored-by: Mark Williams --- .../emails/html/dewar-dispatch-lite.html | 2 +- .../Controllers/AuthenticationController.php | 5 +- api/src/Page/Shipment.php | 203 ++++++++++++++---- .../js/modules/shipment/models/dispatch.js | 2 +- .../src/js/templates/shipment/dispatch.html | 10 +- 5 files changed, 168 insertions(+), 54 deletions(-) diff --git a/api/assets/emails/html/dewar-dispatch-lite.html b/api/assets/emails/html/dewar-dispatch-lite.html index ad3b16b2b..becda15da 100644 --- a/api/assets/emails/html/dewar-dispatch-lite.html +++ b/api/assets/emails/html/dewar-dispatch-lite.html @@ -1,4 +1,4 @@ -

Dewar ready to leave diamond

+

Dewar ready to leave Diamond

Goods Handling, please arrange dispatch of the following Dewar. diff --git a/api/src/Controllers/AuthenticationController.php b/api/src/Controllers/AuthenticationController.php index f6062657a..0db43e3f3 100644 --- a/api/src/Controllers/AuthenticationController.php +++ b/api/src/Controllers/AuthenticationController.php @@ -116,7 +116,10 @@ private function checkAuthRequiredForSpecificSituations($parts): bool ($parts[0] == 'shipment' && $parts[1] == 'containers' && $parts[2] == 'notify' && in_array($_SERVER["REMOTE_ADDR"], $auto)) || # Allow barcode reader ips unauthorised access to add container history - ($parts[0] == 'shipment' && $parts[1] == 'containers' && $parts[2] == 'history' && in_array($_SERVER["REMOTE_ADDR"], $bcr)) + ($parts[0] == 'shipment' && $parts[1] == 'containers' && $parts[2] == 'history' && in_array($_SERVER["REMOTE_ADDR"], $bcr)) || + + # Allow shipping service to update dewar status + ($parts[0] == 'shipment' && $parts[1] == 'dewars' && $parts[2] == 'confirmdispatch') ) { $need_auth = false; diff --git a/api/src/Page/Shipment.php b/api/src/Page/Shipment.php index 4e8ee5d25..6b3f16f4a 100644 --- a/api/src/Page/Shipment.php +++ b/api/src/Page/Shipment.php @@ -143,6 +143,9 @@ class Shipment extends Page 'CLOSETIME' => '\d\d:\d\d', 'PRODUCTCODE' => '\w', 'BEAMLINENAME' => '[\w\-]+', + 'TOKEN' => '\w+', + 'tracking_number' => '\w+', + 'AWBURL' => '[\w\:\/\.\-]+', 'manifest' => '\d', 'currentuser' => '\d', @@ -196,6 +199,7 @@ class Shipment extends Page array('/dewars/transfer', 'post', '_transfer_dewar'), array('/dewars/dispatch', 'post', '_dispatch_dewar'), + array('/dewars/confirmdispatch/did/:did/token/:TOKEN', 'post', '_dispatch_dewar_confirmation'), array('/dewars/tracking(/:DEWARID)', 'get', '_get_dewar_tracking'), @@ -986,7 +990,8 @@ function _create_dewars_shipment_request( array $dewars, string $proposal, int $external_id, - int $shipping_id + int $shipping_id, + string $callback_url="" ): int { $packages = []; @@ -1035,6 +1040,9 @@ function _create_dewars_shipment_request( "origin_url" => "{$protocol}://{$_SERVER['SERVER_NAME']}{$server_port}/shipments/sid/{$shipping_id}", "packages" => $packages ); + if ($callback_url) { + $shipment_request_info["dispatch_callback_url"] = "{$protocol}://{$_SERVER['SERVER_NAME']}{$server_port}{$callback_url}"; + } $response = $this->shipping_service->create_shipment_request($shipment_request_info); $external_shipping_id = $response['shipmentRequestId']; return $external_shipping_id; @@ -1050,7 +1058,14 @@ function _dispatch_dewar_shipment_request($dewar) $proposal = $dewar['PROPOSAL']; $external_id = (int) $dewar['DEWARID']; $shipping_id = (int) $dewar['SHIPPINGID']; - $external_shipping_id = $this->_create_dewars_shipment_request($dewars, $proposal, $external_id, $shipping_id); + $token = md5(uniqid()); + $this->db->pq( + "UPDATE dewar SET extra = JSON_SET(IFNULL(extra, '{}'), '$.token', :1 ) WHERE dewarid=:2", + array($token, $external_id) + ); + + $callback_url = "/api/shipment/dewars/confirmdispatch/did/{$external_id}/token/{$token}"; + $external_shipping_id = $this->_create_dewars_shipment_request($dewars, $proposal, $external_id, $shipping_id, $callback_url); $this->db->pq( "UPDATE dewar SET externalShippingIdFromSynchrotron=:1 WHERE dewarid=:2", @@ -1200,14 +1215,6 @@ function _dispatch_dewar() $dispatch_from_location = 'eBIC'; } - // Update dewar transport history with provided location. - $this->db->pq( - "INSERT INTO dewartransporthistory (dewartransporthistoryid,dewarid,dewarstatus,storagelocation,arrivaldate) - VALUES (s_dewartransporthistory.nextval,:1,'dispatch-requested',:2,CURRENT_TIMESTAMP) - RETURNING dewartransporthistoryid INTO :id", - array($dew['DEWARID'], $dewar_location) - ); - $terms = $this->db->pq( "SELECT cta.couriertermsacceptedid FROM couriertermsaccepted cta WHERE cta.shippingid=:1", array($dew['SHIPPINGID']) @@ -1255,10 +1262,133 @@ function _dispatch_dewar() && $terms_accepted && Utils::getValueOrDefault($use_shipping_service_redirect) ); - $subject_pickup_date = $use_dispatch_lite_template ? '' : ' - Pickup Date: ' . $this->args['DELIVERYAGENT_SHIPPINGDATE']; - $subject_line = '*** Dispatch requested for Dewar ' . $dew['BARCODE'] . ' from ' . $dispatch_from_location . $subject_pickup_date . ' ***'; - $email_template = $use_dispatch_lite_template ? 'dewar-dispatch-lite' : 'dewar-dispatch'; + + if ($use_dispatch_lite_template) { + $this->_output(1); + } else { + $subject_pickup_date = $use_dispatch_lite_template ? '' : ' - Pickup Date: ' . $this->args['DELIVERYAGENT_SHIPPINGDATE']; + $subject_line = '*** Dispatch requested for Dewar ' . $dew['BARCODE'] . ' from ' . $dispatch_from_location . $subject_pickup_date . ' ***'; + $email_template = $use_dispatch_lite_template ? 'dewar-dispatch-lite' : 'dewar-dispatch'; + $email = new Email($email_template, $subject_line); + + // If a local contact is given, try to find their email address + // First try LDAP, if unsuccessful look at the ISPyB person record for a matching staff user + $local_contact = $this->has_arg('LOCALCONTACT') ? $this->args['LOCALCONTACT'] : ''; + if ($local_contact) { + $this->args['LCEMAIL'] = $this->_get_email_fn($local_contact); + if (!$this->args['LCEMAIL']) { + $this->args['LCEMAIL'] = $this->_get_ispyb_email_fn($local_contact); + } + } + + if (!array_key_exists('FACILITYCODE', $data)) + $data['FACILITYCODE'] = ''; + if (!array_key_exists('AWBNUMBER', $data)) + $data['AWBNUMBER'] = ''; + if (!array_key_exists('DELIVERYAGENT_AGENTNAME', $data)) + $data['DELIVERYAGENT_AGENTNAME'] = ''; + if (!array_key_exists('DELIVERYAGENT_AGENTCODE', $data)) + $data['DELIVERYAGENT_AGENTCODE'] = ''; + if (!array_key_exists('LOCATION', $data)) + $data['LOCATION'] = $dewar_location; + if (!array_key_exists('LOCALCONTACT', $data)) + $data['LOCALCONTACT'] = $local_contact; + if (!array_key_exists('LCEMAIL', $data)) + $data['LCEMAIL'] = ''; + $data['BARCODE'] = $dew['BARCODE']; + $email->data = $data; + + if ( + $country != $facility_country && + array_key_exists('DELIVERYAGENT_AGENTNAME', $data) && + $data['DELIVERYAGENT_AGENTNAME'] === 'DHL' && + array_key_exists('PROPOSALCODE', $dew) && + in_array($dew['PROPOSALCODE'], array('bi','cm','mx')) && + !is_null($dispatch_email_intl) + ) { + $recpts = $dispatch_email_intl; + } else { + $recpts = $dispatch_email; + } + + $recpts .= ', ' . $this->arg('EMAILADDRESS'); + $local_contact_email = $this->has_arg('LCEMAIL') ? $this->args['LCEMAIL'] : ''; + if ($local_contact_email) $recpts .= ', ' . $local_contact_email; + + $email->send($recpts); + + // Update the dewar status and storage location + $this->db->pq( + "UPDATE dewar + set dewarstatus='dispatch-requested', storagelocation=lower(:2) + WHERE dewarid=:1", + array($dew['DEWARID'], $dewar_location) + ); + + $this->db->pq("UPDATE shipping set shippingstatus='dispatch-requested' WHERE shippingid=:1", array($dew['SHIPPINGID'])); + + // Update dewar transport history with provided location. + $this->db->pq( + "INSERT INTO dewartransporthistory (dewartransporthistoryid,dewarid,dewarstatus,storagelocation,arrivaldate) + VALUES (s_dewartransporthistory.nextval,:1,'dispatch-requested',:2,CURRENT_TIMESTAMP) + RETURNING dewartransporthistoryid INTO :id", + array($dew['DEWARID'], $dewar_location) + ); + + $this->_output(1); + } + } + + + function _dispatch_dewar_confirmation() + { + global $dispatch_email; + global $shipping_service_app_url; + + if (!$this->has_arg('did')) + $this->_error('No dewar specified'); + + # Check token against dewar given + $dew = $this->db->pq( + "SELECT d.dewarid, d.barcode, d.storagelocation, d.dewarstatus, d.externalShippingIdFromSynchrotron, d.facilitycode, d.trackingNumberFromSynchrotron, + s.shippingid, + CONCAT(p.proposalcode, p.proposalnumber) as proposal, + json_unquote(json_extract(d.extra, '$.token')) as token, + pe2.emailaddress + FROM dewar d + INNER JOIN shipping s ON s.shippingid = d.shippingid + INNER JOIN proposal p ON p.proposalid = s.proposalid + LEFT OUTER JOIN labcontact c2 ON s.returnlabcontactid = c2.labcontactid + LEFT OUTER JOIN person pe2 ON pe2.personid = c2.personid + WHERE d.dewarid=:1", + array($this->arg('did')) + ); + $dew = $dew[0]; + + if (!$this->has_arg('TOKEN') || $this->arg('TOKEN') !== $dew['TOKEN']) { + $this->_error('Incorrect token'); + } + + # Prepare e-mail to stores + $data = $this->args; + if (!array_key_exists('prop', $data)) + $data['prop'] = $dew['PROPOSAL']; + if (!array_key_exists('FACILITYCODE', $data)) + $data['FACILITYCODE'] = $dew['FACILITYCODE']; + if (!array_key_exists('BARCODE', $data)) + $data['BARCODE'] = $dew['BARCODE']; + if (!array_key_exists('AWBURL', $data)) + $data['AWBURL'] = "{$shipping_service_app_url}/shipment-requests/{$dew['EXTERNALSHIPPINGIDFROMSYNCHROTRON']}/outgoing"; + if (!array_key_exists('LOCATION', $data)) + $data['LOCATION'] = $dew['STORAGELOCATION']; + if (!array_key_exists('EMAILADDRESS', $data)) + $data['EMAILADDRESS'] = $dew['EMAILADDRESS'];; + if (!array_key_exists('tracking_number', $data)) + $data['tracking_number'] = $dew['TRACKINGNUMBERFROMSYNCHROTRON']; + $subject_line = '*** Dispatch requested for Dewar ' . $dew['BARCODE'] . ' from ' . $data['LOCATION'] . ' ***'; + $email_template = 'dewar-dispatch-lite'; $email = new Email($email_template, $subject_line); + $email->data = $data; // If a local contact is given, try to find their email address // First try LDAP, if unsuccessful look at the ISPyB person record for a matching staff user @@ -1270,37 +1400,8 @@ function _dispatch_dewar() } } - if (!array_key_exists('FACILITYCODE', $data)) - $data['FACILITYCODE'] = ''; - if (!array_key_exists('AWBNUMBER', $data)) - $data['AWBNUMBER'] = ''; - if (!array_key_exists('DELIVERYAGENT_AGENTNAME', $data)) - $data['DELIVERYAGENT_AGENTNAME'] = ''; - if (!array_key_exists('DELIVERYAGENT_AGENTCODE', $data)) - $data['DELIVERYAGENT_AGENTCODE'] = ''; - if (!array_key_exists('LOCATION', $data)) - $data['LOCATION'] = $dewar_location; - if (!array_key_exists('LOCALCONTACT', $data)) - $data['LOCALCONTACT'] = $local_contact; - if (!array_key_exists('LCEMAIL', $data)) - $data['LCEMAIL'] = ''; - $data['BARCODE'] = $dew['BARCODE']; - $email->data = $data; - - if ( - $country != $facility_country && - array_key_exists('DELIVERYAGENT_AGENTNAME', $data) && - $data['DELIVERYAGENT_AGENTNAME'] === 'DHL' && - array_key_exists('PROPOSALCODE', $dew) && - in_array($dew['PROPOSALCODE'], array('bi','cm','mx')) && - !is_null($dispatch_email_intl) - ) { - $recpts = $dispatch_email_intl; - } else { - $recpts = $dispatch_email; - } - - $recpts .= ', ' . $this->arg('EMAILADDRESS'); + $recpts = $dispatch_email; + if ($data['EMAILADDRESS']) $recpts .= ', ' . $data['EMAILADDRESS']; $local_contact_email = $this->has_arg('LCEMAIL') ? $this->args['LCEMAIL'] : ''; if ($local_contact_email) $recpts .= ', ' . $local_contact_email; @@ -1309,9 +1410,19 @@ function _dispatch_dewar() // Also update the dewar status and storage location to keep it in sync with history... $this->db->pq( "UPDATE dewar - set dewarstatus='dispatch-requested', storagelocation=lower(:2) + set dewarstatus='dispatch-requested', storagelocation=lower(:2), trackingnumberfromsynchrotron=:3 WHERE dewarid=:1", - array($dew['DEWARID'], $dewar_location) + array($dew['DEWARID'], $data['LOCATION'], $data['tracking_number']) + ); + + $this->db->pq("UPDATE shipping set shippingstatus='dispatch-requested' WHERE shippingid=:1", array($dew['SHIPPINGID'])); + + // Update dewar transport history with provided location. + $this->db->pq( + "INSERT INTO dewartransporthistory (dewartransporthistoryid,dewarid,dewarstatus,storagelocation,arrivaldate) + VALUES (s_dewartransporthistory.nextval,:1,'dispatch-requested',:2,CURRENT_TIMESTAMP) + RETURNING dewartransporthistoryid INTO :id", + array($dew['DEWARID'], $data['LOCATION']) ); $this->_output(1); diff --git a/client/src/js/modules/shipment/models/dispatch.js b/client/src/js/modules/shipment/models/dispatch.js index 779948e33..195045bf3 100644 --- a/client/src/js/modules/shipment/models/dispatch.js +++ b/client/src/js/modules/shipment/models/dispatch.js @@ -37,7 +37,7 @@ define(['backbone'], function(Backbone) { }, EMAILADDRESS: { - required: true, + required: function () {return this.dispatchDetailsRequired}, pattern: 'email', }, diff --git a/client/src/js/templates/shipment/dispatch.html b/client/src/js/templates/shipment/dispatch.html index 74ed6e56f..7bda18046 100644 --- a/client/src/js/templates/shipment/dispatch.html +++ b/client/src/js/templates/shipment/dispatch.html @@ -24,11 +24,6 @@

Request Dewar Dispatch

<% } %> -
  • - - -
  • -
  • +
  • + + +
  • +
  • From 68ae4f525cfb0ad97df136069be33d26546bbb6d Mon Sep 17 00:00:00 2001 From: Mark W <24956497+ndg63276@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:21:34 +0100 Subject: [PATCH 5/8] LIMS-1435: Put CCP4 location into config variable (#821) Co-authored-by: Mark Williams --- api/config_sample.php | 3 +++ api/scripts/mtz2map.sh | 21 ++++++++------------- api/src/Downstream/DownstreamProcessing.php | 13 ++++++------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/api/config_sample.php b/api/config_sample.php index d38e2f0c1..a178d48cd 100644 --- a/api/config_sample.php +++ b/api/config_sample.php @@ -155,6 +155,9 @@ # Server log location $server_log = '/dls_sw/<%=BEAMLINENAME%>/logs/gda-server.log'; + # Path to ccp4 location + $ccp4_location = '/dls_sw/apps/ccp4/latest/ccp4-9'; + # Email addresses, comma separate for multiple recepients # - Email templates in assets/emails in plain and html/ format diff --git a/api/scripts/mtz2map.sh b/api/scripts/mtz2map.sh index 04fb213c0..00542447d 100755 --- a/api/scripts/mtz2map.sh +++ b/api/scripts/mtz2map.sh @@ -2,19 +2,6 @@ cd /tmp -# If you are running with the module system, load ccp4 -#. /etc/profile.d/modules.sh -#module load ccp4 - -# If not, define the environment variables required below -#export CCP4_MASTER=/dls_sw/apps/ccp4/ -export CCP4_MASTER=/dls_sw/apps/ccp4/latest/ccp4-8.0 -export CINCL=$CCP4_MASTER/include -export CLIBD=$CCP4_MASTER/lib/data - -export CCP4_SCR=/tmp -export root=$CCP4_MASTER/bin - if [ -f $1 ]; then mtz=$1 else @@ -41,6 +28,14 @@ else fi fi +#export CCP4_MASTER=/dls_sw/apps/ccp4/ +export CCP4_MASTER=$5 +export CINCL=$CCP4_MASTER/include +export CLIBD=$CCP4_MASTER/lib/data + +export CCP4_SCR=/tmp +export root=$CCP4_MASTER/bin + if [ $3 == 'dimple' ]; then if $root/mtzinfo $mtz | grep -q PH2FOFCWT; then diff --git a/api/src/Downstream/DownstreamProcessing.php b/api/src/Downstream/DownstreamProcessing.php index 325c0a1c1..ca271d91b 100644 --- a/api/src/Downstream/DownstreamProcessing.php +++ b/api/src/Downstream/DownstreamProcessing.php @@ -217,15 +217,14 @@ function _lookup_autoproc($aid, $scalingid = null) { * @param string $pdb The input pdb file to generate the map around */ function convert_mtz($mtz, $aid, $program, $pdb, $map = 0) { + global $ccp4_location; exec( '/bin/bash ./scripts/mtz2map.sh ' . - $mtz . - ' ' . - $aid . - ' ' . - $program . - ' ' . - $pdb, + $mtz . ' ' . + $aid . ' ' . + $program . ' ' . + $pdb . ' ' . + $ccp4_location, $output, $res ); From 486e661f623692b9b34543d247f62ec5b2f5f3a4 Mon Sep 17 00:00:00 2001 From: Mark W <24956497+ndg63276@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:22:15 +0100 Subject: [PATCH 6/8] LIMS-656: Show auto subsamples if they have data (#817) * LIMS-656: Show auto generated subsamples if they have data * LIMS-656: Simpler way to show icon * LIMS-656: Remove 'Old' column --------- Co-authored-by: Mark Williams --- api/src/Page/Sample.php | 28 +++++++++++++++++++++------- client/src/js/utils/table.js | 3 +-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/api/src/Page/Sample.php b/api/src/Page/Sample.php index 145a88838..eb8850184 100644 --- a/api/src/Page/Sample.php +++ b/api/src/Page/Sample.php @@ -631,13 +631,15 @@ function _sub_samples() $where = ''; $first_inner_select_where = ''; $second_inner_select_where = ''; + $third_inner_select_where = ''; $args = array($this->proposalid); if ($this->has_arg('sid')) { $where .= ' AND s.blsampleid=:' . (sizeof($args) + 1); $first_inner_select_where .= ' AND s.blsampleid=:' . (sizeof($args) + 2); $second_inner_select_where .= ' AND s.blsampleid=:' . (sizeof($args) + 3); - array_push($args, $this->arg('sid'), $this->arg('sid'), $this->arg('sid')); + $third_inner_select_where .= ' AND s.blsampleid=:' . (sizeof($args) + 4); + array_push($args, $this->arg('sid'), $this->arg('sid'), $this->arg('sid'), $this->arg('sid')); } if ($this->has_arg('cid')) { @@ -648,7 +650,7 @@ function _sub_samples() } $this->db->wait_rep_sync(true); - $ss_query_string = $this->get_sub_samples_query($where, $first_inner_select_where, $second_inner_select_where); + $ss_query_string = $this->get_sub_samples_query($where, $first_inner_select_where, $second_inner_select_where, $third_inner_select_where); $subs = $this->db->pq($ss_query_string, $args); $this->db->wait_rep_sync(false); @@ -683,7 +685,7 @@ function _get_sub_sample() } } - private function get_sub_samples_query($where, $first_inner_select_where = '', $second_inner_select_where = '') + private function get_sub_samples_query($where, $first_inner_select_where = '', $second_inner_select_where = '', $third_inner_select_where = '') { $group_by = ""; $order_by = ""; @@ -707,7 +709,7 @@ private function get_sub_samples_query($where, $first_inner_select_where = '', $ $from_query = "FROM ( SELECT ss.blsubsampleid FROM ( - SELECT s.blsampleid, max(si.blsampleimageid) AS blsampleimageid + SELECT s.blsampleid, max(si.blsampleimageid) AS blsampleimageid FROM blsample s INNER JOIN blsampleimage si ON si.blsampleid = s.blsampleid WHERE 1=1 $first_inner_select_where @@ -715,14 +717,26 @@ private function get_sub_samples_query($where, $first_inner_select_where = '', $ ) qq JOIN blsubsample ss ON ss.blsampleimageid = qq.blsampleimageid WHERE ss.source = 'auto' - + UNION ALL SELECT ss.blsubsampleid FROM blsubsample ss LEFT JOIN blsample s on ss.blsampleid = s.blsampleid - WHERE ss.source = 'manual' $second_inner_select_where - ) q JOIN blsubsample ss ON ss.blsubsampleid = q.blsubsampleid"; + WHERE ss.source = 'manual' $second_inner_select_where"; + + // show auto generated subsamples with data collections + if ($third_inner_select_where != '') { + $from_query .= " + UNION ALL + SELECT ss.blsubsampleid + FROM blsubsample ss + LEFT JOIN blsample s on ss.blsampleid = s.blsampleid + INNER JOIN datacollection dc ON ss.blsubsampleid = dc.blsubsampleid + WHERE ss.source = 'auto' $third_inner_select_where"; + } + + $from_query .= ") q JOIN blsubsample ss ON ss.blsubsampleid = q.blsubsampleid"; $group_by = "GROUP BY pr.acronym, s.name, diff --git a/client/src/js/utils/table.js b/client/src/js/utils/table.js index 69cd3015f..b8661bb0b 100644 --- a/client/src/js/utils/table.js +++ b/client/src/js/utils/table.js @@ -159,7 +159,7 @@ define(['marionette', 'backgrid', return this; } }), - + ProjectCell: Backgrid.Cell.extend({ events: { 'click a.atp': 'addToProject', @@ -232,4 +232,3 @@ define(['marionette', 'backgrid', } }) - From 216c0c489925b5f0afd0ba53f290d1ab802da6f8 Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Tue, 3 Sep 2024 10:51:27 +0100 Subject: [PATCH 7/8] LIMS-1108: Fix bad merge at ed1dcb55240b0312ebf77536ad98e8d23659ec91 --- client/src/js/modules/shipment/views/shipmentadd.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/src/js/modules/shipment/views/shipmentadd.js b/client/src/js/modules/shipment/views/shipmentadd.js index 45d35957c..a5fea270b 100644 --- a/client/src/js/modules/shipment/views/shipmentadd.js +++ b/client/src/js/modules/shipment/views/shipmentadd.js @@ -48,6 +48,13 @@ define(['marionette', 'views/form', return FormView.extend({ template: template, + templateHelpers: function() { + return { + DHL_ENABLE: app.options.get('dhl_enable'), + FACILITY_COURIER_COUNTRIES_LINK: app.options.get('facility_courier_countries_link'), + } + }, + events: { 'change input[name=DEWARS]': 'updateFCodes', 'change @ui.lcret': 'getlcdetails', From c775a9c1f72e760e5986ebe8b4c6d85bbf4b46cd Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Thu, 5 Sep 2024 13:33:55 +0100 Subject: [PATCH 8/8] LIMS-1432: Fix parent job headers --- api/src/Downstream/Type/Shelxt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/Downstream/Type/Shelxt.php b/api/src/Downstream/Type/Shelxt.php index 466a6392b..c9422e0a5 100644 --- a/api/src/Downstream/Type/Shelxt.php +++ b/api/src/Downstream/Type/Shelxt.php @@ -54,7 +54,7 @@ function results() { $dat['SOLUTIONS'] = json_decode($json_data); // scaling_id should always be present, but just in case... - if (in_array('scaling_id', $this->process['PARAMETERS'])) { + if (array_key_exists('scaling_id', $this->process['PARAMETERS'])) { $integrator = $this->_lookup_autoproc( null, $this->process['PARAMETERS']['scaling_id']