CtAdminInterface.class.php 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370
  1. <?php
  2. namespace Models {
  3. require_once 'Models/User.class.php';
  4. require_once 'Tools/Crypto.class.php';
  5. class CtAdminInterface {
  6. //
  7. protected $DataInterface;
  8. /**
  9. *
  10. */
  11. public function __construct($DataInterface) {
  12. $this->DataInterface = $DataInterface;
  13. }
  14. /**
  15. * Check login/password and create JWT token.
  16. */
  17. public function CtAdminLogin(&$User, $email, $clearPassword) {
  18. $statement = $this->DataInterface->DatabaseConnection->prepare(
  19. "SELECT
  20. ID, password, firstname, lastname
  21. FROM
  22. user
  23. WHERE
  24. active = 1 AND
  25. email = '$email' AND
  26. type = 'cro'"
  27. );
  28. if(!$statement->execute()) {
  29. $results = Array('result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo());
  30. }
  31. else {
  32. $results = $statement->fetchAll(\PDO::FETCH_ASSOC);
  33. if(count($results)){
  34. if(\Tools\Crypto::verify($clearPassword, $results[0]['password'])) {
  35. // Generate JWT token
  36. $issuer_claim = \Config\Settings::getTokenIssuer();
  37. $audience_claim = \Config\Settings::getAdminTokenAudience();
  38. $issuedat_claim = time(); // issued at
  39. $notbefore_claim = $issuedat_claim + \Config\Settings::getTokenNotBefore();
  40. $expire_claim = $issuedat_claim + \Config\Settings::getTokenExpiration();
  41. $token = array(
  42. "iss" => $issuer_claim,
  43. "aud" => $audience_claim,
  44. "iat" => $issuedat_claim,
  45. "nbf" => $notbefore_claim,
  46. "exp" => $expire_claim,
  47. "data" => array(
  48. "ID" => $results[0]['ID'],
  49. "firstname" => $results[0]['firstname'],
  50. "lastname" => $results[0]['lastname'],
  51. "email" => $email
  52. )
  53. );
  54. $jwt = \Firebase\JWT\JWT::encode($token, \Config\Settings::getTokenPrivateKey());
  55. // OK
  56. $results = Array(
  57. "result" => "OK",
  58. "token" => $jwt,
  59. "email" => $email,
  60. "expireAt" => $expire_claim
  61. );
  62. }
  63. else {
  64. $results = Array('result' => 'ERROR', 'reason' => 'bad_password', 'message' => 'Invalid password');
  65. }
  66. }
  67. else {
  68. $results = Array('result' => 'ERROR', 'reason' => 'unknown', 'message' => 'No such user');
  69. }
  70. }
  71. return $results;
  72. }
  73. /**
  74. * Logout.
  75. */
  76. public function CtAdminLogout(&$User) {
  77. $User->logout();
  78. return Array('result' => 'OK');
  79. }
  80. /**
  81. * Get profile data.
  82. */
  83. public function CtAdminProfileGet($User) {
  84. $userID = $User->ID;
  85. // select centers
  86. $statement = $this->DataInterface->DatabaseConnection->prepare(
  87. "SELECT ct_center.ID, organization.name AS org_name, probe.name AS probe_name FROM organization, probe, ct_center WHERE ct_center.fk_organization = organization.ID AND ct_center.fk_probe = probe.ID ORDER by stamp"
  88. );
  89. // Error check
  90. if(!$statement->execute()) {
  91. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  92. }
  93. $centers = $statement->fetchAll(\PDO::FETCH_ASSOC);
  94. $ID_center = count($centers)?$centers[0]['ID']:0;
  95. // select investigators
  96. $statement = $this->DataInterface->DatabaseConnection->prepare(
  97. "SELECT * FROM user WHERE type = 'investigator' ORDER BY ID"
  98. );
  99. // Error check
  100. if(!$statement->execute()) {
  101. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  102. }
  103. $investigators = $statement->fetchAll(\PDO::FETCH_ASSOC);
  104. $ID_investigator = count($investigators)?$investigators[0]['ID']:0;
  105. // select readers
  106. $statement = $this->DataInterface->DatabaseConnection->prepare(
  107. "SELECT * FROM user WHERE type = 'reader' ORDER BY ID"
  108. );
  109. // Error check
  110. if(!$statement->execute()) {
  111. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  112. }
  113. $readers = $statement->fetchAll(\PDO::FETCH_ASSOC);
  114. $ID_reader = count($readers)?$readers[0]['ID']:0;
  115. // OK
  116. return array(
  117. 'result' => 'OK',
  118. 'ID' => $User->ID,
  119. 'firstname' => $User->firstname,
  120. 'lastname' => $User->lastname,
  121. 'email' => $User->email,
  122. 'ID_center' => $ID_center,
  123. 'ID_investigator' => $ID_investigator,
  124. 'ID_reader' => $ID_reader
  125. );
  126. }
  127. /**
  128. *
  129. */
  130. public function CtAdminSettingsGet($User) {
  131. $userID = $User->ID;
  132. $statement = $this->DataInterface->DatabaseConnection->prepare(
  133. "SELECT * FROM clinical_trial"
  134. );
  135. if(!$statement->execute()) {
  136. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  137. }
  138. $settings = $statement->fetchAll(\PDO::FETCH_ASSOC)[0];
  139. $settings['comment'] = stripslashes($settings['comment']);
  140. // OK
  141. return array(
  142. 'result' => 'OK',
  143. 'settings' => $settings
  144. );
  145. }
  146. /**
  147. *
  148. */
  149. public function CtAdminPatientsGet($User, $ID_center) {
  150. $userID = $User->ID;
  151. // select centers
  152. $statement = $this->DataInterface->DatabaseConnection->prepare(
  153. "SELECT ct_center.ID, organization.name AS org_name, probe.name AS probe_name FROM organization, probe, ct_center WHERE ct_center.fk_organization = organization.ID AND ct_center.fk_probe = probe.ID ORDER by stamp"
  154. );
  155. // Error check
  156. if(!$statement->execute()) {
  157. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  158. }
  159. $centers = $statement->fetchAll(\PDO::FETCH_ASSOC);
  160. // select patients
  161. $statement = $this->DataInterface->DatabaseConnection->prepare("
  162. SELECT
  163. P.ctPatientID,
  164. V.*,
  165. (SELECT COUNT(media.ID) FROM media WHERE JSON_VALUE(media.metrics, '$.fps') IS NULL AND media.fk_visit = V.ID) as imageCount,
  166. (SELECT COUNT(media.ID) FROM media WHERE media.fk_visit = V.ID) as mediaCount,
  167. CONCAT(U.lastname,' ',U.firstname) AS investigator,
  168. (SELECT MAX(measure.created) FROM measure, media WHERE media.fk_visit = V.ID AND media.ID = measure.fk_media) as measureLastDate
  169. FROM patient P, visit V, user U, ct_center C
  170. WHERE V.fk_patient = P.ID
  171. AND P.fk_user = U.ID AND U.type = 'investigator'
  172. AND C.ID = U.fk_center AND C.ID = $ID_center
  173. ORDER BY V.visitDate DESC
  174. ");
  175. // Error check
  176. if(!$statement->execute()) {
  177. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  178. }
  179. $visits = $statement->fetchAll(\PDO::FETCH_ASSOC);
  180. // select readers
  181. $statement = $this->DataInterface->DatabaseConnection->prepare(
  182. "SELECT * FROM user WHERE type = 'reader'"
  183. );
  184. // Error check
  185. if(!$statement->execute()) {
  186. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  187. }
  188. $readers = $statement->fetchAll(\PDO::FETCH_ASSOC);
  189. // OK
  190. return [
  191. 'result' => 'OK',
  192. 'visits' => $visits,
  193. 'readers' => $readers,
  194. 'centers' => $centers,
  195. 'user' => $User,
  196. 'ID_center' => $ID_center
  197. ];
  198. }
  199. /**
  200. *
  201. */
  202. public function CtAdminVisitsGet($User, $ID) {
  203. $userID = $User->ID;
  204. // select visits
  205. $statement = $this->DataInterface->DatabaseConnection->prepare(
  206. "SELECT * FROM visit WHERE ID = $ID"
  207. );
  208. // Error check
  209. if(!$statement->execute()) {
  210. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  211. }
  212. $visits = $statement->fetchAll(\PDO::FETCH_ASSOC);
  213. foreach($visits as &$V) {
  214. $ID_visit = $V['ID'];
  215. // select media
  216. $statement = $this->DataInterface->DatabaseConnection->prepare(
  217. "SELECT * FROM media WHERE fk_visit = $ID_visit"
  218. );
  219. // Error check
  220. if(!$statement->execute()) {
  221. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  222. }
  223. $V['media'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  224. foreach($V['media'] as &$M) {
  225. $M['metrics'] = json_decode($M['metrics']);
  226. }
  227. }
  228. return [
  229. 'result' => 'OK',
  230. 'visits' => $visits
  231. ];
  232. }
  233. /**
  234. *
  235. */
  236. public function CtAdminUsersGet($User, $type) {
  237. $userID = $User->ID;
  238. // countries
  239. $statement = $this->DataInterface->DatabaseConnection->prepare(
  240. "SELECT * FROM country ORDER BY name_en"
  241. );
  242. if(!$statement->execute()) {
  243. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  244. }
  245. $countries = $statement->fetchAll(\PDO::FETCH_ASSOC);
  246. if($type=='reader') {
  247. // readers
  248. $statement = $this->DataInterface->DatabaseConnection->prepare(
  249. "SELECT * FROM user WHERE type = '$type'"
  250. );
  251. if(!$statement->execute()) {
  252. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  253. }
  254. $users = $statement->fetchAll(\PDO::FETCH_ASSOC);
  255. foreach($users as &$U) {
  256. $ID = $U['ID'];
  257. // organization
  258. $statement = $this->DataInterface->DatabaseConnection->prepare(
  259. "SELECT * FROM organization WHERE fk_user = $ID"
  260. );
  261. if(!$statement->execute()) {
  262. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  263. }
  264. $U['org'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  265. }
  266. $organizations = [];
  267. }
  268. else if($type=='investigator') {
  269. // organization
  270. $statement = $this->DataInterface->DatabaseConnection->prepare(
  271. "SELECT ct_center.ID AS center_ID, organization.name AS org_name, probe.name AS probe_name FROM organization, probe, ct_center WHERE ct_center.fk_organization = organization.ID AND ct_center.fk_probe = probe.ID ORDER by stamp"
  272. );
  273. if(!$statement->execute()) {
  274. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  275. }
  276. $organizations = $statement->fetchAll(\PDO::FETCH_ASSOC);
  277. // investigators
  278. $statement = $this->DataInterface->DatabaseConnection->prepare(
  279. "SELECT * FROM user WHERE fk_center != 0 AND type = '$type'"
  280. );
  281. if(!$statement->execute()) {
  282. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  283. }
  284. $users = $statement->fetchAll(\PDO::FETCH_ASSOC);
  285. }
  286. // OK
  287. return array(
  288. 'result' => 'OK',
  289. 'users' => $users,
  290. 'organizations' => $organizations,
  291. 'type' => $type,
  292. 'countries' => $countries
  293. );
  294. }
  295. /**
  296. *
  297. */
  298. public function CtAdminCROsGet($User) {
  299. $userID = $User->ID;
  300. $statement = $this->DataInterface->DatabaseConnection->prepare(
  301. "SELECT * FROM user WHERE type = 'cro'"
  302. );
  303. if(!$statement->execute()) {
  304. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  305. }
  306. $users = $statement->fetchAll(\PDO::FETCH_ASSOC);
  307. // OK
  308. return array(
  309. 'result' => 'OK',
  310. 'users' => $users
  311. );
  312. }
  313. /**
  314. *
  315. */
  316. public function CtAdminUsersPost($User, $data) {
  317. $userID = intval($data['userID']);
  318. if($data['type']=='investigator') {
  319. // insert
  320. if($userID==0) {
  321. // Insert user
  322. $statement = $this->DataInterface->DatabaseConnection->prepare(
  323. "INSERT INTO user(activation_token, activation_expire, activation, password, firstname, lastname, email, phone, type, active, fk_center)
  324. VALUES(:activation_token, :activation_expire, NOW(), :password, :firstname, :lastname, :email, :phone, :type, :active, :fk_center)"
  325. );
  326. $activation_token = \Tools\UUID::v4();
  327. $activation_expire = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s'). ' + 1 days'));
  328. $statement->bindParam(':activation_token', $activation_token);
  329. $statement->bindParam(':activation_expire', $activation_expire);
  330. $password = \Tools\UUID::v4();
  331. $statement->bindParam(':password', $password);
  332. $statement->bindParam(':firstname', $data['user']['firstname']);
  333. $statement->bindParam(':lastname', $data['user']['lastname']);
  334. $statement->bindParam(':email', $data['user']['email']);
  335. $statement->bindParam(':phone', $data['user']['phone']);
  336. $statement->bindParam(':active', $data['user']['active']);
  337. $statement->bindParam(':type', $data['type']);
  338. $statement->bindParam(':fk_center', $data['user']['centerID']);
  339. // Error check
  340. if(!$statement->execute()) {
  341. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  342. }
  343. }
  344. // update
  345. else {
  346. // Update user
  347. $statement = $this->DataInterface->DatabaseConnection->prepare(
  348. "UPDATE user SET firstname=:firstname, lastname=:lastname, email=:email, phone=:phone, active=:active, fk_center=:fk_center WHERE ID=:userID"
  349. );
  350. $statement->bindParam(':firstname', $data['user']['firstname']);
  351. $statement->bindParam(':lastname', $data['user']['lastname']);
  352. $statement->bindParam(':email', $data['user']['email']);
  353. $statement->bindParam(':phone', $data['user']['phone']);
  354. $statement->bindParam(':active', $data['user']['active']);
  355. $statement->bindParam(':fk_center', $data['user']['centerID']);
  356. $statement->bindParam(':userID', $userID);
  357. // Error check
  358. if(!$statement->execute()) {
  359. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  360. }
  361. }
  362. }
  363. else if($data['type']=='reader') {
  364. // insert
  365. if($userID==0) {
  366. // Insert user
  367. $statement = $this->DataInterface->DatabaseConnection->prepare(
  368. "INSERT INTO user(activation_token, activation_expire, activation, password, firstname, lastname, email, phone, type, active, fk_center)
  369. VALUES(:activation_token, :activation_expire, NOW(), :password, :firstname, :lastname, :email, :phone, :type, :active, :fk_center)"
  370. );
  371. $activation_token = \Tools\UUID::v4();
  372. $activation_expire = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s'). ' + 1 days'));
  373. $statement->bindParam(':activation_token', $activation_token);
  374. $statement->bindParam(':activation_expire', $activation_expire);
  375. $password = \Tools\UUID::v4();
  376. $statement->bindParam(':password', $password);
  377. $statement->bindParam(':firstname', $data['user']['firstname']);
  378. $statement->bindParam(':lastname', $data['user']['lastname']);
  379. $statement->bindParam(':email', $data['user']['email']);
  380. $statement->bindParam(':phone', $data['user']['phone']);
  381. $statement->bindParam(':active', $data['user']['active']);
  382. $statement->bindParam(':type', $data['type']);
  383. $statement->bindParam(':fk_center', $data['user']['centerID']);
  384. // Error check
  385. if(!$statement->execute()) {
  386. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  387. }
  388. $fk_user = $this->DataInterface->DatabaseConnection->lastInsertId();
  389. // Insert organization
  390. $statement = $this->DataInterface->DatabaseConnection->prepare(
  391. "INSERT INTO organization VALUES(0, :fk_user, :name, :fk_country, :zip, :city, :address, :phone)"
  392. );
  393. $statement->bindParam(':fk_user', $fk_user);
  394. $statement->bindParam(':name', $data['user']['org_name']);
  395. $statement->bindParam(':fk_country', $data['user']['org_country']);
  396. $statement->bindParam(':zip', $data['user']['org_zip']);
  397. $statement->bindParam(':city', $data['user']['org_city']);
  398. $statement->bindParam(':address', $data['user']['org_address']);
  399. $statement->bindParam(':phone', $data['user']['org_phone']);
  400. // Error check
  401. if(!$statement->execute()) {
  402. $this->DataInterface->DatabaseConnection->rollback();
  403. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  404. }
  405. }
  406. // update
  407. else {
  408. // Update user
  409. $statement = $this->DataInterface->DatabaseConnection->prepare(
  410. "UPDATE user SET firstname=:firstname, lastname=:lastname, email=:email, phone=:phone, active=:active, fk_center=:fk_center WHERE ID=:userID"
  411. );
  412. $statement->bindParam(':firstname', $data['user']['firstname']);
  413. $statement->bindParam(':lastname', $data['user']['lastname']);
  414. $statement->bindParam(':email', $data['user']['email']);
  415. $statement->bindParam(':phone', $data['user']['phone']);
  416. $statement->bindParam(':active', $data['user']['active']);
  417. $statement->bindParam(':fk_center', $data['user']['centerID']);
  418. $statement->bindParam(':userID', $userID);
  419. // Error check
  420. if(!$statement->execute()) {
  421. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  422. }
  423. // Update organization
  424. $statement = $this->DataInterface->DatabaseConnection->prepare(
  425. "UPDATE organization SET name=:name, fk_country=:fk_country, zip=:zip, city=:city, address=:address, phone=:phone WHERE fk_user=:userID"
  426. );
  427. $statement->bindParam(':address', $data['user']['org_address']);
  428. $statement->bindParam(':city', $data['user']['org_city']);
  429. $statement->bindParam(':zip', $data['user']['org_zip']);
  430. $statement->bindParam(':name', $data['user']['org_name']);
  431. $statement->bindParam(':phone', $data['user']['org_phone']);
  432. $statement->bindParam(':fk_country', $data['user']['org_country']);
  433. $statement->bindParam(':userID', $userID);
  434. // Error check
  435. if(!$statement->execute()) {
  436. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  437. }
  438. }
  439. }
  440. // OK
  441. return array(
  442. 'result' => 'OK',
  443. 'data' => $data,
  444. 'password_token' => $password
  445. );
  446. }
  447. /**
  448. *
  449. */
  450. public function CtAdminCROsPost($User, $data) {
  451. $type = 'cro';
  452. $userID = intval($data['userID']);
  453. // insert
  454. if($userID==0) {
  455. // Insert user
  456. $statement = $this->DataInterface->DatabaseConnection->prepare(
  457. "INSERT INTO user(activation_token, activation_expire, activation, password, firstname, lastname, email, phone, type, active)
  458. VALUES(:activation_token, :activation_expire, NOW(), :password, :firstname, :lastname, :email, :phone, :type, :active)"
  459. );
  460. $activation_token = \Tools\UUID::v4();
  461. $activation_expire = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s'). ' + 1 days'));
  462. $statement->bindParam(':activation_token', $activation_token);
  463. $statement->bindParam(':activation_expire', $activation_expire);
  464. $password = \Tools\UUID::v4();
  465. $statement->bindParam(':password', $password);
  466. $statement->bindParam(':firstname', $data['user']['firstname']);
  467. $statement->bindParam(':lastname', $data['user']['lastname']);
  468. $statement->bindParam(':email', $data['user']['email']);
  469. $statement->bindParam(':phone', $data['user']['phone']);
  470. $statement->bindParam(':active', $data['user']['active']);
  471. $statement->bindParam(':type', $type);
  472. // Error check
  473. if(!$statement->execute()) {
  474. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  475. }
  476. }
  477. // update
  478. else {
  479. // Update user
  480. $statement = $this->DataInterface->DatabaseConnection->prepare(
  481. "UPDATE user SET firstname=:firstname, lastname=:lastname, email=:email, phone=:phone, active=:active WHERE ID=:userID"
  482. );
  483. $statement->bindParam(':firstname', $data['user']['firstname']);
  484. $statement->bindParam(':lastname', $data['user']['lastname']);
  485. $statement->bindParam(':email', $data['user']['email']);
  486. $statement->bindParam(':phone', $data['user']['phone']);
  487. $statement->bindParam(':active', $data['user']['active']);
  488. $statement->bindParam(':userID', $userID);
  489. // Error check
  490. if(!$statement->execute()) {
  491. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  492. }
  493. }
  494. // OK
  495. return array(
  496. 'result' => 'OK',
  497. 'data' => $data,
  498. 'userID' => $userID,
  499. 'password_token' => $password
  500. );
  501. }
  502. /**
  503. *
  504. */
  505. public function ctAdminPasswordPost($data) {
  506. if (strlen($data['newPassword']) < 8 ||
  507. !preg_match("#[0-9]+#", $data['newPassword']) ||
  508. !preg_match("#[a-z]+#", $data['newPassword']) ||
  509. !preg_match("#[A-Z]+#", $data['newPassword'])) {
  510. return ['result' => 'ERROR', 'reason' => 'password_strength'];
  511. }
  512. $password = \Tools\Crypto::getHashPassword($data['newPassword']);
  513. $statement = $this->DataInterface->DatabaseConnection->prepare(
  514. "UPDATE user SET password = :newPassword WHERE password = :token"
  515. );
  516. $statement->bindParam(':newPassword', $password);
  517. $statement->bindParam(':token', $data['token']);
  518. if(!$statement->execute()) {
  519. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  520. }
  521. //
  522. return [
  523. 'result' => 'OK'
  524. ];
  525. }
  526. /**
  527. *
  528. */
  529. public function ctAdminReaderPost($User, $data) {
  530. $userID = $User->ID;
  531. $readerID = $data['readerID'];
  532. $visitID = $data['visitID'];
  533. // Update
  534. $statement = $this->DataInterface->DatabaseConnection->prepare(
  535. "UPDATE visit SET fk_reader = $readerID WHERE ID = $visitID"
  536. );
  537. // Error check
  538. if(!$statement->execute()) {
  539. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  540. }
  541. // OK
  542. return array(
  543. 'result' => 'OK'
  544. );
  545. }
  546. /**
  547. *
  548. */
  549. public function CtAdminCentersGet($User) {
  550. $userID = $User->ID;
  551. // countries
  552. $statement = $this->DataInterface->DatabaseConnection->prepare(
  553. "SELECT * FROM country ORDER BY name_en"
  554. );
  555. if(!$statement->execute()) {
  556. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  557. }
  558. $countries = $statement->fetchAll(\PDO::FETCH_ASSOC);
  559. // select data
  560. $statement = $this->DataInterface->DatabaseConnection->prepare("
  561. SELECT ct_center.ID AS centerID,
  562. organization.ID AS org_ID,
  563. organization.name AS org_name,
  564. organization.fk_country AS org_country,
  565. organization.zip AS org_zip,
  566. organization.city AS org_city,
  567. organization.address AS org_address,
  568. organization.phone AS org_phone,
  569. probe.ID AS probe_ID,
  570. probe.name AS probe_name,
  571. probe.brand AS probe_brand,
  572. probe.year AS probe_year,
  573. probe.frequency AS probe_frequency
  574. FROM organization, probe, ct_center
  575. WHERE ct_center.fk_organization = organization.ID AND ct_center.fk_probe = probe.ID ORDER by stamp"
  576. );
  577. // Error check
  578. if(!$statement->execute()) {
  579. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  580. }
  581. $centers = $statement->fetchAll(\PDO::FETCH_ASSOC);
  582. // OK
  583. return array(
  584. 'result' => 'OK',
  585. 'countries' => $countries,
  586. 'center' => $centers
  587. );
  588. }
  589. /**
  590. *
  591. */
  592. public function CtAdminCentersPost($User, $data) {
  593. $ID_user = $User->ID;
  594. // Begin transaction
  595. $this->DataInterface->DatabaseConnection->beginTransaction();
  596. $centerID = intval($data['centerID']);
  597. // insert
  598. if($centerID==0) {
  599. // Insert organization
  600. $statement = $this->DataInterface->DatabaseConnection->prepare(
  601. "INSERT INTO organization VALUES(0, $ID_user, :name, :fk_country, :zip, :city, :address, :phone)"
  602. );
  603. $statement->bindParam(':name', $data['organization']['org_name']);
  604. $statement->bindParam(':fk_country', $data['organization']['org_country']);
  605. $statement->bindParam(':zip', $data['organization']['org_zip']);
  606. $statement->bindParam(':city', $data['organization']['org_city']);
  607. $statement->bindParam(':address', $data['organization']['org_address']);
  608. $statement->bindParam(':phone', $data['organization']['org_phone']);
  609. // Error check
  610. if(!$statement->execute()) {
  611. $this->DataInterface->DatabaseConnection->rollback();
  612. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  613. }
  614. $fk_organization = $this->DataInterface->DatabaseConnection->lastInsertId();
  615. // Insert probe
  616. $statement = $this->DataInterface->DatabaseConnection->prepare(
  617. "INSERT INTO probe VALUES(0, $ID_user, :name, :brand, '', :year, :frequency)"
  618. );
  619. $statement->bindParam(':name', $data['probe']['probe_name']);
  620. $statement->bindParam(':brand', $data['probe']['probe_brand']);
  621. $year = $data['probe']['probe_year']?$data['probe']['probe_year']:null;
  622. $statement->bindParam(':year', $year);
  623. $statement->bindParam(':frequency', $data['probe']['probe_frequency']);
  624. // Error check
  625. if(!$statement->execute()) {
  626. $this->DataInterface->DatabaseConnection->rollback();
  627. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  628. }
  629. $fk_probe = $this->DataInterface->DatabaseConnection->lastInsertId();
  630. // Insert center
  631. $statement = $this->DataInterface->DatabaseConnection->prepare(
  632. "INSERT INTO ct_center VALUES(0, $fk_organization, $fk_probe, NOW())"
  633. );
  634. // Error check
  635. if(!$statement->execute()) {
  636. $this->DataInterface->DatabaseConnection->rollback();
  637. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  638. }
  639. }
  640. // update
  641. else {
  642. // Update organization
  643. $statement = $this->DataInterface->DatabaseConnection->prepare(
  644. "UPDATE organization SET name=:name, fk_country=:fk_country, zip=:zip, city=:city, address=:address, phone=:phone WHERE ID=:org_ID"
  645. );
  646. $statement->bindParam(':name', $data['organization']['org_name']);
  647. $statement->bindParam(':fk_country', $data['organization']['org_country']);
  648. $statement->bindParam(':zip', $data['organization']['org_zip']);
  649. $statement->bindParam(':city', $data['organization']['org_city']);
  650. $statement->bindParam(':address', $data['organization']['org_address']);
  651. $statement->bindParam(':phone', $data['organization']['org_phone']);
  652. $statement->bindParam(':org_ID', $data['organization']['org_ID']);
  653. // Error check
  654. if(!$statement->execute()) {
  655. $this->DataInterface->DatabaseConnection->rollback();
  656. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  657. }
  658. // Update probe
  659. $statement = $this->DataInterface->DatabaseConnection->prepare(
  660. "UPDATE probe SET name=:name, brand=:brand, year=:year, frequency=:frequency WHERE ID=:probe_ID"
  661. );
  662. $statement->bindParam(':name', $data['probe']['probe_name']);
  663. $statement->bindParam(':brand', $data['probe']['probe_brand']);
  664. $year = $data['probe']['probe_year']?$data['probe']['probe_year']:null;
  665. $statement->bindParam(':year', $year);
  666. $statement->bindParam(':frequency', $data['probe']['probe_frequency']);
  667. $statement->bindParam(':probe_ID', $data['probe']['probe_ID']);
  668. // Error check
  669. if(!$statement->execute()) {
  670. $this->DataInterface->DatabaseConnection->rollback();
  671. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  672. }
  673. }
  674. // Commit
  675. $this->DataInterface->DatabaseConnection->commit();
  676. return [
  677. 'result' => 'OK',
  678. 'data' => $data
  679. ];
  680. }
  681. /**
  682. *
  683. */
  684. public function ctAdminSettingsPost($User, $data) {
  685. $userID = $User->ID;
  686. // update data
  687. $statement = $this->DataInterface->DatabaseConnection->prepare(
  688. "UPDATE clinical_trial SET number=:number, name=:name, start=:start, patient_expected=:patient_expected, center_count=:center_count, inclusion_month=:inclusion_month, followup_month=:followup_month, visit_per_patient=:visit_per_patient, visit_interval=:visit_interval, image_per_visit=:image_per_visit, video_per_visit=:video_per_visit, measure_per_timepoint=:measure_per_timepoint, comment=:comment, anon_percent=:anon_percent, fk_user=:fk_user WHERE 1"
  689. );
  690. $statement->bindParam(':number', $data['ct']['number']);
  691. $statement->bindParam(':name', addslashes($data['ct']['name']));
  692. $statement->bindParam(':start', $data['ct']['start']);
  693. $statement->bindParam(':patient_expected', $data['ct']['patient_expected']);
  694. $statement->bindParam(':center_count', $data['ct']['center_count']);
  695. $statement->bindParam(':inclusion_month', $data['ct']['inclusion_month']);
  696. $statement->bindParam(':followup_month', $data['ct']['followup_month']);
  697. $statement->bindParam(':visit_per_patient', $data['ct']['visit_per_patient']);
  698. $statement->bindParam(':visit_interval', $data['ct']['visit_interval']);
  699. $statement->bindParam(':image_per_visit', $data['ct']['image_per_visit']);
  700. $statement->bindParam(':video_per_visit', $data['ct']['video_per_visit']);
  701. $statement->bindParam(':measure_per_timepoint', $data['ct']['measure_per_timepoint']);
  702. $statement->bindParam(':comment', addslashes($data['ct']['comment']));
  703. $statement->bindParam(':anon_percent', $data['ct']['anon_percent']);
  704. $statement->bindParam(':fk_user', $userID);
  705. // Error check
  706. if(!$statement->execute()) {
  707. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  708. }
  709. // OK
  710. return array(
  711. 'result' => 'OK',
  712. 'data' => $data
  713. );
  714. }
  715. /**
  716. * Get pacs data.
  717. */
  718. public function ctAdminPacsGet($User) {
  719. $userID = $User->ID;
  720. // centers
  721. $statement = $this->DataInterface->DatabaseConnection->prepare(
  722. "SELECT ct_center.ID, organization.name AS org_name, probe.name AS probe_name FROM organization, probe, ct_center WHERE ct_center.fk_organization = organization.ID AND ct_center.fk_probe = probe.ID ORDER by stamp"
  723. );
  724. // Error check
  725. if(!$statement->execute()) {
  726. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  727. }
  728. $centers = $statement->fetchAll(\PDO::FETCH_ASSOC);
  729. // pacs
  730. $statement = $this->DataInterface->DatabaseConnection->prepare(
  731. "SELECT ID, data FROM settings_pacs WHERE fk_physician IS NULL AND fk_center IS NOT NULL ORDER BY ID"
  732. );
  733. // Error check
  734. if(!$statement->execute()) {
  735. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  736. }
  737. $pacs = $statement->fetchAll(\PDO::FETCH_ASSOC);
  738. foreach($pacs as &$p) {
  739. $p['data'] = json_decode($p['data']);
  740. }
  741. // OK
  742. return array(
  743. 'result' => 'OK',
  744. 'centers' => $centers,
  745. 'ourAET' => 'IIMT',
  746. 'pacs' => $pacs
  747. );
  748. }
  749. /**
  750. *
  751. */
  752. public function ctAdminEchoPost($User, $data) {
  753. $cmdLine = 'echoscu '.$data['serverAddress'].' '.$data['queryPort'].' -v 2>&1';
  754. $output=null;
  755. $retval=null;
  756. exec($cmdLine, $output, $retval);
  757. if($retval !== 0 || count($output)<1) {
  758. return [
  759. 'result' => 'ERROR',
  760. 'cmdLine' => $cmdLine,
  761. 'output' => $output,
  762. 'retval' => $retval
  763. ];
  764. }
  765. return [
  766. 'result' => 'OK',
  767. 'output' => $output
  768. ];
  769. }
  770. /**
  771. * Post pacs data.
  772. */
  773. public function ctAdminPacsPost($User, $data) {
  774. $userID = $User->ID;
  775. $fk_center = $data['data']['centerID'];
  776. // insert
  777. if(intval($data['data']['PACSID'])==0) {
  778. $statement = $this->DataInterface->DatabaseConnection->prepare(
  779. "INSERT INTO settings_pacs VALUES(0, :data, NULL, :fk_center)"
  780. );
  781. unset($data['data']['PACSID']);
  782. $data = json_encode($data['data'], JSON_NUMERIC_CHECK);
  783. $statement->bindParam(':data', $data);
  784. $statement->bindParam(':fk_center', $fk_center);
  785. // Error check
  786. if(!$statement->execute()) {
  787. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  788. }
  789. }
  790. // update
  791. else {
  792. $statement = $this->DataInterface->DatabaseConnection->prepare(
  793. "UPDATE settings_pacs SET data=:data, fk_center=:fk_center WHERE ID = ".$data['data']['PACSID']
  794. );
  795. unset($data['data']['PACSID']);
  796. $data = json_encode($data['data'], JSON_NUMERIC_CHECK);
  797. $statement->bindParam(':data', $data);
  798. $statement->bindParam(':fk_center', $fk_center);
  799. // Error check
  800. if(!$statement->execute()) {
  801. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  802. }
  803. }
  804. // OK
  805. return array(
  806. 'result' => 'OK',
  807. 'data' => $data
  808. );
  809. }
  810. /**
  811. * Auditlog data.
  812. */
  813. public function ctAdminAuditLogPost($User, $data) {
  814. $userID = $User->ID;
  815. $start = $data['start'];
  816. $end = $data['end'];
  817. $statement = $this->DataInterface->DatabaseConnection->prepare(
  818. "SELECT A.*, R.* FROM iimt_mathcloud_audit.ray R, iimt_mathcloud_audit.activity A WHERE A.ID_ray = R.ID AND DATE(A.stamp) >= '$start' AND DATE(A.stamp) <= '$end' ORDER BY A.stamp"
  819. );
  820. // Error check
  821. if(!$statement->execute()) {
  822. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  823. }
  824. $data = $statement->fetchAll();
  825. $header = [
  826. 'Activity ID', 'Ray ID', 'Activity data', 'Activity stamp',
  827. 'Ray ID', 'User agent', 'API key', 'IP data', 'Location data', 'User data', 'Activity stamp'
  828. ];
  829. $header = implode(';', $header);
  830. $res = [];
  831. $res[] = $header;
  832. foreach($data as $d) {
  833. $line = implode(';', [
  834. '"'.$d[0].'"', '"'.$d[1].'"', '"'.$d[2].'"', '"'.$d[3].'"', '"'.$d[4].'"', '"'.$d[5].'"', '"'.$d[6].'"', '"'.$d[7].'"', '"'.$d[8].'"', '"'.$d[9].'"', '"'.$d[10].'"'
  835. ]);
  836. $res[] = $line;
  837. }
  838. // OK
  839. return array(
  840. 'result' => 'OK',
  841. 'data' => base64_encode(implode("\n", $res)),
  842. 'start' => $start,
  843. 'end' => $end
  844. );
  845. }
  846. /**
  847. * eCRF data.
  848. */
  849. public function ctAdminAuditECRFPost($User, $data) {
  850. $userID = $User->ID;
  851. // CT general data
  852. $statement = $this->DataInterface->DatabaseConnection->prepare("
  853. SELECT * FROM clinical_trial
  854. ");
  855. // Error check
  856. if(!$statement->execute()) {
  857. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  858. }
  859. $clinical_trial = $statement->fetchAll(\PDO::FETCH_ASSOC)[0];
  860. $od = '../../storage/tmp/'.$clinical_trial['number'].'/';
  861. \Tools\FS::mkpath($od);
  862. $data = [];
  863. // header
  864. $data[] =
  865. 'Visit_PatientID,Visit_Date,Visit_Created,Visit_Completion,Visit_Area,'.
  866. 'Visit_ReaderID,Visit_InvestigatorID,Visit_CenterName,'.
  867. 'Media_Location,Media_Incidence,Media_Filename,Media_Width,Media_Height,Media_PixelWidth,Media_PixelHeight,Media_FrameCount,Media_FramePerSecond,'.
  868. 'Measure_Created,Measure_Frame,Measure_Distance,Measure_ImtMean,Measure_ImtMax,Measure_ImtStddev,Measure_IntimaMean,Measure_MediaMean,Measure_NearWall,Measure_QualityIndex,Measure_NumberOfPoints';
  869. // visit
  870. $statement = $this->DataInterface->DatabaseConnection->prepare("
  871. SELECT patient.ctPatientID, patient.fk_user AS fk_investigator, visit.*
  872. FROM patient, visit
  873. WHERE patient.ID = visit.fk_patient
  874. AND visit.completed IS NOT NULL
  875. AND visit.area = 'carotid'
  876. ");
  877. // Error check
  878. if(!$statement->execute()) {
  879. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  880. }
  881. $visits = $statement->fetchAll(\PDO::FETCH_ASSOC);
  882. foreach($visits as $visit) {
  883. // center
  884. $fk_investigator = $visit['fk_investigator'];
  885. $statement = $this->DataInterface->DatabaseConnection->prepare("
  886. SELECT organization.name
  887. FROM user, organization, ct_center
  888. WHERE user.ID = $fk_investigator
  889. AND user.fk_center = ct_center.ID
  890. AND ct_center.fk_organization = organization.ID
  891. ");
  892. // Error check
  893. if(!$statement->execute()) {
  894. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  895. }
  896. $center = $statement->fetchAll(\PDO::FETCH_ASSOC)[0];
  897. $fk_visit = $visit['ID'];
  898. // media
  899. $statement = $this->DataInterface->DatabaseConnection->prepare("
  900. SELECT media.*
  901. FROM media
  902. WHERE fk_visit = $fk_visit
  903. ");
  904. // Error check
  905. if(!$statement->execute()) {
  906. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  907. }
  908. $medias = $statement->fetchAll(\PDO::FETCH_ASSOC);
  909. foreach($medias as $media) {
  910. $fk_media = $media['ID'];
  911. // measure
  912. $statement = $this->DataInterface->DatabaseConnection->prepare("
  913. SELECT measure.*
  914. FROM measure
  915. WHERE fk_media = $fk_media
  916. AND type = 'imt'
  917. ");
  918. // Error check
  919. if(!$statement->execute()) {
  920. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  921. }
  922. $measures = $statement->fetchAll(\PDO::FETCH_ASSOC);
  923. // save file
  924. if(count($measures)) {
  925. copy('../../storage/media/'.$visit['ID'].'/'.$media['filename'], $od.'/'.$media['filename']);
  926. }
  927. foreach($measures as $measure) {
  928. $V['Visit_PatientID'] = $visit['ctPatientID'];
  929. $V['Visit_Date'] = $visit['visitDate'];
  930. $V['Visit_Created'] = $visit['created'];
  931. $V['Visit_Completion'] = $visit['completed'];
  932. $V['Visit_Area'] = $visit['area'];
  933. $V['Visit_ReaderID'] = $visit['fk_reader'];
  934. $V['Visit_InvestigatorID'] = $visit['fk_investigator'];
  935. $V['Visit_CenterName'] = $center['name'];
  936. $V['Media_Location'] = $media['location'];
  937. $V['Media_Incidence'] = $media['incidence'];
  938. $V['Media_Filename'] = $media['filename'];
  939. $metrics = json_decode($media['metrics']);
  940. $V['Media_Width'] = $metrics->width;
  941. $V['Media_Height'] = $metrics->height;
  942. $V['Media_PixelWidth'] = $metrics->pxwidth;
  943. $V['Media_PixelHeight'] = $metrics->pxheight;
  944. $V['Media_FrameCount'] = $metrics->frameCount;
  945. $V['Media_FramePerSecond'] = $metrics->fps;
  946. $V['Measure_Created'] = $measure['created'];
  947. $V['Measure_Frame'] = $measure['frame'];
  948. $computation = json_decode($measure['computation']);
  949. $V['Measure_Distance'] = $computation->distance;
  950. $V['Measure_ImtMean'] = $computation->imt_mean;
  951. $V['Measure_ImtMax'] = $computation->imt_max;
  952. $V['Measure_ImtStddev'] = $computation->imt_stddev;
  953. $V['Measure_IntimaMean'] = $computation->intima_mean;
  954. $V['Measure_MediaMean'] = $computation->media_mean;
  955. $V['Measure_Location'] = $computation->nearWall?'Proximal':'Distal';
  956. $V['Measure_QualityIndex'] = $computation->qualityIndex;
  957. $V['Measure_NumberOfPoints'] = $computation->numberOfPoints;
  958. //$data[] = $V;
  959. $data[] = implode(",", $V);
  960. }
  961. }
  962. }
  963. unlink('../../storage/tmp/'.$clinical_trial['number']);
  964. // make archive
  965. $dst = '../../storage/tmp/'.$clinical_trial['number'].'.zip';
  966. unlink($dst);
  967. $cmdLine = 'cd ../../storage/tmp && zip -r '.$clinical_trial['number'].'.zip '.$clinical_trial['number'].'/ 2>&1';
  968. $output=null;
  969. $retval=null;
  970. exec($cmdLine, $output, $retval);
  971. // error
  972. if($retval !== 0 || count($output)<1) {
  973. return [
  974. 'result' => 'ERROR',
  975. 'cmdLine' => $cmdLine,
  976. 'output' => $output,
  977. 'retval' => $retval
  978. ];
  979. }
  980. // make csv
  981. unlink('../../storage/tmp/'.$clinical_trial['number'].'.csv');
  982. file_put_contents('../../storage/tmp/'.$clinical_trial['number'].'.csv', implode("\n", $data));
  983. // OK
  984. return array(
  985. 'result' => 'OK',
  986. 'clinical_trial' => $clinical_trial,
  987. //'data' => $data,
  988. 'csv' => 'tmp/'.$clinical_trial['number'].'.csv',
  989. 'zip' => 'tmp/'.$clinical_trial['number'].'.zip'
  990. );
  991. }
  992. /**
  993. *
  994. */
  995. public function ctAdminOverviewGet($User) {
  996. $userID = $User->ID;
  997. // settings
  998. $statement = $this->DataInterface->DatabaseConnection->prepare(
  999. "SELECT * FROM clinical_trial"
  1000. );
  1001. if(!$statement->execute()) {
  1002. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1003. }
  1004. $settings = $statement->fetchAll(\PDO::FETCH_ASSOC)[0];
  1005. // active centers
  1006. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1007. "SELECT DISTINCT(ct_center.ID) FROM ct_center, user, patient WHERE patient.fk_user = user.ID AND user.type = 'investigator' AND user.fk_center = ct_center.ID"
  1008. );
  1009. if(!$statement->execute()) {
  1010. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1011. }
  1012. $activeCenters = count($statement->fetchAll(\PDO::FETCH_ASSOC));
  1013. // included patients
  1014. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1015. "SELECT COUNT(patient.ID) AS cnt FROM patient, user WHERE patient.fk_user = user.ID AND user.type = 'investigator'"
  1016. );
  1017. if(!$statement->execute()) {
  1018. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1019. }
  1020. $includedPatients = $statement->fetchAll(\PDO::FETCH_ASSOC)[0]['cnt'];
  1021. // completed timepoints
  1022. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1023. "SELECT COUNT(visit.ID) FROM visit, user WHERE visit.fk_reader = user.ID AND user.type = 'reader' AND visit.completed IS NOT NULL"
  1024. );
  1025. if(!$statement->execute()) {
  1026. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1027. }
  1028. $completedTimepoints = $statement->fetchAll(\PDO::FETCH_ASSOC)[0]['cnt'];
  1029. // patients & timepoints
  1030. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1031. SELECT DATE_FORMAT(patient.created, '%Y-%m') AS m, COUNT(patient.ID) AS patients
  1032. FROM patient, user
  1033. WHERE patient.fk_user = user.ID AND user.type = 'investigator'
  1034. GROUP BY DATE_FORMAT(patient.created, '%Y-%m')
  1035. ");
  1036. // Error check
  1037. if(!$statement->execute()) {
  1038. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1039. }
  1040. $resPatients = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1041. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1042. SELECT DATE_FORMAT(visit.created, '%Y-%m') AS m, COUNT(visit.ID) AS timepoints
  1043. FROM patient, visit, user
  1044. WHERE visit.fk_patient = patient.ID AND patient.fk_user = user.ID AND user.type = 'investigator'
  1045. GROUP BY DATE_FORMAT(visit.created, '%Y-%m')
  1046. ");
  1047. // Error check
  1048. if(!$statement->execute()) {
  1049. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1050. }
  1051. $resVisits = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1052. $patientsTimepoints = [];
  1053. $start = (new \DateTime($resPatients[0]['m'].'-01'))->modify('first day of this month');
  1054. $end = (new \DateTime(date('Y-m-d')))->modify('first day of next month');
  1055. $interval = \DateInterval::createFromDateString('1 month');
  1056. $period = new \DatePeriod($start, $interval, $end);
  1057. foreach($period as $dt) {
  1058. $patientsTimepoints[] = array('m' => $dt->format("Y-m"), 'patients' => 0, 'timepoints' => 0);
  1059. }
  1060. foreach($resPatients as $R) {
  1061. foreach($patientsTimepoints as &$PT) {
  1062. if($PT['m'] == $R['m']) {
  1063. $PT['patients'] = intval($R['patients']);
  1064. }
  1065. }
  1066. }
  1067. foreach($resVisits as $R) {
  1068. foreach($patientsTimepoints as &$PT) {
  1069. if($PT['m'] == $R['m']) {
  1070. $PT['timepoints'] = intval($R['timepoints']);
  1071. }
  1072. }
  1073. }
  1074. // readers & measures
  1075. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1076. SELECT DATE_FORMAT(measure.created, '%Y-%m') AS m, COUNT(measure.ID) AS measures, COUNT(DISTINCT measure.fk_user) AS readers
  1077. FROM measure, user
  1078. WHERE measure.fk_user = user.ID AND user.type = 'reader'
  1079. GROUP BY DATE_FORMAT(measure.created, '%Y-%m')
  1080. ");
  1081. // Error check
  1082. if(!$statement->execute()) {
  1083. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1084. }
  1085. $resMeasures = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1086. $readersMeasures = [];
  1087. $start = (new \DateTime($resMeasures[0]['m'].'-01'))->modify('first day of this month');
  1088. $end = (new \DateTime(date('Y-m-d')))->modify('first day of next month');
  1089. $interval = \DateInterval::createFromDateString('1 month');
  1090. $period = new \DatePeriod($start, $interval, $end);
  1091. foreach($period as $dt) {
  1092. $readersMeasures[] = array('m' => $dt->format("Y-m"), 'readers' => 0, 'measures' => 0);
  1093. }
  1094. foreach($resMeasures as $R) {
  1095. foreach($readersMeasures as &$RM) {
  1096. if($RM['m'] == $R['m']) {
  1097. $RM['measures'] = intval($R['measures']);
  1098. $RM['readers'] = intval($R['readers']);
  1099. }
  1100. }
  1101. }
  1102. // OK
  1103. return array(
  1104. 'result' => 'OK',
  1105. 'settings' => $settings,
  1106. 'activeCenters' => $activeCenters,
  1107. 'includedPatients' => $includedPatients,
  1108. 'completedTimepoints' => $completedTimepoints,
  1109. 'patientsTimepoints' => $patientsTimepoints,
  1110. 'readersMeasures' => $readersMeasures
  1111. );
  1112. }
  1113. /**
  1114. *
  1115. */
  1116. public function ctAdminInvestigatorsGet($User, $ID) {
  1117. $userID = $User->ID;
  1118. // select users
  1119. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1120. "SELECT * FROM user WHERE type = 'investigator'"
  1121. );
  1122. // Error check
  1123. if(!$statement->execute()) {
  1124. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1125. }
  1126. $users = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1127. $userData = [];
  1128. foreach($users as &$U) {
  1129. // select visits
  1130. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1131. SELECT
  1132. patient.ctPatientID,
  1133. V.*,
  1134. (SELECT COUNT(media.ID) FROM media WHERE JSON_VALUE(media.metrics, '$.fps') IS NULL AND media.fk_visit = V.ID) as imageCount,
  1135. (SELECT COUNT(media.ID) FROM media WHERE media.fk_visit = V.ID) as mediaCount
  1136. FROM patient, visit V
  1137. WHERE V.fk_patient = patient.ID AND patient.fk_user = ".$U['ID']."
  1138. ORDER BY V.visitDate DESC
  1139. ");
  1140. // Error check
  1141. if(!$statement->execute()) {
  1142. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1143. }
  1144. $userData[$U['ID']]['visits'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1145. /*foreach($userData[$U['ID']]['visits'] as &$V) {
  1146. // select media
  1147. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1148. SELECT * FROM media
  1149. WHERE fk_visit = ".$V['ID']."
  1150. ");
  1151. // Error check
  1152. if(!$statement->execute()) {
  1153. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1154. }
  1155. $V['media'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1156. foreach($V['media'] as &$M) {
  1157. $M['metrics'] = json_decode($M['metrics']);
  1158. // select measure
  1159. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1160. SELECT * FROM measure
  1161. WHERE fk_media = ".$M['ID']."
  1162. ");
  1163. // Error check
  1164. if(!$statement->execute()) {
  1165. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1166. }
  1167. $M['measure'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1168. foreach($M['measure'] as &$MS) {
  1169. $MS['computation'] = json_decode($MS['computation']);
  1170. }
  1171. }
  1172. }*/
  1173. }
  1174. // OK
  1175. return [
  1176. 'result' => 'OK',
  1177. 'ID' => $ID,
  1178. 'users' => $users,
  1179. 'userData' => $userData
  1180. ];
  1181. }
  1182. /**
  1183. *
  1184. */
  1185. public function ctAdminReadersGet($User, $ID) {
  1186. $userID = $User->ID;
  1187. // select users
  1188. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1189. "SELECT * FROM user WHERE type = 'reader'"
  1190. );
  1191. // Error check
  1192. if(!$statement->execute()) {
  1193. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1194. }
  1195. $users = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1196. $userData = [];
  1197. foreach($users as &$U) {
  1198. // select visits
  1199. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1200. SELECT
  1201. P.ctPatientID,
  1202. V.*,
  1203. (SELECT COUNT(media.ID) FROM media WHERE JSON_VALUE(media.metrics, '$.fps') IS NULL AND media.fk_visit = V.ID) as imageCount,
  1204. (SELECT COUNT(media.ID) FROM media WHERE media.fk_visit = V.ID) as mediaCount,
  1205. (SELECT MAX(measure.created) FROM measure, media WHERE media.fk_visit = V.ID AND media.ID = measure.fk_media) as measureLastDate
  1206. FROM patient P, visit V
  1207. WHERE V.fk_patient = P.ID AND V.fk_reader = ".$U['ID']."
  1208. ORDER BY V.visitDate DESC
  1209. ");
  1210. // Error check
  1211. if(!$statement->execute()) {
  1212. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1213. }
  1214. $userData[$U['ID']]['visits'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1215. foreach($userData[$U['ID']]['visits'] as &$V) {
  1216. // select media
  1217. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1218. SELECT * FROM media
  1219. WHERE fk_visit = ".$V['ID']."
  1220. ");
  1221. // Error check
  1222. if(!$statement->execute()) {
  1223. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1224. }
  1225. $V['media'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1226. foreach($V['media'] as &$M) {
  1227. $M['metrics'] = json_decode($M['metrics']);
  1228. // select measure
  1229. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1230. SELECT * FROM measure
  1231. WHERE fk_media = ".$M['ID']."
  1232. ");
  1233. // Error check
  1234. if(!$statement->execute()) {
  1235. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1236. }
  1237. $M['measure'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1238. foreach($M['measure'] as &$MS) {
  1239. $MS['computation'] = json_decode($MS['computation']);
  1240. }
  1241. }
  1242. }
  1243. }
  1244. // OK
  1245. return [
  1246. 'result' => 'OK',
  1247. 'ID' => $ID,
  1248. 'users' => $users,
  1249. 'userData' => $userData
  1250. ];
  1251. }
  1252. }
  1253. }