portfolio.class.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. <?php
  2. /*
  3. * This file contains several classes related to portfolios management to avoid
  4. * having too much files under the lib/.
  5. *
  6. * Once external libraries are moved to their own directory it would be worth
  7. * moving them to their own files under a common portfolio directory.
  8. */
  9. use Model\Document;
  10. use Model\Course;
  11. /**
  12. * A portfolio is used to present content to other people. In most cases it is
  13. * an external application.
  14. *
  15. * From the application point of view it is an end point to which the user can send
  16. * content.
  17. *
  18. * Available portfolios are configured in /main/inc/config/portfolio.conf.php
  19. *
  20. * The Portfolio class serves as an entry point to other portfolio components:
  21. *
  22. * - portfolio controller
  23. * - portfolio share button
  24. * - portfolio action
  25. *
  26. * Note:
  27. *
  28. *
  29. * @license see /license.txt
  30. * @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
  31. */
  32. class Portfolio extends Portfolio\Portfolio
  33. {
  34. /**
  35. * Returns all portfolios available
  36. *
  37. * @return array
  38. */
  39. public static function all()
  40. {
  41. $conf = Chamilo::path('/main/inc/conf/portfolio.conf.php');
  42. if (!is_readable($conf)) {
  43. return array();
  44. }
  45. include $conf;
  46. return isset($portfolios) ? $portfolios : array();
  47. }
  48. /**
  49. * Returns a portfolio from its name.
  50. *
  51. * @param string $name
  52. * @return Portfolio\Portfolio
  53. */
  54. public static function get($name)
  55. {
  56. $items = self::all();
  57. foreach ($items as $item) {
  58. if ($item->get_name() == $name) {
  59. return $item;
  60. }
  61. }
  62. return Portfolio\Portfolio::none();
  63. }
  64. /**
  65. * True if portfolios are enabled. False otherwise.
  66. *
  67. * @return boolean
  68. */
  69. public static function is_enabled()
  70. {
  71. if (api_is_anonymous()) {
  72. return false;
  73. }
  74. $user_id = api_get_user_id();
  75. if (empty($user_id)) {
  76. return false;
  77. }
  78. $portfolios = self::all();
  79. if (count($portfolios) == 0) {
  80. return false;
  81. }
  82. return true;
  83. }
  84. /**
  85. * The controller for portfolio.
  86. *
  87. * @return \PortfolioController
  88. */
  89. public static function controller()
  90. {
  91. return PortfolioController::instance();
  92. }
  93. /**
  94. * Returns a share component/button.
  95. *
  96. * @param string $tool
  97. * @param int $id
  98. * @param array $attributes
  99. * @return \PortfolioShare
  100. */
  101. public static function share($tool, $id, $attributes = array())
  102. {
  103. return PortfolioShare::factory($tool, $id, $attributes);
  104. }
  105. /**
  106. * Returns the list of actions.
  107. *
  108. * @return array
  109. */
  110. public static function actions()
  111. {
  112. return PortfolioController::actions();
  113. }
  114. /**
  115. * Returns a temporary url to download files and/or folders.
  116. *
  117. * @param string|array $ids
  118. * @return string
  119. */
  120. public static function download_url($ids, $tool)
  121. {
  122. $ids = is_array($ids) ? implode(',', $ids) : $ids;
  123. $params = Uri::course_params();
  124. $params['id'] = $ids;
  125. $params[KeyAuth::PARAM_ACCESS_TOKEN] = KeyAuth::create_temp_token();
  126. $result = Uri::url("/main/$tool/file.php", $params, false);
  127. return $result;
  128. }
  129. }
  130. /**
  131. * The portfolio controller. Responsible to dispatch/process portfolio actions.
  132. *
  133. * Usage:
  134. *
  135. * if(Porfolio::contoller()->accept()){
  136. * Portfolio::controller()->run();
  137. * }
  138. *
  139. *
  140. */
  141. class PortfolioController
  142. {
  143. const PARAM_ACTION = 'action';
  144. const PARAM_ID = 'id';
  145. const PARAM_TOOL = 'tool';
  146. const PARAM_PORTFOLIO = 'portfolio';
  147. const PARAM_CONTROLLER = 'controller';
  148. const PARAM_SECURITY_TOKEN = 'sec_token';
  149. const ACTION_SHARE = 'share';
  150. const NAME = 'portfolio';
  151. /**
  152. *
  153. * @return \PortfolioController
  154. */
  155. static function instance()
  156. {
  157. static $result = null;
  158. if (empty($result)) {
  159. $result = new self();
  160. }
  161. return $result;
  162. }
  163. protected $message = '';
  164. protected function __construct()
  165. {
  166. }
  167. public static function portfolios()
  168. {
  169. return Portfolio::all();
  170. }
  171. /**
  172. * List of actions for the SortableTable.
  173. *
  174. * @return array
  175. */
  176. public static function actions()
  177. {
  178. static $result = null;
  179. if (!is_null($result)) {
  180. return $result;
  181. }
  182. $items = self::portfolios();
  183. if (empty($items)) {
  184. $result = array();
  185. return $result;
  186. }
  187. $result = array();
  188. foreach ($items as $item) {
  189. $action = PortfolioBulkAction::create($item);
  190. $result[] = $action;
  191. }
  192. return $result;
  193. }
  194. /**
  195. * Returns true if the controller accept to process the current request.
  196. * Returns false otherwise.
  197. *
  198. * @return boolean
  199. */
  200. function accept()
  201. {
  202. if (!Portfolio::is_enabled()) {
  203. return false;
  204. }
  205. $actions = self::actions();
  206. foreach ($actions as $action) {
  207. if ($action->accept()) {
  208. return true;
  209. }
  210. }
  211. if ($this->get_controller() != self::NAME) {
  212. return false;
  213. }
  214. if (!Security::check_token('get')) {
  215. return false;
  216. }
  217. $id = $this->get_id();
  218. if (empty($id)) {
  219. return false;
  220. }
  221. return $this->get_action() == self::ACTION_SHARE;
  222. }
  223. /**
  224. * Returns the value of the current controller request parameters. That is
  225. * the name of the controller which shall handle the current request.
  226. *
  227. * @return string
  228. */
  229. function get_controller()
  230. {
  231. return Request::get(self::PARAM_CONTROLLER);
  232. }
  233. /**
  234. * Returns the value of the action parameter. That is which action shall be
  235. * performed. That is share to send an object to a portfolio.
  236. *
  237. * @return string
  238. */
  239. function get_action()
  240. {
  241. $result = Request::get(self::PARAM_ACTION);
  242. return ($result == self::ACTION_SHARE) ? self::ACTION_SHARE : '';
  243. }
  244. /**
  245. * Returns the value of the id parameter: id of object to send.
  246. *
  247. * @return int
  248. */
  249. function get_id()
  250. {
  251. return (int) Request::get(self::PARAM_ID);
  252. }
  253. /**
  254. * The course code (id) to which the object belongs.
  255. *
  256. * @return string
  257. */
  258. function course_code()
  259. {
  260. return Chamilo::session()->course()->code();
  261. }
  262. /**
  263. * The name of the porfolio where to send.
  264. *
  265. * @return type
  266. */
  267. function get_portfolio()
  268. {
  269. return Request::get(self::PARAM_PORTFOLIO);
  270. }
  271. /**
  272. * Name of the tool: document, work, etc. Defaults to current_course_tool.
  273. *
  274. * @global string $current_course_tool
  275. * @return string
  276. */
  277. function get_tool()
  278. {
  279. global $current_course_tool;
  280. return Request::get(self::PARAM_TOOL, $current_course_tool);
  281. }
  282. /**
  283. * Returns the end user message after running the controller..
  284. * @return string
  285. */
  286. function message()
  287. {
  288. return $this->message;
  289. }
  290. /**
  291. * Execute the controller action as required. If a registered action accept
  292. * the current request the controller calls it.
  293. *
  294. * If not action is accept the current request and current action is "share"
  295. * the controller execute the "send to portfolio" action
  296. *
  297. * @return PortfolioController
  298. */
  299. function run()
  300. {
  301. if (!$this->accept()) {
  302. return $this;
  303. }
  304. $actions = self::actions();
  305. foreach ($actions as $action) {
  306. if ($action->accept()) {
  307. return $action->run();
  308. }
  309. }
  310. $action = $this->get_action();
  311. if ($action == self::ACTION_SHARE) {
  312. $user = new \Portfolio\User();
  313. $user->email = Chamilo::user()->email();
  314. $tool = $this->get_tool();
  315. $id = $this->get_id();
  316. $url = Portfolio::download_url($id, $tool);
  317. $artefact = new Portfolio\Artefact($url);
  318. $name = $this->get_portfolio();
  319. $result = Portfolio::get($name)->send($user, $artefact);
  320. if ($result) {
  321. $this->message = Display::return_message(get_lang('SentSuccessfully'), 'normal');
  322. } else {
  323. $this->message = Display::return_message(get_lang('SentFailed'), 'error');
  324. }
  325. return $this;
  326. } else {
  327. $this->message = '';
  328. }
  329. return $this;
  330. }
  331. }
  332. /**
  333. * This component is used to display a "send to portfolio" button for a specific
  334. * object.
  335. *
  336. * Note that the component implement the __toString() magic method and can be
  337. * therefore used in situation where a string is expected: for ex echo $button.
  338. *
  339. * Usage
  340. *
  341. * $button = Portfolio::share(...);
  342. * echo $button;
  343. *
  344. */
  345. class PortfolioShare
  346. {
  347. /**
  348. * Create a "send to portfolio" button
  349. *
  350. * @param string $tool The name of the tool: document, work.
  351. * @param int $c_id The id of the course
  352. * @param int $id The id of the object
  353. * @param array $attributes Html attributes
  354. * @return \PortfolioShare
  355. */
  356. static function factory($tool, $id, $attributes = array())
  357. {
  358. $result = new self($tool, $id, $attributes);
  359. return $result;
  360. }
  361. /**
  362. * Returns the current secuirty token. Used to avoid see surfing attacks.
  363. *
  364. * @return type
  365. */
  366. static function security_token()
  367. {
  368. static $result = null;
  369. if (empty($result)) {
  370. $result = Security::get_token();
  371. }
  372. return $result;
  373. }
  374. protected $id = 0;
  375. protected $attributes = array();
  376. protected $tool = '';
  377. function __construct($tool, $id, $attributes = array())
  378. {
  379. $this->tool = $tool;
  380. $this->id = (int) $id;
  381. $this->attributes = $attributes;
  382. }
  383. /**
  384. * Object id to send
  385. * @return int
  386. */
  387. function get_id()
  388. {
  389. return $this->id;
  390. }
  391. /**
  392. * Object id to send
  393. * @return int
  394. */
  395. function get_c_id()
  396. {
  397. return $this->c_id;
  398. }
  399. /**
  400. * Html attributes.
  401. *
  402. * @return array
  403. */
  404. function get_attributes()
  405. {
  406. return $this->attributes;
  407. }
  408. /**
  409. * Name of the tool. I.e. the type of the id parameter. Can be document, work.
  410. *
  411. * @return string
  412. */
  413. function get_tool()
  414. {
  415. return $this->tool;
  416. }
  417. /**
  418. * Display the component.
  419. *
  420. * @return string
  421. */
  422. function display()
  423. {
  424. if (!Portfolio::is_enabled()) {
  425. return '';
  426. }
  427. $id = $this->id;
  428. $tool = $this->tool;
  429. $attributes = $this->attributes;
  430. $attributes['z-index'] = 100000;
  431. $s = ' ';
  432. foreach ($attributes as $key => $value) {
  433. $s .= $key . '="' . $value . '" ';
  434. }
  435. $result = array();
  436. $result[] = '<span ' . $s . ' >';
  437. $result[] = '<span class="dropdown" >';
  438. $result[] = '<a href="#" data-toggle="dropdown" class="dropdown-toggle">';
  439. $result[] = Display::return_icon('document_send.png', get_lang('Send'), array(), ICON_SIZE_SMALL) . '<b class="caret"></b>';
  440. $result[] = '</a>';
  441. $result[] = '<ul class="dropdown-menu">';
  442. $portfolios = Portfolio::all();
  443. foreach ($portfolios as $portfolio) {
  444. $parameters = Uri::course_params();
  445. $parameters[PortfolioController::PARAM_ACTION] = PortfolioController::ACTION_SHARE;
  446. $parameters[PortfolioController::PARAM_CONTROLLER] = PortfolioController::NAME;
  447. $parameters[PortfolioController::PARAM_PORTFOLIO] = $portfolio->get_name();
  448. $parameters[PortfolioController::PARAM_SECURITY_TOKEN] = self::security_token();
  449. $parameters[PortfolioController::PARAM_TOOL] = $this->get_tool();
  450. $parameters[PortfolioController::PARAM_ID] = $id;
  451. $parameters[PortfolioController::PARAM_TOOL] = $tool;
  452. $url = Chamilo::url('/main/portfolio/share.php', $parameters);
  453. $result[] = '<li>';
  454. $result[] = '<a href="' . $url . '">' . $portfolio->get_title() . '</a>';
  455. $result[] = '</li>';
  456. }
  457. $result[] = '</ul>';
  458. $result[] = '</span>';
  459. $result[] = '</span>';
  460. return implode("\n", $result);
  461. }
  462. function __toString()
  463. {
  464. return $this->display();
  465. }
  466. }
  467. /**
  468. * A "send to this portfolio" action. Actions are used by the SortableTable to
  469. * perform actions on a set of objects. An action is composed of
  470. *
  471. * - a name
  472. * - a title (displayed to the user)
  473. * - code to execute
  474. *
  475. * Usage:
  476. *
  477. * $form_actions = array();
  478. * $form_action['...'] = get_lang('...');
  479. * $portfolio_actions = Portfolio::actions();
  480. * foreach($portfolio_actions as $action){
  481. * $form_action[$action->get_name()] = $action->get_title();
  482. * }
  483. * $table->set_form_actions($form_action, 'path');
  484. *
  485. * @see SortableTable
  486. */
  487. class PortfolioBulkAction
  488. {
  489. /**
  490. *
  491. * @param \Portfolio\Portfolio $portfolio
  492. * @return PortfolioBulkAction
  493. */
  494. public static function create($portfolio)
  495. {
  496. return new self($portfolio);
  497. }
  498. protected $name = '';
  499. protected $title = '';
  500. protected $portfolio = null;
  501. /**
  502. *
  503. * @param \Portfolio\Portfolio $portfolio
  504. */
  505. public function __construct($portfolio)
  506. {
  507. $this->name = md5(__CLASS__) . '_' . $portfolio->get_name();
  508. $this->title = $portfolio->get_title() ? $portfolio->get_title() : get_lang('SendTo') . ' ' . $portfolio->get_name();
  509. $this->portfolio = $portfolio;
  510. }
  511. public function get_name()
  512. {
  513. return $this->name;
  514. }
  515. public function get_title()
  516. {
  517. return $this->title;
  518. }
  519. /**
  520. *
  521. * @return \Portfolio\Portfolio
  522. */
  523. public function get_portfolio()
  524. {
  525. return $this->portfolio;
  526. }
  527. public function accept()
  528. {
  529. $name = $this->get_name();
  530. $action = Request::get(PortfolioController::PARAM_ACTION);
  531. if ($name != $action) {
  532. return false;
  533. }
  534. $pathes = Request::get('path');
  535. if (empty($pathes)) {
  536. return false;
  537. }
  538. $course = Course::current();
  539. if (empty($course)) {
  540. return false;
  541. }
  542. return true;
  543. }
  544. public function run()
  545. {
  546. if (!$this->accept()) {
  547. return false;
  548. }
  549. $course = Course::current();
  550. $pathes = Request::get('path');
  551. $pathes = is_array($pathes) ? $pathes : array($pathes);
  552. $ids = array();
  553. foreach ($pathes as $path) {
  554. $doc = Document::get_by_path($course, $path);
  555. if ($doc) {
  556. $ids[] = $doc->get_id();
  557. }
  558. }
  559. if (empty($ids)) {
  560. return false;
  561. }
  562. $user = new \Portfolio\User();
  563. $user->email = Chamilo::user()->email();
  564. $artefact = new Portfolio\Artefact();
  565. $artefact->url = Portfolio::download_url($ids);
  566. $portfolio = $this->get_portfolio();
  567. $result = $portfolio->send($user, $artefact);
  568. return $result;
  569. }
  570. }