PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/application/plugins/files/models/ProjectFileRevision.class.php

https://github.com/fb83/Project-Pier
PHP | 501 lines | 214 code | 60 blank | 227 comment | 41 complexity | 34f80e77f6422595ff4777a0d1c92f57 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, AGPL-3.0, LGPL-2.1, GPL-3.0
  1. <?php
  2. /**
  3. * ProjectFileRevision class
  4. *
  5. * @http://www.projectpier.org/
  6. */
  7. class ProjectFileRevision extends BaseProjectFileRevision {
  8. /**
  9. * Message comments are searchable
  10. *
  11. * @var boolean
  12. */
  13. protected $is_searchable = true;
  14. /**
  15. * Array of searchable columns
  16. *
  17. * @var array
  18. */
  19. protected $searchable_columns = array('comment', 'filecontent');
  20. /**
  21. * Parent file object
  22. *
  23. * @var ProjectFile
  24. */
  25. private $file;
  26. /**
  27. * Cached file type object
  28. *
  29. * @var FileType
  30. */
  31. private $file_type;
  32. /**
  33. * Cached show thumbnails configuration option
  34. *
  35. * @var String
  36. */
  37. private $show_thumbnail;
  38. /**
  39. * Construct file revision object
  40. *
  41. * @param void
  42. * @return ProjectFileRevision
  43. */
  44. function __construct() {
  45. $this->addProtectedAttribute('file_id', 'file_type_id', 'system_filename', 'thumb_filename', 'revision_number', 'type_string', 'filesize');
  46. parent::__construct();
  47. $this->show_thumbnail = (config_option('files_show_thumbnails', '1') == '1');
  48. } // __construct
  49. /**
  50. * Return parent file object
  51. *
  52. * @param void
  53. * @return ProjectFile
  54. */
  55. function getFile() {
  56. if (is_null($this->file)) {
  57. $this->file = ProjectFiles::findById($this->getFileId());
  58. } // if
  59. return $this->file;
  60. } // getFile
  61. /**
  62. * Return parent project
  63. *
  64. * @param void
  65. * @return Project
  66. */
  67. function getProject() {
  68. if (is_null($this->project)) {
  69. $file = $this->getFile();
  70. if ($file instanceof ProjectFile) {
  71. $this->project = $file->getProject();
  72. }
  73. } // if
  74. return $this->project;
  75. } // getProject
  76. /**
  77. * Return project ID
  78. *
  79. * @param void
  80. * @return integer
  81. */
  82. function getProjectId() {
  83. $project = $this->getProject();
  84. return $project instanceof Project ? $project->getId() : null;
  85. } // getProjectId
  86. /**
  87. * Return file type object
  88. *
  89. * @param void
  90. * @return FileType
  91. */
  92. function getFileType() {
  93. if (is_null($this->file_type)) {
  94. $this->file_type = FileTypes::findById($this->getFileTypeId());
  95. } // if
  96. return $this->file_type;
  97. } // getFileType
  98. /**
  99. * Return content of this file
  100. *
  101. * @param void
  102. * @return string
  103. */
  104. function getFilePath() {
  105. return FileRepository::getFilePath($this->getRepositoryId());
  106. } // getFilePath
  107. /**
  108. * Return value of 'filename' field
  109. *
  110. * @access public
  111. * @param void
  112. * @return string
  113. */
  114. function getFilename() {
  115. $filename = $this->getColumnValue('filename');
  116. if (!$filename) {
  117. $filename = $this->getFile()->getFilename();
  118. }
  119. return $filename;
  120. } // getFilename()
  121. /**
  122. * Return content of this file
  123. *
  124. * @param void
  125. * @return string
  126. */
  127. function getFileContent() {
  128. try {
  129. return FileRepository::getFileContent($this->getRepositoryId());
  130. } catch(Exception $e) {
  131. return '';
  132. }
  133. } // getFileContent
  134. // ---------------------------------------------------
  135. // Utils
  136. // ---------------------------------------------------
  137. /**
  138. * This function will return content of specific searchable column. It uses inherited
  139. * behaviour for all columns except for `filecontent`. In case of this column function
  140. * will return file content if file type is marked as searchable (text documents, office
  141. * documents etc).
  142. *
  143. * @param string $column_name Column name
  144. * @return string
  145. */
  146. function getSearchableColumnContent($column_name) {
  147. if ($column_name == 'filecontent') {
  148. // Unknown type or type not searchable
  149. $file_type = $this->getFileType();
  150. if (!($file_type instanceof FileType) || !$file_type->getIsSearchable()) {
  151. return null;
  152. } // if
  153. $content = $this->getFileContent();
  154. if (strlen($content) <= MAX_SEARCHABLE_FILE_SIZE) {
  155. return $content;
  156. }
  157. } else {
  158. return parent::getSearchableColumnContent($column_name);
  159. } // if
  160. } // getSearchableColumnContent
  161. /**
  162. * Create image thumbnail. This function will return true on success, false otherwise
  163. *
  164. * @param void
  165. * @return boolean
  166. */
  167. protected function createThumb() {
  168. do {
  169. $source_file = CACHE_DIR . '/' . sha1(uniqid(rand(), true));
  170. } while (is_file($source_file));
  171. if (!file_put_contents($source_file, $this->getFileContent()) || !is_readable($source_file)) {
  172. return false;
  173. } // if
  174. do {
  175. $temp_file = CACHE_DIR . '/' . sha1(uniqid(rand(), true));
  176. } while (is_file($temp_file));
  177. try {
  178. Env::useLibrary('simplegd');
  179. $image = new SimpleGdImage($source_file);
  180. $thumb = $image->scale(100, 100, SimpleGdImage::BOUNDARY_DECREASE_ONLY, false);
  181. $thumb->saveAs($temp_file, IMAGETYPE_PNG);
  182. $public_filename = PublicFiles::addFile($temp_file, 'png');
  183. if ($public_filename) {
  184. $this->setThumbFilename($public_filename);
  185. $this->save();
  186. } // if
  187. $result = true;
  188. } catch(Exception $e) {
  189. $result = false;
  190. } // try
  191. @unlink($source_file);
  192. @unlink($temp_file);
  193. return $result;
  194. } // createThumb
  195. // ---------------------------------------------------
  196. // URLs
  197. // ---------------------------------------------------
  198. /**
  199. * Return revision details URL
  200. *
  201. * @param void
  202. * @return string
  203. */
  204. function getDetailsUrl() {
  205. $file = $this->getFile();
  206. return $file instanceof ProjectFile ? $file->getDetailsUrl() . '#revision' . $this->getId() : null;
  207. } // getDetailsUrl
  208. /**
  209. * Show download URL
  210. *
  211. * @param void
  212. * @return string
  213. */
  214. function getDownloadUrl() {
  215. return get_url('files', 'download_revision', array('id' => $this->getId(), 'active_project' => $this->getProjectId()));
  216. } // getDownloadUrl
  217. /**
  218. * Return edit revision URL
  219. *
  220. * @param void
  221. * @return string
  222. */
  223. function getEditUrl() {
  224. return get_url('files', 'edit_revision', array('id' => $this->getId(), 'active_project' => $this->getProjectId()));
  225. } // getEditUrl
  226. /**
  227. * Return delete revision URL
  228. *
  229. * @param void
  230. * @return string
  231. */
  232. function getDeleteUrl() {
  233. return get_url('files', 'delete_revision', array('id' => $this->getId(), 'active_project' => $this->getProjectId()));
  234. } // getDeleteUrl
  235. /**
  236. * Return thumb URL
  237. *
  238. * @param void
  239. * @return string
  240. */
  241. function getThumbUrl() {
  242. if ($this->getThumbFilename() == '') {
  243. $this->createThumb();
  244. } // if
  245. if (trim($this->getThumbFilename())) {
  246. return PublicFiles::getFileUrl($this->getThumbFilename());
  247. } else {
  248. return '';
  249. } // if
  250. } // getThumbUrl
  251. /**
  252. * Return URL of file type icon. If we are working with image file type this function
  253. * will return thumb URL if it success in creating it
  254. *
  255. * @param void
  256. * @return string
  257. */
  258. function getTypeIconUrl() {
  259. $file_type = $this->getFileType();
  260. if ($file_type instanceof FileType) {
  261. if ($this->show_thumbnail && $file_type->getIsImage()) {
  262. $thumb_url = $this->getThumbUrl();
  263. if (trim($thumb_url)) {
  264. return $thumb_url; // we have the thumb!
  265. } // if
  266. } // if
  267. } // if
  268. $icon_file = $file_type instanceof FileType ? $file_type->getIcon() : 'unknown.png';
  269. return get_image_url("filetypes/$icon_file");
  270. } // getTypeIconUrl
  271. // ---------------------------------------------------
  272. // Permissions
  273. // ---------------------------------------------------
  274. /**
  275. * Check CAN_MANAGE_DOCUMENS permission
  276. *
  277. * @access public
  278. * @param User $user
  279. * @return boolean
  280. */
  281. function canManage(User $user) {
  282. if (!$user->isProjectUser($this->getProject())) {
  283. return false;
  284. }
  285. return $user->getProjectPermission($this->getProject(), PermissionManager::CAN_MANAGE_FILES);
  286. } // canManage
  287. /**
  288. * Empty implementation of abstract method. Message determins if user have view access
  289. *
  290. * @param void
  291. * @return boolean
  292. */
  293. function canView(User $user) {
  294. //if (!$user->isProjectUser($this->getProject())) return false;
  295. if ($this->isPrivate() && !$user->isMemberOfOwnerCompany()) {
  296. return false;
  297. }
  298. return true;
  299. } // canView
  300. /**
  301. * Returns true if user can download this file
  302. *
  303. * @param User $user
  304. * @return boolean
  305. */
  306. function canDownload(User $user) {
  307. return $this->canView($user);
  308. } // canDownload
  309. /**
  310. * Empty implementation of abstract methods. Messages determine does user have
  311. * permissions to add comment
  312. *
  313. * @param void
  314. * @return null
  315. */
  316. function canAdd(User $user, Project $project) {
  317. return $user->isAdministrator() || ProjectFile::canUpload($user, $project);
  318. } // canAdd
  319. /**
  320. * Check if specific user can edit this file
  321. *
  322. * @access public
  323. * @param User $user
  324. * @return boolean
  325. */
  326. function canEdit(User $user) {
  327. if ($user->isAdministrator()) {
  328. return true; // give access to admin
  329. }
  330. if (!$this->canManage(logged_user())) {
  331. return false; // user don't have access to this project or can't manage files
  332. }
  333. return false;
  334. } // canEdit
  335. /**
  336. * Check if specific user can delete this comment
  337. *
  338. * @access public
  339. * @param User $user
  340. * @return boolean
  341. */
  342. function canDelete(User $user) {
  343. if ($user->isAdministrator()) {
  344. return true; // give access to admin
  345. }
  346. if (!$user->isProjectUser($this->getProject())) {
  347. return false;
  348. } // if
  349. $file = $this->getFile();
  350. if (!($file instanceof ProjectFile)) {
  351. return false;
  352. } // if
  353. if ($file->countRevisions() == 1) {
  354. return false; // this is the only file revision! it can't be deleted!
  355. } // if
  356. return false;
  357. } // canDelete
  358. // ---------------------------------------------------
  359. // System
  360. // ---------------------------------------------------
  361. /**
  362. * Validate before save. This one is used to keep the data in sync. Users
  363. * can't create revisions directly...
  364. *
  365. * @param array $errors
  366. * @return null
  367. */
  368. function validate(&$errors) {
  369. if (!$this->validatePresenceOf('file_id')) {
  370. $errors[] = lang('file revision file_id required');
  371. } // if
  372. if (!$this->validatePresenceOf('repository_id')) {
  373. $errors[] = lang('file revision filename required');
  374. } // if
  375. if (!$this->validatePresenceOf('type_string')) {
  376. $errors[] = lang('file revision type_string required');
  377. } // if
  378. } // validate
  379. /**
  380. * Delete from DB and from the disk
  381. *
  382. * @param void
  383. * @return boolean
  384. */
  385. function delete() {
  386. FileRepository::deleteFile($this->getRepositoryId());
  387. $this->deleteThumb(false);
  388. return parent::delete();
  389. } // delete
  390. /**
  391. * Delete thumb
  392. *
  393. * @param boolean $save
  394. * @return boolean
  395. */
  396. function deleteThumb($save = true) {
  397. $thumb_filename = $this->getThumbFilename();
  398. if ($thumb_filename) {
  399. $this->setThumbFilename('');
  400. PublicFiles::deleteFile($this->getThumbFilename());
  401. } // if
  402. if ($save) {
  403. return $this->save();
  404. } // if
  405. return true;
  406. } // deleteThumb
  407. // ---------------------------------------------------
  408. // ApplicationDataObject implementation
  409. // ---------------------------------------------------
  410. /**
  411. * Return object name
  412. *
  413. * @access public
  414. * @param void
  415. * @return string
  416. */
  417. function getObjectName() {
  418. $file = $this->getFile();
  419. return $file instanceof ProjectFile ? $file->getObjectName() . ' revision #' . $this->getRevisionNumber() : 'Unknown file revision';
  420. } // getObjectName
  421. /**
  422. * Return object type name
  423. *
  424. * @param void
  425. * @return string
  426. */
  427. function getObjectTypeName() {
  428. return lang('file revision');
  429. } // getObjectTypeName
  430. /**
  431. * Return object URl
  432. *
  433. * @access public
  434. * @param void
  435. * @return string
  436. */
  437. function getObjectUrl() {
  438. return $this->getDetailsurl();
  439. } // getObjectUrl
  440. } // ProjectFileRevision
  441. ?>