tripal.user.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. <?php
  2. function tripal_user_get_files($uid) {
  3. $directory = [];
  4. // Get all of the files that have been uploaded by the user.
  5. $sql = "
  6. SELECT FM.fid, FM.filename, FM.uri, FM.uid, FM.filesize, TGEF.expiration_date
  7. FROM {file_managed} FM
  8. INNER JOIN {file_usage} FU on FM.fid = FU.fid and FM.uid = :user_id
  9. LEFT JOIN {tripal_expiration_files} TGEF on TGEF.fid = FU.fid
  10. WHERE FU.module = 'tripal'
  11. ORDER BY FM.uri
  12. ";
  13. $files = db_query($sql, [':user_id' => $uid]);
  14. $rows = [];
  15. While ($file = $files->fetchObject()) {
  16. // Don't list files that don't exist on the file system.
  17. if (!file_exists($file->uri)) {
  18. continue;
  19. }
  20. // Files have to be in the User's directory.
  21. if (!preg_match('/^public:\/\/tripal\/users\//', $file->uri)) {
  22. continue;
  23. }
  24. // If the expiration date is somehow not set, then set it.
  25. if (!$file->expiration_date) {
  26. $file->expiration_date = tripal_reset_file_expiration($file->fid);
  27. }
  28. // Organize the file into it's directory structure.
  29. $rpath = preg_replace('/^public:\/\/tripal\/users\/' . $uid . '\//', '', $file->uri);
  30. $paths = explode('/', $rpath);
  31. _tripal_user_build_files_dir($directory, $paths, $file);
  32. }
  33. return $directory;
  34. }
  35. /**
  36. * A recursive helper function for building the directory file tree.
  37. *
  38. * @param $directory
  39. * The $directory array into which the file will be placed.
  40. * @param $paths
  41. * An containing the directory path of the file. Each Directory
  42. * is a separate element of the array.
  43. * @param $file
  44. * The file object to add to the $directory object.
  45. */
  46. function _tripal_user_build_files_dir(&$directory, $paths, $file) {
  47. $path = array_shift($paths);
  48. if (count($paths) == 0) {
  49. $directory[$path] = $file;
  50. }
  51. else {
  52. _tripal_user_build_files_dir($directory[$path], $paths, $file);
  53. }
  54. }
  55. /**
  56. * Generates an item list of the files.
  57. *
  58. * The results from this function can be passed to the theme_item_list function
  59. * and then themed as a file tree..
  60. *
  61. * @param $files_list
  62. * The array as returned by tripal_user_get_files().
  63. *
  64. * @return
  65. * An item list.
  66. */
  67. function tripal_user_get_files_item_list($files_list, &$i = 0) {
  68. $items = [];
  69. // Add a header row
  70. if ($i == 0) {
  71. $items[] = [
  72. 'data' => '<span><b>File</b></span>' .
  73. '<span class="file-expires"><b>Expires</b></span>' .
  74. '<span class="file-size"><b>Size</b></span>',
  75. ];
  76. }
  77. // Iterate through each file and recursively add it to our items array.
  78. foreach ($files_list as $filename => $file) {
  79. $i++;
  80. // If this is a folder then recurse.
  81. if (is_array($file)) {
  82. $items[] = [
  83. 'data' => $filename,
  84. 'children' => tripal_user_get_files_item_list($file, $i),
  85. 'class' => [
  86. 'tree-node-folder',
  87. 'tree-node-closed',
  88. ($i % 2 == 0) ? 'even' : 'odd',
  89. ],
  90. ];
  91. }
  92. // If this is a file then give details for it.
  93. else {
  94. $datediff = $file->expiration_date - time();
  95. $dayleft = round($datediff / (60 * 60 * 24));
  96. if ($dayleft < 0) {
  97. $dayleft = 0;
  98. }
  99. $expiration = $file->expiration_date ? date('Y-m-d', $file->expiration_date) : '';
  100. $items[] = [
  101. 'data' => '<span class="file-details"><span class="file-name">' . $filename . '</span>' .
  102. '<span class="file-expires">' . $dayleft . ' days</span>' .
  103. '<span class="file-size">' . tripal_format_bytes($file->filesize) . '</span></span>',
  104. 'class' => ['tree-node-file', ($i % 2 == 0) ? 'even' : 'odd'],
  105. 'fid' => $file->fid,
  106. 'uid' => $file->uid,
  107. ];
  108. }
  109. }
  110. return $items;
  111. }
  112. /**
  113. * Gets the list of collections that have not yet generated files.
  114. *
  115. * @param $uid
  116. * The ID of the user.
  117. */
  118. function tripal_user_files_get_pending_collections_table($uid) {
  119. $collections = db_select('tripal_collection', 'tc')
  120. ->fields('tc', ['collection_id'])
  121. ->condition('uid', $uid)
  122. ->orderBy('tc.collection_name')
  123. ->execute();
  124. $headers = ['Name', 'Download Formats', 'Actions'];
  125. $rows = [];
  126. while ($collection_id = $collections->fetchField()) {
  127. $collection = new TripalEntityCollection();
  128. $collection->load($collection_id);
  129. $downloads = [];
  130. $formatters = $collection->getFormatters();
  131. $formatter_labels = [];
  132. $status = 'complete';
  133. foreach ($formatters as $class_name => $label) {
  134. $formatter_labels[] = $label;
  135. $outfile = $collection->getOutfilePath($class_name);
  136. if (file_exists($outfile)) {
  137. continue;
  138. }
  139. else {
  140. $status = 'pending';
  141. }
  142. }
  143. if ($status == 'pending') {
  144. $rows[] = [
  145. 'data' => [
  146. $collection->getName(),
  147. implode(', ', $formatters),
  148. l('Create Files', 'user/' . $uid . '/data-collections/generate/' . $collection_id) . ' | ' .
  149. l('View', 'user/' . $uid . '/data-collections/' . $collection_id . '/view') . ' | ' .
  150. l('Delete', 'user/' . $uid . '/data-collections/' . $collection_id . '/delete'),
  151. ],
  152. ];
  153. }
  154. }
  155. return theme_table([
  156. 'header' => $headers,
  157. 'rows' => $rows,
  158. 'attributes' => [],
  159. 'caption' => '',
  160. 'colgroups' => [],
  161. 'sticky' => TRUE,
  162. 'empty' => t('You currently have no pending data collections.'),
  163. ]);
  164. }
  165. /**
  166. * Provides the page with a list of files uploaded by the user.
  167. *
  168. * @param $uid
  169. * The user ID.
  170. *
  171. * @return
  172. * A Drupal render array.
  173. */
  174. function tripal_user_files_page($uid) {
  175. drupal_add_css(drupal_get_path('module', 'tripal') . '/theme/css/tripal_user_files.css');
  176. drupal_add_js(drupal_get_path('module', 'tripal') . '/theme/js/tripal.user_files.js', 'file');
  177. $user_files = tripal_user_get_files($uid);
  178. $items = tripal_user_get_files_item_list($user_files);
  179. $theme_files = theme_item_list([
  180. 'items' => $items,
  181. 'title' => '',
  182. 'type' => 'ul',
  183. 'attributes' => [
  184. 'id' => 'tripal-user-file-tree',
  185. ],
  186. ]);
  187. $data_collections = tripal_user_files_get_pending_collections_table($uid);
  188. // Get the user quota settings.
  189. $quota = tripal_get_user_quota($uid);
  190. $usage = tripal_get_user_usage($uid);
  191. $content = [
  192. 'page_title' => [
  193. '#type' => 'markup',
  194. '#markup' => '<h2>Your Files</h2>',
  195. ],
  196. 'page_description' => [
  197. '#type' => 'markup',
  198. '#markup' => '<p>' . t('Each user is allowed to consume a limited amount of space for files. This page provides details about your current usage, your limits and files in your account.') . '</p>',
  199. ],
  200. 'usage' => [
  201. '#type' => 'item',
  202. '#title' => 'Current Usage',
  203. '#markup' => tripal_format_bytes($usage),
  204. '#description' => t('The total number of bytes you currently consume.'),
  205. ],
  206. 'quota' => [
  207. '#type' => 'item',
  208. '#title' => 'Current Quota',
  209. '#markup' => tripal_format_bytes($quota->custom_quota),
  210. '#description' => t('The maximum number of bytes of files you can upload.'),
  211. ],
  212. 'expiration' => [
  213. '#type' => 'item',
  214. '#title' => 'Current Days to Expire',
  215. '#markup' => $quota->custom_expiration,
  216. '#description' => t('The number of days a file will remain on the server before deletion. The expiration of date of a file can be renewed by selecting the file name and then selecting the "Renew" link in the file details table.'),
  217. ],
  218. 'data_collections' => [
  219. '#type' => 'item',
  220. '#title' => 'Pending Data Collections',
  221. '#markup' => $data_collections,
  222. '#description' => t('Data collections allow you to store custom sets of data
  223. for use on this site. Typically data collections are created using search
  224. tools. The above data collections are waiting to be generated. You must
  225. generate the files before you can use them.'),
  226. ],
  227. 'file_list' => [
  228. '#type' => 'item',
  229. '#title' => 'File Browser',
  230. '#markup' => $theme_files,
  231. ],
  232. 'file_details' => [
  233. '#type' => 'item',
  234. '#title' => 'File Details',
  235. '#markup' => '<div id="tripal-user-file-details">Click a file above for details.</div>',
  236. ],
  237. ];
  238. if ($usage < $quota->custom_quota) {
  239. drupal_set_message('Your file usage is currently below the file quota limit.');
  240. }
  241. else {
  242. drupal_set_message('Your file usage is currently over your file quota limit. Please remove some files before uploading more', 'warning');
  243. }
  244. return $content;
  245. }
  246. /**
  247. * User action to renew the expiration of a file.
  248. *
  249. * Adds the current time and the expiration date (either from default or if
  250. * the user has a custom expiration date) to tripal_expiration_files
  251. * table.
  252. *
  253. **/
  254. function tripal_renew_file($fid) {
  255. $file = file_load($fid);
  256. $success = tripal_reset_file_expiration($fid);
  257. if ($success) {
  258. drupal_set_message('Successfully updated expiration date.');
  259. }
  260. drupal_goto('user/' . $file->uid . '/files/');
  261. }
  262. /**
  263. * Downloads a file.
  264. *
  265. * @param $fid
  266. * The File ID of the file to be downloaded.
  267. */
  268. function tripal_download_file($fid) {
  269. $file = file_load($fid);
  270. if (file_exists($file->uri)) {
  271. $headers = [];
  272. $headers['Content-Type'] = $file->filemime;
  273. $headers['Content-Disposition'] = 'attachment; filename=' . $file->filename;
  274. $headers['Content-Length'] = $file->filesize;
  275. file_transfer($file->uri, $headers);
  276. }
  277. else {
  278. drupal_set_message('Can not download. The file no longer exists on the server.', 'error');
  279. drupal_goto('user/' . $file->uid . '/files/');
  280. }
  281. }
  282. /**
  283. * Provides a confirmation form for deleting an uploaded file.
  284. */
  285. function tripal_delete_file_form($form, $form_state, $uid, $fid) {
  286. $form = [];
  287. $file = file_load($fid);
  288. $form['uid'] = [
  289. '#type' => 'value',
  290. '#value' => $uid,
  291. ];
  292. $form['fid'] = [
  293. '#type' => 'value',
  294. '#value' => $fid,
  295. ];
  296. return confirm_form($form,
  297. t('Confirm deletion of the file named "' . $file->filename . '"?'),
  298. 'user/' . $uid . '/files/'
  299. );
  300. }
  301. /**
  302. * Implements a form submit for deleting an uploaded file.
  303. */
  304. function tripal_delete_file_form_submit($form, &$form_state) {
  305. $fid = $form_state['values']['fid'];
  306. $uid = $form_state['values']['uid'];
  307. $file = file_load($fid);
  308. // Remove the file from the file_usage table for all entries that link
  309. // to the tripal module.
  310. file_usage_delete($file, 'tripal', NULL, NULL, 0);
  311. // Get any remaining usage for other modules
  312. $file_usage = file_usage_list($file);
  313. // If this file is still used by the tripal module then something
  314. // didn't work right.
  315. if (in_array('tripal', $file_usage)) {
  316. drupal_set_message('The file could not be removed. Please contact the site administrator.', 'error');
  317. }
  318. // If there is no other usage of this file from other modules then delete it.
  319. if (count(array_keys($file_usage)) == 0) {
  320. if (file_unmanaged_delete($file->uri)) {
  321. // Also remove the md5 checksum.
  322. if (file_exists(file_unmanaged_delete($file->uri . '.md5'))) {
  323. file_unmanaged_delete($file->uri . '.md5');
  324. }
  325. drupal_set_message('The file has been fully removed.');
  326. }
  327. else {
  328. drupal_set_message('The file has removed from this list and does not count against your quota, but other components of this site rely on this file. Thus it has not been fully removed.');
  329. }
  330. }
  331. drupal_goto('user/' . $file->uid . '/files/');
  332. }
  333. /**
  334. * Provides details about a file.
  335. */
  336. function tripal_view_file($uid, $fid) {
  337. $file = file_load($fid);
  338. $usage = file_usage_list($file);
  339. // Check to see if this is a data collection.
  340. $collection = NULL;
  341. $collection_ctypes = [];
  342. $collection_field_list = [];
  343. $collection_formatters = [];
  344. $collection_entities = 0;
  345. if (array_key_exists('tripal', $usage)) {
  346. if (array_key_exists('data_collection', $usage['tripal'])) {
  347. $collection_id = array_keys($usage['tripal']['data_collection'])[0];
  348. $collection = new TripalEntityCollection();
  349. $collection->load($collection_id);
  350. // Get the content types for this data collection.
  351. $cbundles = $collection->getBundles();
  352. foreach ($cbundles as $cbundle) {
  353. $eids = $collection->getEntityIDs($cbundle->bundle_name);
  354. $fields = $collection->getFieldIDs($cbundle->bundle_name);
  355. // Convert local field IDs to their names.
  356. if (!$cbundle->site_id) {
  357. $bundle = tripal_load_bundle_entity(['name' => $cbundle->bundle_name]);
  358. $collection_ctypes[] = $bundle->label;
  359. foreach ($fields as $field_id) {
  360. $field = field_info_field_by_id($field_id);
  361. $instance = field_info_instance('TripalEntity', $field['field_name'], $bundle->name);
  362. $collection_field_list[] = $instance['label'];
  363. $field_formatters = tripal_get_field_field_formatters($field, $instance);
  364. foreach ($field_formatters as $class_name => $label) {
  365. tripal_load_include_downloader_class($class_name);
  366. $collection_formatters[] = $class_name::$label . ' (' . $class_name::$full_label . ')';
  367. }
  368. }
  369. }
  370. // Convert remote field IDs to their names.
  371. // TODO: add in retrieval of remote details.
  372. $collection_entities += count($eids);
  373. }
  374. }
  375. }
  376. $headers = [];
  377. $rows = [];
  378. $actions = l('Delete', "user/$uid/files/$file->fid/delete") . '<br>' .
  379. l('Download', "user/$uid/files/$file->fid/download") . '<br>' .
  380. l('Renew', "user/$uid/files/$file->fid/renew");
  381. // Name row
  382. $rows[] = [
  383. [
  384. 'data' => 'File Name',
  385. 'header' => TRUE,
  386. 'width' => '20%',
  387. ],
  388. $file->filename,
  389. ];
  390. $date_uploaded = date('Y-m-d H:i:s', $file->timestamp);
  391. $rows[] = [
  392. [
  393. 'data' => 'Create Date',
  394. 'header' => TRUE,
  395. 'width' => '20%',
  396. ],
  397. $date_uploaded,
  398. ];
  399. $expiration_date = db_select('tripal_expiration_files', 'tgef')
  400. ->fields('tgef', ['expiration_date'])
  401. ->condition('fid', $fid)
  402. ->execute()
  403. ->fetchField();
  404. $expiration = $expiration_date ? date('Y-m-d H:i:s', $expiration_date) : '';
  405. $rows[] = [
  406. [
  407. 'data' => 'Expiration Date',
  408. 'header' => TRUE,
  409. 'width' => '20%',
  410. ],
  411. $expiration,
  412. ];
  413. $md5_file = $file->uri . '.md5';
  414. if (file_exists($md5_file)) {
  415. $rows[] = [
  416. [
  417. 'data' => 'MD5',
  418. 'header' => TRUE,
  419. 'width' => '20%',
  420. ],
  421. file_get_contents($md5_file),
  422. ];
  423. }
  424. $rows[] = [
  425. [
  426. 'data' => 'Actions',
  427. 'header' => TRUE,
  428. 'width' => '20%',
  429. ],
  430. $actions,
  431. ];
  432. $file_content = theme_table([
  433. 'header' => $headers,
  434. 'rows' => $rows,
  435. 'attributes' => [],
  436. 'sticky' => FALSE,
  437. 'caption' => '',
  438. 'colgroups' => [],
  439. 'empty' => '',
  440. ]);
  441. $collection_content = '';
  442. if ($collection) {
  443. $rows = [];
  444. $rows[] = [
  445. [
  446. 'data' => 'Description',
  447. 'header' => TRUE,
  448. 'width' => '20%',
  449. ],
  450. $collection->getDescription(),
  451. ];
  452. $rows[] = [
  453. [
  454. 'data' => 'Content types',
  455. 'header' => TRUE,
  456. 'width' => '20%',
  457. ],
  458. join(', ', $collection_ctypes),
  459. ];
  460. $rows[] = [
  461. [
  462. 'data' => 'Fields',
  463. 'header' => TRUE,
  464. 'width' => '20%',
  465. ],
  466. join(', ', array_unique($collection_field_list)),
  467. ];
  468. $rows[] = [
  469. [
  470. 'data' => 'Supported File Types',
  471. 'header' => TRUE,
  472. 'width' => '20%',
  473. ],
  474. join(', ', array_unique($collection_formatters)),
  475. ];
  476. $rows[] = [
  477. [
  478. 'data' => 'Records',
  479. 'header' => TRUE,
  480. 'width' => '20%',
  481. ],
  482. number_format($collection_entities),
  483. ];
  484. $rows[] = [
  485. [
  486. 'data' => 'Actions',
  487. 'header' => TRUE,
  488. 'width' => '20%',
  489. ],
  490. l('Delete', 'user/' . $uid . '/data-collections/' . $collection->getCollectionID() . '/delete'),
  491. ];
  492. $collection_content = '<b>Collection Details</b>' . theme_table([
  493. 'header' => $headers,
  494. 'rows' => $rows,
  495. 'attributes' => [],
  496. 'sticky' => FALSE,
  497. 'caption' => '',
  498. 'colgroups' => [],
  499. 'empty' => '',
  500. ]);
  501. }
  502. drupal_json_output($file_content . $collection_content);
  503. }