CtAdminInterface.class.php 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392
  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. // rm old files
  852. $now = time();
  853. $files = glob('../../storage/tmp/*.zip');
  854. foreach($files as $F) {
  855. if ($now - filemtime($F) >= 60 * 60 * 24 * 1) { // 1 day
  856. unlink($F);
  857. }
  858. }
  859. $files = glob('../../storage/tmp/*.csv');
  860. foreach($files as $F) {
  861. if ($now - filemtime($F) >= 60 * 60 * 24 * 1) { // 1 day
  862. unlink($F);
  863. }
  864. }
  865. // CT general data
  866. $statement = $this->DataInterface->DatabaseConnection->prepare("
  867. SELECT * FROM clinical_trial
  868. ");
  869. // Error check
  870. if(!$statement->execute()) {
  871. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  872. }
  873. $clinical_trial = $statement->fetchAll(\PDO::FETCH_ASSOC)[0];
  874. $od = '../../storage/tmp/'.$clinical_trial['number'].'/';
  875. \Tools\FS::mkpath($od);
  876. $data = [];
  877. // header
  878. $data[] =
  879. 'Visit_PatientID,Visit_PatientLastname,Visit_PatientFistname,Visit_PatientBirth,Visit_PatientSex,Visit_ID,Visit_Date,Visit_Created,Visit_Completion,Visit_Area,'.
  880. 'Visit_ReaderID,Visit_InvestigatorID,Visit_CenterName,'.
  881. 'Media_Side,Media_Location,Media_Incidence,Media_Filename,Media_Width,Media_Height,Media_PixelWidth,Media_PixelHeight,Media_FrameCount,Media_FramePerSecond,'.
  882. 'Measure_Created,Measure_Frame,Measure_Distance,Measure_ImtMean,Measure_ImtMax,Measure_ImtStddev,Measure_IntimaMean,Measure_MediaMean,Measure_NearWall,Measure_QualityIndex,Measure_NumberOfPoints';
  883. // visit
  884. $statement = $this->DataInterface->DatabaseConnection->prepare("
  885. SELECT patient.*, patient.ctPatientID, patient.fk_user AS fk_investigator, visit.*
  886. FROM patient, visit
  887. WHERE patient.ID = visit.fk_patient
  888. AND visit.completed IS NOT NULL
  889. AND visit.area = 'carotid'
  890. ");
  891. // Error check
  892. if(!$statement->execute()) {
  893. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  894. }
  895. $visits = $statement->fetchAll(\PDO::FETCH_ASSOC);
  896. foreach($visits as $visit) {
  897. // center
  898. $fk_investigator = $visit['fk_investigator'];
  899. $statement = $this->DataInterface->DatabaseConnection->prepare("
  900. SELECT organization.name
  901. FROM user, organization, ct_center
  902. WHERE user.ID = $fk_investigator
  903. AND user.fk_center = ct_center.ID
  904. AND ct_center.fk_organization = organization.ID
  905. ");
  906. // Error check
  907. if(!$statement->execute()) {
  908. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  909. }
  910. $center = $statement->fetchAll(\PDO::FETCH_ASSOC)[0];
  911. $fk_visit = $visit['ID'];
  912. // media
  913. $statement = $this->DataInterface->DatabaseConnection->prepare("
  914. SELECT media.*
  915. FROM media
  916. WHERE fk_visit = $fk_visit
  917. ");
  918. // Error check
  919. if(!$statement->execute()) {
  920. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  921. }
  922. $medias = $statement->fetchAll(\PDO::FETCH_ASSOC);
  923. foreach($medias as $media) {
  924. $fk_media = $media['ID'];
  925. // measure
  926. $statement = $this->DataInterface->DatabaseConnection->prepare("
  927. SELECT measure.*
  928. FROM measure
  929. WHERE fk_media = $fk_media
  930. AND type = 'imt'
  931. ");
  932. // Error check
  933. if(!$statement->execute()) {
  934. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  935. }
  936. $measures = $statement->fetchAll(\PDO::FETCH_ASSOC);
  937. // save file
  938. if(count($measures)) {
  939. copy('../../storage/media/'.$visit['ID'].'/'.$media['filename'], $od.'/'.$media['filename']);
  940. }
  941. foreach($measures as $measure) {
  942. $V['Visit_PatientID'] = $visit['ctPatientID'];
  943. $V['Visit_PatientLastname'] = $visit['lastname'];
  944. $V['Visit_PatientFistname'] = $visit['firstname'];
  945. $V['Visit_PatientBirth'] = $visit['birthDate'];
  946. $V['Visit_PatientSex'] = $visit['gender'];
  947. $V['Visit_ID'] = $visit['number'];
  948. $V['Visit_Date'] = $visit['visitDate'];
  949. $V['Visit_Created'] = $visit['created'];
  950. $V['Visit_Completion'] = $visit['completed'];
  951. $V['Visit_Area'] = $visit['area'];
  952. $V['Visit_ReaderID'] = $visit['fk_reader'];
  953. $V['Visit_InvestigatorID'] = $visit['fk_investigator'];
  954. $V['Visit_CenterName'] = $center['name'];
  955. $V['Media_Side'] = $media['side'];
  956. $V['Media_Location'] = $media['location'];
  957. $V['Media_Incidence'] = $media['incidence'];
  958. $V['Media_Filename'] = $media['filename'];
  959. $metrics = json_decode($media['metrics']);
  960. $V['Media_Width'] = $metrics->width;
  961. $V['Media_Height'] = $metrics->height;
  962. $V['Media_PixelWidth'] = $metrics->pxwidth;
  963. $V['Media_PixelHeight'] = $metrics->pxheight;
  964. $V['Media_FrameCount'] = $metrics->frameCount;
  965. $V['Media_FramePerSecond'] = $metrics->fps;
  966. $V['Measure_Created'] = $measure['created'];
  967. $V['Measure_Frame'] = $measure['frame'];
  968. $computation = json_decode($measure['computation']);
  969. $V['Measure_Distance'] = $computation->distance;
  970. $V['Measure_ImtMean'] = $computation->imt_mean;
  971. $V['Measure_ImtMax'] = $computation->imt_max;
  972. $V['Measure_ImtStddev'] = $computation->imt_stddev;
  973. $V['Measure_IntimaMean'] = $computation->intima_mean;
  974. $V['Measure_MediaMean'] = $computation->media_mean;
  975. $V['Measure_Location'] = $computation->nearWall?'Proximal':'Distal';
  976. $V['Measure_QualityIndex'] = $computation->qualityIndex;
  977. $V['Measure_NumberOfPoints'] = $computation->numberOfPoints;
  978. //$data[] = $V;
  979. $data[] = implode(",", $V);
  980. }
  981. }
  982. }
  983. unlink('../../storage/tmp/'.$clinical_trial['number']);
  984. // make archive
  985. $dst = '../../storage/tmp/'.$clinical_trial['number'].'.zip';
  986. unlink($dst);
  987. $cmdLine = 'cd ../../storage/tmp && zip -r '.$clinical_trial['number'].'.zip '.$clinical_trial['number'].'/ 2>&1';
  988. $output=null;
  989. $retval=null;
  990. exec($cmdLine, $output, $retval);
  991. // error
  992. if($retval !== 0 || count($output)<1) {
  993. return [
  994. 'result' => 'ERROR',
  995. 'cmdLine' => $cmdLine,
  996. 'output' => $output,
  997. 'retval' => $retval
  998. ];
  999. }
  1000. // make csv
  1001. unlink('../../storage/tmp/'.$clinical_trial['number'].'.csv');
  1002. file_put_contents('../../storage/tmp/'.$clinical_trial['number'].'.csv', implode("\n", $data));
  1003. // OK
  1004. return array(
  1005. 'result' => 'OK',
  1006. 'clinical_trial' => $clinical_trial,
  1007. //'data' => $data,
  1008. 'csv' => 'tmp/'.$clinical_trial['number'].'.csv',
  1009. 'zip' => 'tmp/'.$clinical_trial['number'].'.zip'
  1010. );
  1011. }
  1012. /**
  1013. *
  1014. */
  1015. public function ctAdminOverviewGet($User) {
  1016. $userID = $User->ID;
  1017. // settings
  1018. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1019. "SELECT * FROM clinical_trial"
  1020. );
  1021. if(!$statement->execute()) {
  1022. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1023. }
  1024. $settings = $statement->fetchAll(\PDO::FETCH_ASSOC)[0];
  1025. // active centers
  1026. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1027. "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"
  1028. );
  1029. if(!$statement->execute()) {
  1030. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1031. }
  1032. $activeCenters = count($statement->fetchAll(\PDO::FETCH_ASSOC));
  1033. // included patients
  1034. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1035. "SELECT COUNT(patient.ID) AS cnt FROM patient, user WHERE patient.fk_user = user.ID AND user.type = 'investigator'"
  1036. );
  1037. if(!$statement->execute()) {
  1038. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1039. }
  1040. $includedPatients = $statement->fetchAll(\PDO::FETCH_ASSOC)[0]['cnt'];
  1041. // completed timepoints
  1042. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1043. "SELECT COUNT(visit.ID) FROM visit, user WHERE visit.fk_reader = user.ID AND user.type = 'reader' AND visit.completed IS NOT NULL"
  1044. );
  1045. if(!$statement->execute()) {
  1046. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1047. }
  1048. $completedTimepoints = $statement->fetchAll(\PDO::FETCH_ASSOC)[0]['cnt'];
  1049. // patients & timepoints
  1050. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1051. SELECT DATE_FORMAT(patient.created, '%Y-%m') AS m, COUNT(patient.ID) AS patients
  1052. FROM patient, user
  1053. WHERE patient.fk_user = user.ID AND user.type = 'investigator'
  1054. GROUP BY DATE_FORMAT(patient.created, '%Y-%m')
  1055. ");
  1056. // Error check
  1057. if(!$statement->execute()) {
  1058. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1059. }
  1060. $resPatients = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1061. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1062. SELECT DATE_FORMAT(visit.created, '%Y-%m') AS m, COUNT(visit.ID) AS timepoints
  1063. FROM patient, visit, user
  1064. WHERE visit.fk_patient = patient.ID AND patient.fk_user = user.ID AND user.type = 'investigator'
  1065. GROUP BY DATE_FORMAT(visit.created, '%Y-%m')
  1066. ");
  1067. // Error check
  1068. if(!$statement->execute()) {
  1069. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1070. }
  1071. $resVisits = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1072. $patientsTimepoints = [];
  1073. $start = (new \DateTime($resPatients[0]['m'].'-01'))->modify('first day of this month');
  1074. $end = (new \DateTime(date('Y-m-d')))->modify('first day of next month');
  1075. $interval = \DateInterval::createFromDateString('1 month');
  1076. $period = new \DatePeriod($start, $interval, $end);
  1077. foreach($period as $dt) {
  1078. $patientsTimepoints[] = array('m' => $dt->format("Y-m"), 'patients' => 0, 'timepoints' => 0);
  1079. }
  1080. foreach($resPatients as $R) {
  1081. foreach($patientsTimepoints as &$PT) {
  1082. if($PT['m'] == $R['m']) {
  1083. $PT['patients'] = intval($R['patients']);
  1084. }
  1085. }
  1086. }
  1087. foreach($resVisits as $R) {
  1088. foreach($patientsTimepoints as &$PT) {
  1089. if($PT['m'] == $R['m']) {
  1090. $PT['timepoints'] = intval($R['timepoints']);
  1091. }
  1092. }
  1093. }
  1094. // readers & measures
  1095. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1096. SELECT DATE_FORMAT(measure.created, '%Y-%m') AS m, COUNT(measure.ID) AS measures, COUNT(DISTINCT measure.fk_user) AS readers
  1097. FROM measure, user
  1098. WHERE measure.fk_user = user.ID AND user.type = 'reader'
  1099. GROUP BY DATE_FORMAT(measure.created, '%Y-%m')
  1100. ");
  1101. // Error check
  1102. if(!$statement->execute()) {
  1103. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1104. }
  1105. $resMeasures = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1106. $readersMeasures = [];
  1107. $start = (new \DateTime($resMeasures[0]['m'].'-01'))->modify('first day of this month');
  1108. $end = (new \DateTime(date('Y-m-d')))->modify('first day of next month');
  1109. $interval = \DateInterval::createFromDateString('1 month');
  1110. $period = new \DatePeriod($start, $interval, $end);
  1111. foreach($period as $dt) {
  1112. $readersMeasures[] = array('m' => $dt->format("Y-m"), 'readers' => 0, 'measures' => 0);
  1113. }
  1114. foreach($resMeasures as $R) {
  1115. foreach($readersMeasures as &$RM) {
  1116. if($RM['m'] == $R['m']) {
  1117. $RM['measures'] = intval($R['measures']);
  1118. $RM['readers'] = intval($R['readers']);
  1119. }
  1120. }
  1121. }
  1122. // OK
  1123. return array(
  1124. 'result' => 'OK',
  1125. 'settings' => $settings,
  1126. 'activeCenters' => $activeCenters,
  1127. 'includedPatients' => $includedPatients,
  1128. 'completedTimepoints' => $completedTimepoints,
  1129. 'patientsTimepoints' => $patientsTimepoints,
  1130. 'readersMeasures' => $readersMeasures
  1131. );
  1132. }
  1133. /**
  1134. *
  1135. */
  1136. public function ctAdminInvestigatorsGet($User, $ID) {
  1137. $userID = $User->ID;
  1138. // select users
  1139. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1140. "SELECT * FROM user WHERE type = 'investigator'"
  1141. );
  1142. // Error check
  1143. if(!$statement->execute()) {
  1144. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1145. }
  1146. $users = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1147. $userData = [];
  1148. foreach($users as &$U) {
  1149. // select visits
  1150. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1151. SELECT
  1152. patient.ctPatientID,
  1153. V.*,
  1154. (SELECT COUNT(media.ID) FROM media WHERE JSON_VALUE(media.metrics, '$.fps') IS NULL AND media.fk_visit = V.ID) as imageCount,
  1155. (SELECT COUNT(media.ID) FROM media WHERE media.fk_visit = V.ID) as mediaCount
  1156. FROM patient, visit V
  1157. WHERE V.fk_patient = patient.ID AND patient.fk_user = ".$U['ID']."
  1158. ORDER BY V.visitDate DESC
  1159. ");
  1160. // Error check
  1161. if(!$statement->execute()) {
  1162. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1163. }
  1164. $userData[$U['ID']]['visits'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1165. /*foreach($userData[$U['ID']]['visits'] as &$V) {
  1166. // select media
  1167. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1168. SELECT * FROM media
  1169. WHERE fk_visit = ".$V['ID']."
  1170. ");
  1171. // Error check
  1172. if(!$statement->execute()) {
  1173. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1174. }
  1175. $V['media'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1176. foreach($V['media'] as &$M) {
  1177. $M['metrics'] = json_decode($M['metrics']);
  1178. // select measure
  1179. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1180. SELECT * FROM measure
  1181. WHERE fk_media = ".$M['ID']."
  1182. ");
  1183. // Error check
  1184. if(!$statement->execute()) {
  1185. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1186. }
  1187. $M['measure'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1188. foreach($M['measure'] as &$MS) {
  1189. $MS['computation'] = json_decode($MS['computation']);
  1190. }
  1191. }
  1192. }*/
  1193. }
  1194. // OK
  1195. return [
  1196. 'result' => 'OK',
  1197. 'ID' => $ID,
  1198. 'users' => $users,
  1199. 'userData' => $userData
  1200. ];
  1201. }
  1202. /**
  1203. *
  1204. */
  1205. public function ctAdminReadersGet($User, $ID) {
  1206. $userID = $User->ID;
  1207. // select users
  1208. $statement = $this->DataInterface->DatabaseConnection->prepare(
  1209. "SELECT * FROM user WHERE type = 'reader'"
  1210. );
  1211. // Error check
  1212. if(!$statement->execute()) {
  1213. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1214. }
  1215. $users = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1216. $userData = [];
  1217. foreach($users as &$U) {
  1218. // select visits
  1219. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1220. SELECT
  1221. P.ctPatientID,
  1222. V.*,
  1223. (SELECT COUNT(media.ID) FROM media WHERE JSON_VALUE(media.metrics, '$.fps') IS NULL AND media.fk_visit = V.ID) as imageCount,
  1224. (SELECT COUNT(media.ID) FROM media WHERE media.fk_visit = V.ID) as mediaCount,
  1225. (SELECT MAX(measure.created) FROM measure, media WHERE media.fk_visit = V.ID AND media.ID = measure.fk_media) as measureLastDate
  1226. FROM patient P, visit V
  1227. WHERE V.fk_patient = P.ID AND V.fk_reader = ".$U['ID']."
  1228. ORDER BY V.visitDate DESC
  1229. ");
  1230. // Error check
  1231. if(!$statement->execute()) {
  1232. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1233. }
  1234. $userData[$U['ID']]['visits'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1235. foreach($userData[$U['ID']]['visits'] as &$V) {
  1236. // select media
  1237. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1238. SELECT * FROM media
  1239. WHERE fk_visit = ".$V['ID']."
  1240. ");
  1241. // Error check
  1242. if(!$statement->execute()) {
  1243. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1244. }
  1245. $V['media'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1246. foreach($V['media'] as &$M) {
  1247. $M['metrics'] = json_decode($M['metrics']);
  1248. // select measure
  1249. $statement = $this->DataInterface->DatabaseConnection->prepare("
  1250. SELECT * FROM measure
  1251. WHERE fk_media = ".$M['ID']."
  1252. ");
  1253. // Error check
  1254. if(!$statement->execute()) {
  1255. return ['result' => 'ERROR', 'reason' => 'internal_error', 'message' => 'Database error', 'data' => $statement->errorInfo()];
  1256. }
  1257. $M['measure'] = $statement->fetchAll(\PDO::FETCH_ASSOC);
  1258. foreach($M['measure'] as &$MS) {
  1259. $MS['computation'] = json_decode($MS['computation']);
  1260. }
  1261. }
  1262. }
  1263. }
  1264. // OK
  1265. return [
  1266. 'result' => 'OK',
  1267. 'ID' => $ID,
  1268. 'users' => $users,
  1269. 'userData' => $userData
  1270. ];
  1271. }
  1272. }
  1273. }