| 1 | <?php |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | /********************************************************************\ |
|---|
| 5 | * This program is free software; you can redistribute it and/or * |
|---|
| 6 | * modify it under the terms of the GNU General Public License as * |
|---|
| 7 | * published by the Free Software Foundation; either version 2 of * |
|---|
| 8 | * the License, or (at your option) any later version. * |
|---|
| 9 | * * |
|---|
| 10 | * This program is distributed in the hope that it will be useful, * |
|---|
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
|---|
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
|---|
| 13 | * GNU General Public License for more details. * |
|---|
| 14 | * * |
|---|
| 15 | * You should have received a copy of the GNU General Public License* |
|---|
| 16 | * along with this program; if not, contact: * |
|---|
| 17 | * * |
|---|
| 18 | * Free Software Foundation Voice: +1-617-542-5942 * |
|---|
| 19 | * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 * |
|---|
| 20 | * Boston, MA 02111-1307, USA gnu@gnu.org * |
|---|
| 21 | * * |
|---|
| 22 | \********************************************************************/ |
|---|
| 23 | /**@file Content.php |
|---|
| 24 | * @author Copyright (C) 2005 Benoit Grégoire <bock@step.polymtl.ca>, |
|---|
| 25 | * Technologies Coeus inc. |
|---|
| 26 | */ |
|---|
| 27 | require_once BASEPATH.'include/common.php'; |
|---|
| 28 | require_once BASEPATH.'classes/FormSelectGenerator.php'; |
|---|
| 29 | require_once BASEPATH.'classes/GenericObject.php'; |
|---|
| 30 | |
|---|
| 31 | /** Any type of content */ |
|---|
| 32 | class Content implements GenericObject |
|---|
| 33 | { |
|---|
| 34 | protected $id; |
|---|
| 35 | protected $content_row; |
|---|
| 36 | private $content_type; |
|---|
| 37 | private $is_trivial_content; |
|---|
| 38 | private $is_logging_enabled; |
|---|
| 39 | |
|---|
| 40 | /** Create a new Content object in the database |
|---|
| 41 | * @param $content_type Optionnal, the content type to be given to the new object |
|---|
| 42 | * @param $id Optionnal, the id to be given to the new Content. If null, a new id will be assigned |
|---|
| 43 | * @return the newly created Content object, or null if there was an error (an exception is also trown |
|---|
| 44 | */ |
|---|
| 45 | static function createNewObject($content_type = 'Content', $id = null) |
|---|
| 46 | { |
|---|
| 47 | global $db; |
|---|
| 48 | if (empty ($id)) |
|---|
| 49 | { |
|---|
| 50 | $content_id = get_guid(); |
|---|
| 51 | } |
|---|
| 52 | else |
|---|
| 53 | { |
|---|
| 54 | $content_id = $db->EscapeString($id); |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | if (empty ($content_type)) |
|---|
| 58 | { |
|---|
| 59 | throw new Exception(_('Content type is optionnal, but cannot be empty!')); |
|---|
| 60 | } |
|---|
| 61 | else |
|---|
| 62 | { |
|---|
| 63 | $content_type = $db->EscapeString($content_type); |
|---|
| 64 | } |
|---|
| 65 | $sql = "INSERT INTO content (content_id, content_type) VALUES ('$content_id', '$content_type')"; |
|---|
| 66 | |
|---|
| 67 | if (!$db->ExecSqlUpdate($sql, false)) |
|---|
| 68 | { |
|---|
| 69 | throw new Exception(_('Unable to insert new content into database!')); |
|---|
| 70 | } |
|---|
| 71 | |
|---|
| 72 | $object = self :: getObject($content_id); |
|---|
| 73 | /* At least add the current user as the default owner */ |
|---|
| 74 | $object->AddOwner(User :: getCurrentUser()); |
|---|
| 75 | /* By default, make it persistent */ |
|---|
| 76 | $object->setIsPersistent(true); |
|---|
| 77 | |
|---|
| 78 | return $object; |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | /** Get an interface to create a new object. |
|---|
| 82 | * @return html markup |
|---|
| 83 | */ |
|---|
| 84 | public static function getCreateNewObjectUI() |
|---|
| 85 | { |
|---|
| 86 | $html = ''; |
|---|
| 87 | $i = 0; |
|---|
| 88 | $tab = array (); |
|---|
| 89 | foreach (self :: getAvailableContentTypes() as $classname) |
|---|
| 90 | { |
|---|
| 91 | $tab[$i][0] = $classname; |
|---|
| 92 | $tab[$i][1] = $classname; |
|---|
| 93 | $i ++; |
|---|
| 94 | } |
|---|
| 95 | $name = "new_content_content_type"; |
|---|
| 96 | $default = 'TrivialLangstring'; |
|---|
| 97 | if (empty ($tab)) |
|---|
| 98 | $html .= _("It appears that you have not installed any Content plugin !"); |
|---|
| 99 | else |
|---|
| 100 | { |
|---|
| 101 | $html .= _("You must select a content type: "); |
|---|
| 102 | $html .= FormSelectGenerator :: generateFromArray($tab, $default, $name, "Content", false); |
|---|
| 103 | } |
|---|
| 104 | return $html; |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | /** Process the new object interface. |
|---|
| 108 | * Will return the new object if the user has the credentials |
|---|
| 109 | * necessary (Else an exception is thrown) and and the form was fully |
|---|
| 110 | * filled (Else the object returns null). |
|---|
| 111 | * @return the node object or null if no new node was created. |
|---|
| 112 | */ |
|---|
| 113 | static function processCreateNewObjectUI() |
|---|
| 114 | { |
|---|
| 115 | $retval = null; |
|---|
| 116 | $name = "new_content_content_type"; |
|---|
| 117 | $content_type = FormSelectGenerator :: getResult($name, "Content"); |
|---|
| 118 | if ($content_type) |
|---|
| 119 | { |
|---|
| 120 | $retval = self :: createNewObject($content_type); |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | return $retval; |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | /** Get the Content object, specific to it's content type |
|---|
| 127 | * @param $content_id The content id |
|---|
| 128 | * @return the Content object, or null if there was an error (an exception is also thrown) |
|---|
| 129 | */ |
|---|
| 130 | static function getObject($content_id) |
|---|
| 131 | { |
|---|
| 132 | global $db; |
|---|
| 133 | $content_id = $db->EscapeString($content_id); |
|---|
| 134 | $sql = "SELECT content_type FROM content WHERE content_id='$content_id'"; |
|---|
| 135 | $db->ExecSqlUniqueRes($sql, $row, false); |
|---|
| 136 | if ($row == null) |
|---|
| 137 | { |
|---|
| 138 | throw new Exception(_("The content with the following id could not be found in the database: ").$content_id); |
|---|
| 139 | } |
|---|
| 140 | $content_type = $row['content_type']; |
|---|
| 141 | $object = new $content_type ($content_id); |
|---|
| 142 | return $object; |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | /** Get the list of available content type on the system |
|---|
| 146 | * @return an array of class names */ |
|---|
| 147 | public static function getAvailableContentTypes() |
|---|
| 148 | { |
|---|
| 149 | $dir = BASEPATH.'classes/Content'; |
|---|
| 150 | if ($dir_handle = @opendir($dir)) |
|---|
| 151 | { |
|---|
| 152 | $content_types = array(); |
|---|
| 153 | |
|---|
| 154 | /* This is the correct way to loop over the directory. */ |
|---|
| 155 | while (false !== ($sub_dir = readdir($dir_handle))) |
|---|
| 156 | { |
|---|
| 157 | // Loop through sub-directories of Content |
|---|
| 158 | if ($sub_dir != '.' && $sub_dir != '..' && is_dir("{$dir}/{$sub_dir}")) |
|---|
| 159 | { |
|---|
| 160 | // Only add directories containing corresponding initial Content class |
|---|
| 161 | if(is_file("{$dir}/{$sub_dir}/{$sub_dir}.php")) |
|---|
| 162 | $content_types[] = $sub_dir; |
|---|
| 163 | } |
|---|
| 164 | } |
|---|
| 165 | closedir($dir_handle); |
|---|
| 166 | } |
|---|
| 167 | else |
|---|
| 168 | { |
|---|
| 169 | throw new Exception(_('Unable to open directory ').$dir); |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | // Cleanup PHP file extensions and sort the result array |
|---|
| 173 | $content_types = str_ireplace('.php', '', $content_types); |
|---|
| 174 | sort($content_types); |
|---|
| 175 | |
|---|
| 176 | return $content_types; |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | /** |
|---|
| 180 | * Get all content, can be restricted to a given content type |
|---|
| 181 | */ |
|---|
| 182 | public static function getAllContent($content_type = "") |
|---|
| 183 | { |
|---|
| 184 | global $db; |
|---|
| 185 | $where_clause = ""; |
|---|
| 186 | if (!empty ($content_type)) |
|---|
| 187 | { |
|---|
| 188 | $content_type = $db->EscapeString($content_type); |
|---|
| 189 | $where_clause = "WHERE content_type = '$content_type'"; |
|---|
| 190 | } |
|---|
| 191 | $db->ExecSql("SELECT content_id FROM content $where_clause", $rows, false); |
|---|
| 192 | $objects = array (); |
|---|
| 193 | if ($rows) |
|---|
| 194 | foreach ($rows as $row) |
|---|
| 195 | $objects[] = self :: getObject($row['content_id']); |
|---|
| 196 | return $objects; |
|---|
| 197 | } |
|---|
| 198 | |
|---|
| 199 | /** Get a flexible interface to generate new content objects |
|---|
| 200 | * @param $user_prefix A identifier provided by the programmer to recognise it's generated html form |
|---|
| 201 | * @param $content_type If set, the created content will be of this type, otherwise, the user will have to chose |
|---|
| 202 | * @return html markup |
|---|
| 203 | */ |
|---|
| 204 | static function getNewContentUI($user_prefix, $content_type = null) |
|---|
| 205 | { |
|---|
| 206 | global $db; |
|---|
| 207 | $html = ''; |
|---|
| 208 | $available_content_types = self :: getAvailableContentTypes(); |
|---|
| 209 | |
|---|
| 210 | $name = "get_new_content_{$user_prefix}_content_type"; |
|---|
| 211 | if (empty ($content_type)) |
|---|
| 212 | { |
|---|
| 213 | $html .= _("Content type: "); |
|---|
| 214 | $i = 0; |
|---|
| 215 | foreach ($available_content_types as $classname) |
|---|
| 216 | { |
|---|
| 217 | $tab[$i][0] = $classname; |
|---|
| 218 | $tab[$i][1] = $classname; |
|---|
| 219 | $i ++; |
|---|
| 220 | } |
|---|
| 221 | $html .= FormSelectGenerator :: generateFromArray($tab, 'TrivialLangstring', $name, null, false); |
|---|
| 222 | } |
|---|
| 223 | else |
|---|
| 224 | { |
|---|
| 225 | if (false === array_search($content_type, $available_content_types, true)) |
|---|
| 226 | { |
|---|
| 227 | throw new Exception(_("The following content type isn't valid: ").$content_type); |
|---|
| 228 | } |
|---|
| 229 | $html .= "<input type='hidden' name='$name' value='$content_type'>"; |
|---|
| 230 | } |
|---|
| 231 | $name = "get_new_content_{$user_prefix}_add"; |
|---|
| 232 | |
|---|
| 233 | if ($content_type) |
|---|
| 234 | { |
|---|
| 235 | $value = _("Add a")." $content_type"; |
|---|
| 236 | } |
|---|
| 237 | else |
|---|
| 238 | { |
|---|
| 239 | $value = _("Add"); |
|---|
| 240 | } |
|---|
| 241 | $html .= "<input type='submit' name='$name' value='$value'>"; |
|---|
| 242 | return $html; |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | /** Get the created Content object, IF one was created |
|---|
| 246 | * OR Get existing content ( depending on what the user clicked ) |
|---|
| 247 | * @param $user_prefix A identifier provided by the programmer to recognise it's generated form |
|---|
| 248 | * @param $associate_existing_content boolean if true allows to get existing |
|---|
| 249 | * object |
|---|
| 250 | * @return the Content object, or null if the user didn't greate one |
|---|
| 251 | */ |
|---|
| 252 | static function processNewContentUI($user_prefix, $associate_existing_content = false) |
|---|
| 253 | { |
|---|
| 254 | $object = null; |
|---|
| 255 | if ($associate_existing_content == true) |
|---|
| 256 | $name = "{$user_prefix}_add"; |
|---|
| 257 | else |
|---|
| 258 | $name = "get_new_content_{$user_prefix}_add"; |
|---|
| 259 | if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) |
|---|
| 260 | { |
|---|
| 261 | if ($associate_existing_content == true) |
|---|
| 262 | $name = "{$user_prefix}"; |
|---|
| 263 | else |
|---|
| 264 | $name = "get_new_content_{$user_prefix}_content_type"; |
|---|
| 265 | |
|---|
| 266 | // The result can be either a Content type or a Content ID depending on the form ( associate_existing_content or NOT ) |
|---|
| 267 | $content_ui_result = FormSelectGenerator :: getResult($name, null); |
|---|
| 268 | if ($associate_existing_content == true) |
|---|
| 269 | $object = self :: getObject($content_ui_result); |
|---|
| 270 | else |
|---|
| 271 | $object = self :: createNewObject($content_ui_result); |
|---|
| 272 | } |
|---|
| 273 | return $object; |
|---|
| 274 | } |
|---|
| 275 | |
|---|
| 276 | /** Get a flexible interface to manage content linked to a node, a network or anything else |
|---|
| 277 | * @param $user_prefix A identifier provided by the programmer to recognise it's generated html form |
|---|
| 278 | * @param $content_type If set, the created content will be of this type, otherwise, the user will have to chose |
|---|
| 279 | * @return html markup |
|---|
| 280 | */ |
|---|
| 281 | static function getLinkedContentUI($user_prefix, $link_table, $link_table_obj_key_col, $link_table_obj_key, $display_location) |
|---|
| 282 | { |
|---|
| 283 | global $db; |
|---|
| 284 | $html = ''; |
|---|
| 285 | $link_table = $db->EscapeString($link_table); |
|---|
| 286 | $link_table_obj_key_col = $db->EscapeString($link_table_obj_key_col); |
|---|
| 287 | $link_table_obj_key = $db->EscapeString($link_table_obj_key); |
|---|
| 288 | $display_location = $db->EscapeString($display_location); |
|---|
| 289 | $name = "{$user_prefix}_display_location"; |
|---|
| 290 | |
|---|
| 291 | $html .= "<input type='hidden' name='{$name}' value='{$display_location}'>\n"; |
|---|
| 292 | $current_content_sql = "SELECT * FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key' AND display_location='$display_location' ORDER BY subscribe_timestamp DESC"; |
|---|
| 293 | $rows = null; |
|---|
| 294 | $db->ExecSql($current_content_sql, $rows, false); |
|---|
| 295 | $html .= "<ul class='admin_section_list'>\n"; |
|---|
| 296 | if ($rows) |
|---|
| 297 | foreach ($rows as $row) |
|---|
| 298 | { |
|---|
| 299 | $content = Content :: getObject($row['content_id']); |
|---|
| 300 | $html .= "<li class='admin_section_list_item'>\n"; |
|---|
| 301 | $html .= "<div class='admin_section_data'>\n"; |
|---|
| 302 | $html .= $content->getListUI(); |
|---|
| 303 | $html .= "</div>\n"; |
|---|
| 304 | $html .= "<div class='admin_section_tools'>\n"; |
|---|
| 305 | $name = "{$user_prefix}_".$content->GetId()."_edit"; |
|---|
| 306 | $html .= "<input type='button' name='$name' value='"._("Edit")."' onClick='window.location.href = \"".GENERIC_OBJECT_ADMIN_ABS_HREF."?object_class=Content&action=edit&object_id=".$content->GetId()."\";'>\n"; |
|---|
| 307 | $name = "{$user_prefix}_".$content->GetId()."_erase"; |
|---|
| 308 | $html .= "<input type='submit' name='$name' value='"._("Remove")."'>"; |
|---|
| 309 | $html .= "</div>\n"; |
|---|
| 310 | $html .= "</li>\n"; |
|---|
| 311 | } |
|---|
| 312 | $html .= "<li class='admin_section_list_item'>\n"; |
|---|
| 313 | $name = "{$user_prefix}_new_existing"; |
|---|
| 314 | $html .= Content :: getSelectContentUI($name, "AND content_id NOT IN (SELECT content_id FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key')"); |
|---|
| 315 | $name = "{$user_prefix}_new_display_location"; |
|---|
| 316 | |
|---|
| 317 | $html .= "<input type='hidden' name='{$name}' value='{$display_location}'>\n"; |
|---|
| 318 | $name = "{$user_prefix}_new_existing_submit"; |
|---|
| 319 | $html .= "<input type='submit' name='$name' value='"._("Add")."'>"; |
|---|
| 320 | $html .= "</li>\n"; |
|---|
| 321 | $html .= "<li class='admin_section_list_item'>\n"; |
|---|
| 322 | $html .= "Add new content: "; |
|---|
| 323 | $name = "{$user_prefix}_new"; |
|---|
| 324 | $html .= self :: getNewContentUI($name, $content_type = null); |
|---|
| 325 | $html .= "</li>\n"; |
|---|
| 326 | $html .= "</ul>\n"; |
|---|
| 327 | |
|---|
| 328 | return $html; |
|---|
| 329 | } |
|---|
| 330 | |
|---|
| 331 | /** Get the created Content object, IF one was created |
|---|
| 332 | * OR Get existing content ( depending on what the user clicked ) |
|---|
| 333 | * @param $user_prefix A identifier provided by the programmer to recognise it's generated form |
|---|
| 334 | * @param $associate_existing_content boolean if true allows to get existing |
|---|
| 335 | * object |
|---|
| 336 | * @return the Content object, or null if the user didn't greate one |
|---|
| 337 | */ |
|---|
| 338 | static function processLinkedContentUI($user_prefix, $link_table, $link_table_obj_key_col, $link_table_obj_key) |
|---|
| 339 | { |
|---|
| 340 | |
|---|
| 341 | global $db; |
|---|
| 342 | $link_table = $db->EscapeString($link_table); |
|---|
| 343 | $link_table_obj_key_col = $db->EscapeString($link_table_obj_key_col); |
|---|
| 344 | $link_table_obj_key = $db->EscapeString($link_table_obj_key); |
|---|
| 345 | $name = "{$user_prefix}_display_location"; |
|---|
| 346 | $display_location = $db->EscapeString($_REQUEST[$name]); |
|---|
| 347 | $name = "{$user_prefix}_new_display_location"; |
|---|
| 348 | $display_location_new = $db->EscapeString($_REQUEST[$name]); |
|---|
| 349 | $current_content_sql = "SELECT * FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key' AND display_location='$display_location' ORDER BY subscribe_timestamp DESC"; |
|---|
| 350 | $rows = null; |
|---|
| 351 | $db->ExecSql($current_content_sql, $rows, false); |
|---|
| 352 | if ($rows) |
|---|
| 353 | foreach ($rows as $row) |
|---|
| 354 | { |
|---|
| 355 | $content = Content :: getObject($row['content_id']); |
|---|
| 356 | $content_id = $db->EscapeString($content->getId()); |
|---|
| 357 | $name = "{$user_prefix}_".$content->GetId()."_erase"; |
|---|
| 358 | if (!empty ($_REQUEST[$name])) |
|---|
| 359 | { |
|---|
| 360 | $sql = "DELETE FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key' AND content_id = '$content_id'"; |
|---|
| 361 | $db->ExecSqlUpdate($sql, $rows, false); |
|---|
| 362 | } |
|---|
| 363 | } |
|---|
| 364 | |
|---|
| 365 | $name = "{$user_prefix}_new_existing_submit"; |
|---|
| 366 | if (!empty ($_REQUEST[$name])) |
|---|
| 367 | { |
|---|
| 368 | $name = "{$user_prefix}_new_existing"; |
|---|
| 369 | $content = Content :: processSelectContentUI($name); |
|---|
| 370 | if ($content) |
|---|
| 371 | { |
|---|
| 372 | $content_id = $db->EscapeString($content->getId()); |
|---|
| 373 | $sql = "INSERT INTO $link_table (content_id, $link_table_obj_key_col, display_location) VALUES ('$content_id', '$link_table_obj_key', '$display_location_new');\n"; |
|---|
| 374 | $db->ExecSqlUpdate($sql, $rows, false); |
|---|
| 375 | } |
|---|
| 376 | } |
|---|
| 377 | $name = "{$user_prefix}_new"; |
|---|
| 378 | $content = self :: processNewContentUI($name); |
|---|
| 379 | if ($content) |
|---|
| 380 | { |
|---|
| 381 | $content_id = $db->EscapeString($content->getId()); |
|---|
| 382 | $sql = "INSERT INTO $link_table (content_id, $link_table_obj_key_col, display_location) VALUES ('$content_id', '$link_table_obj_key', '$display_location_new');\n"; |
|---|
| 383 | $db->ExecSqlUpdate($sql, $rows, false); |
|---|
| 384 | } |
|---|
| 385 | |
|---|
| 386 | } |
|---|
| 387 | |
|---|
| 388 | /** Get an interface to pick content from all persistent content. |
|---|
| 389 | * @param $user_prefix A identifier provided by the programmer to recognise it's generated html form |
|---|
| 390 | @param $sql_additional_where Addidional where conditions to restrict the candidate objects |
|---|
| 391 | * @return html markup |
|---|
| 392 | */ |
|---|
| 393 | public static function getSelectContentUI($user_prefix, $sql_additional_where = null) |
|---|
| 394 | { |
|---|
| 395 | $html = ''; |
|---|
| 396 | $name = "{$user_prefix}"; |
|---|
| 397 | $html .= _("Select existing Content : ")."\n"; |
|---|
| 398 | global $db; |
|---|
| 399 | $retval = array (); |
|---|
| 400 | $sql = "SELECT * FROM content WHERE is_persistent=TRUE $sql_additional_where ORDER BY creation_timestamp"; |
|---|
| 401 | $db->ExecSql($sql, $content_rows, false); |
|---|
| 402 | if ($content_rows != null) |
|---|
| 403 | { |
|---|
| 404 | $i = 0; |
|---|
| 405 | foreach ($content_rows as $content_row) |
|---|
| 406 | { |
|---|
| 407 | $content = Content :: getObject($content_row['content_id']); |
|---|
| 408 | $tab[$i][0] = $content->getId(); |
|---|
| 409 | $tab[$i][1] = $content->__toString()." (".get_class($content).")"; |
|---|
| 410 | $i ++; |
|---|
| 411 | } |
|---|
| 412 | $html .= FormSelectGenerator :: generateFromArray($tab, null, $name, null, false); |
|---|
| 413 | |
|---|
| 414 | } |
|---|
| 415 | else |
|---|
| 416 | { |
|---|
| 417 | $html .= "<div class='warningmsg'>"._("Sorry, no content available in the database")."</div>\n"; |
|---|
| 418 | } |
|---|
| 419 | return $html; |
|---|
| 420 | } |
|---|
| 421 | |
|---|
| 422 | /** Get the selected Content object. |
|---|
| 423 | * @param $user_prefix A identifier provided by the programmer to recognise it's generated form |
|---|
| 424 | * @return the Content object |
|---|
| 425 | */ |
|---|
| 426 | static function processSelectContentUI($user_prefix) |
|---|
| 427 | { |
|---|
| 428 | $name = "{$user_prefix}"; |
|---|
| 429 | if (!empty ($_REQUEST[$name])) |
|---|
| 430 | return Content :: getObject($_REQUEST[$name]); |
|---|
| 431 | else |
|---|
| 432 | return null; |
|---|
| 433 | } |
|---|
| 434 | |
|---|
| 435 | private function __construct($content_id) |
|---|
| 436 | { |
|---|
| 437 | global $db; |
|---|
| 438 | |
|---|
| 439 | $content_id = $db->EscapeString($content_id); |
|---|
| 440 | $sql = "SELECT * FROM content WHERE content_id='$content_id'"; |
|---|
| 441 | $db->ExecSqlUniqueRes($sql, $row, false); |
|---|
| 442 | if ($row == null) |
|---|
| 443 | { |
|---|
| 444 | throw new Exception(_("The content with the following id could not be found in the database: ").$content_id); |
|---|
| 445 | } |
|---|
| 446 | $this->content_row = $row; |
|---|
| 447 | $this->id = $row['content_id']; |
|---|
| 448 | $this->content_type = $row['content_type']; |
|---|
| 449 | |
|---|
| 450 | // By default Content display logging is enabled |
|---|
| 451 | $this->setLoggingStatus(true); |
|---|
| 452 | } |
|---|
| 453 | |
|---|
| 454 | /** A short string representation of the content */ |
|---|
| 455 | public function __toString() |
|---|
| 456 | { |
|---|
| 457 | if (empty ($this->content_row['title'])) |
|---|
| 458 | { |
|---|
| 459 | $string = _("Untitled content"); |
|---|
| 460 | } |
|---|
| 461 | else |
|---|
| 462 | { |
|---|
| 463 | $title = self :: getObject($this->content_row['title']); |
|---|
| 464 | $string = $title->__toString(); |
|---|
| 465 | } |
|---|
| 466 | return $string; |
|---|
| 467 | } |
|---|
| 468 | |
|---|
| 469 | /** Get the true object type represented by this isntance |
|---|
| 470 | * @return an array of class names */ |
|---|
| 471 | public function getObjectType() |
|---|
| 472 | { |
|---|
| 473 | return $this->content_type; |
|---|
| 474 | } |
|---|
| 475 | |
|---|
| 476 | /** |
|---|
| 477 | * Get content title |
|---|
| 478 | * @return content a content sub-class |
|---|
| 479 | */ |
|---|
| 480 | public function getTitle() |
|---|
| 481 | { |
|---|
| 482 | try |
|---|
| 483 | { |
|---|
| 484 | return self :: getObject($this->content_row['title']); |
|---|
| 485 | } |
|---|
| 486 | catch (Exception $e) |
|---|
| 487 | { |
|---|
| 488 | return null; |
|---|
| 489 | } |
|---|
| 490 | } |
|---|
| 491 | |
|---|
| 492 | /** |
|---|
| 493 | * Get content description |
|---|
| 494 | * @return content a content sub-class |
|---|
| 495 | */ |
|---|
| 496 | public function getDescription() |
|---|
| 497 | { |
|---|
| 498 | try |
|---|
| 499 | { |
|---|
| 500 | return self :: getObject($this->content_row['description']); |
|---|
| 501 | } |
|---|
| 502 | catch (Exception $e) |
|---|
| 503 | { |
|---|
| 504 | return null; |
|---|
| 505 | } |
|---|
| 506 | } |
|---|
| 507 | |
|---|
| 508 | /** |
|---|
| 509 | * Get content long description |
|---|
| 510 | * @return content a content sub-class |
|---|
| 511 | */ |
|---|
| 512 | public function getLongDescription() |
|---|
| 513 | { |
|---|
| 514 | try |
|---|
| 515 | { |
|---|
| 516 | return self :: getObject($this->content_row['long_description']); |
|---|
| 517 | } |
|---|
| 518 | catch (Exception $e) |
|---|
| 519 | { |
|---|
| 520 | return null; |
|---|
| 521 | } |
|---|
| 522 | } |
|---|
| 523 | |
|---|
| 524 | /** |
|---|
| 525 | * Get content project info |
|---|
| 526 | * @return content a content sub-class |
|---|
| 527 | */ |
|---|
| 528 | public function getProjectInfo() |
|---|
| 529 | { |
|---|
| 530 | try |
|---|
| 531 | { |
|---|
| 532 | return self :: getObject($this->content_row['project_info']); |
|---|
| 533 | } |
|---|
| 534 | catch (Exception $e) |
|---|
| 535 | { |
|---|
| 536 | return null; |
|---|
| 537 | } |
|---|
| 538 | } |
|---|
| 539 | |
|---|
| 540 | /** |
|---|
| 541 | * Get content sponsor info |
|---|
| 542 | * @return content a content sub-class |
|---|
| 543 | */ |
|---|
| 544 | public function getSponsorInfo() |
|---|
| 545 | { |
|---|
| 546 | try |
|---|
| 547 | { |
|---|
| 548 | return self :: getObject($this->content_row['sponsor_info']); |
|---|
| 549 | } |
|---|
| 550 | catch (Exception $e) |
|---|
| 551 | { |
|---|
| 552 | return null; |
|---|
| 553 | } |
|---|
| 554 | } |
|---|
| 555 | |
|---|
| 556 | /** Set the object type of this object |
|---|
| 557 | * Note that after using this, the object must be re-instanciated to have the right type |
|---|
| 558 | * */ |
|---|
| 559 | private function setContentType($content_type) |
|---|
| 560 | { |
|---|
| 561 | global $db; |
|---|
| 562 | $content_type = $db->EscapeString($content_type); |
|---|
| 563 | $available_content_types = self :: getAvailableContentTypes(); |
|---|
| 564 | if (false === array_search($content_type, $available_content_types, true)) |
|---|
| 565 | { |
|---|
| 566 | throw new Exception(_("The following content type isn't valid: ").$content_type); |
|---|
| 567 | } |
|---|
| 568 | $sql = "UPDATE content SET content_type = '$content_type' WHERE content_id='$this->id'"; |
|---|
| 569 | |
|---|
| 570 | if (!$db->ExecSqlUpdate($sql, false)) |
|---|
| 571 | { |
|---|
| 572 | throw new Exception(_("Update was unsuccessfull (database error)")); |
|---|
| 573 | } |
|---|
| 574 | |
|---|
| 575 | } |
|---|
| 576 | |
|---|
| 577 | /** Check if a user is one of the owners of the object |
|---|
| 578 | * @param $user The user to be added to the owners list |
|---|
| 579 | * @param $is_author Optionnal, true or false. Set to true if the user is one of the actual authors of the Content |
|---|
| 580 | * @return true on success, false on failure */ |
|---|
| 581 | public function addOwner(User $user, $is_author = false) |
|---|
| 582 | { |
|---|
| 583 | global $db; |
|---|
| 584 | $content_id = "'".$this->id."'"; |
|---|
| 585 | $user_id = "'".$db->EscapeString($user->getId())."'"; |
|---|
| 586 | $is_author ? $is_author = 'TRUE' : $is_author = 'FALSE'; |
|---|
| 587 | $sql = "INSERT INTO content_has_owners (content_id, user_id, is_author) VALUES ($content_id, $user_id, $is_author)"; |
|---|
| 588 | |
|---|
| 589 | if (!$db->ExecSqlUpdate($sql, false)) |
|---|
| 590 | { |
|---|
| 591 | throw new Exception(_('Unable to insert the new Owner into database.')); |
|---|
| 592 | } |
|---|
| 593 | |
|---|
| 594 | return true; |
|---|
| 595 | } |
|---|
| 596 | |
|---|
| 597 | /** Remove an owner of the content |
|---|
| 598 | * @param $user The user to be removed from the owners list |
|---|
| 599 | */ |
|---|
| 600 | public function deleteOwner(User $user, $is_author = false) |
|---|
| 601 | { |
|---|
| 602 | global $db; |
|---|
| 603 | $content_id = "'".$this->id."'"; |
|---|
| 604 | $user_id = "'".$db->EscapeString($user->getId())."'"; |
|---|
| 605 | |
|---|
| 606 | $sql = "DELETE FROM content_has_owners WHERE content_id=$content_id AND user_id=$user_id"; |
|---|
| 607 | |
|---|
| 608 | if (!$db->ExecSqlUpdate($sql, false)) |
|---|
| 609 | { |
|---|
| 610 | throw new Exception(_('Unable to remove the owner from the database.')); |
|---|
| 611 | } |
|---|
| 612 | |
|---|
| 613 | return true; |
|---|
| 614 | } |
|---|
| 615 | |
|---|
| 616 | /** |
|---|
| 617 | * Indicates display logging status |
|---|
| 618 | */ |
|---|
| 619 | public function getLoggingStatus() |
|---|
| 620 | { |
|---|
| 621 | return $this->is_logging_enabled; |
|---|
| 622 | } |
|---|
| 623 | |
|---|
| 624 | /** |
|---|
| 625 | * Sets display logging status |
|---|
| 626 | */ |
|---|
| 627 | public function setLoggingStatus($status) |
|---|
| 628 | { |
|---|
| 629 | if (is_bool($status)) |
|---|
| 630 | $this->is_logging_enabled = $status; |
|---|
| 631 | } |
|---|
| 632 | |
|---|
| 633 | /** Get the PHP timestamp of the last time this content was displayed |
|---|
| 634 | * @param $user User, Optional, if present, restrict to the selected user |
|---|
| 635 | * @param $node Node, Optional, if present, restrict to the selected node |
|---|
| 636 | * @return PHP timestamp (seconds since UNIX epoch) if the content has been |
|---|
| 637 | * displayed before, an empty string otherwise. |
|---|
| 638 | */ |
|---|
| 639 | public function getLastDisplayTimestamp($user = null, $node = null) |
|---|
| 640 | { |
|---|
| 641 | global $db; |
|---|
| 642 | $retval = ''; |
|---|
| 643 | $sql = "SELECT EXTRACT(EPOCH FROM last_display_timestamp) as last_display_unix_timestamp FROM content_display_log WHERE content_id='{$this->id}' \n"; |
|---|
| 644 | |
|---|
| 645 | if ($user) |
|---|
| 646 | { |
|---|
| 647 | $user_id = $db->EscapeString($user->getId()); |
|---|
| 648 | $sql .= " AND user_id = '{$user_id}' \n"; |
|---|
| 649 | } |
|---|
| 650 | if ($node) |
|---|
| 651 | { |
|---|
| 652 | $node_id = $db->EscapeString($node->getId()); |
|---|
| 653 | $sql .= " AND node_id = '{$node_id}' \n"; |
|---|
| 654 | } |
|---|
| 655 | $sql .= " ORDER BY last_display_timestamp DESC "; |
|---|
| 656 | $db->ExecSql($sql, $log_rows, false); |
|---|
| 657 | if ($log_rows) |
|---|
| 658 | { |
|---|
| 659 | $retval = $log_rows[0]['last_display_unix_timestamp']; |
|---|
| 660 | } |
|---|
| 661 | |
|---|
| 662 | return $retval; |
|---|
| 663 | } |
|---|
| 664 | |
|---|
| 665 | /** Is this Content element displayable at this hotspot, many classer override this |
|---|
| 666 | * @param $node Node, optionnal |
|---|
| 667 | * @return true or false */ |
|---|
| 668 | public function isDisplayableAt($node) |
|---|
| 669 | { |
|---|
| 670 | return true; |
|---|
| 671 | } |
|---|
| 672 | |
|---|
| 673 | /** Check if a user is one of the owners of the object |
|---|
| 674 | * @param $user User object: the user to be tested. |
|---|
| 675 | * @return true if the user is a owner, false if he isn't of the user is null */ |
|---|
| 676 | public function isOwner($user) |
|---|
| 677 | { |
|---|
| 678 | global $db; |
|---|
| 679 | $retval = false; |
|---|
| 680 | if ($user != null) |
|---|
| 681 | { |
|---|
| 682 | $user_id = $db->EscapeString($user->GetId()); |
|---|
| 683 | $sql = "SELECT * FROM content_has_owners WHERE content_id='$this->id' AND user_id='$user_id'"; |
|---|
| 684 | $db->ExecSqlUniqueRes($sql, $content_owner_row, false); |
|---|
| 685 | if ($content_owner_row != null) |
|---|
| 686 | { |
|---|
| 687 | $retval = true; |
|---|
| 688 | } |
|---|
| 689 | } |
|---|
| 690 | |
|---|
| 691 | return $retval; |
|---|
| 692 | } |
|---|
| 693 | /** Get the authors of the Content |
|---|
| 694 | * @return null or array of User objects */ |
|---|
| 695 | public function getAuthors() |
|---|
| 696 | { |
|---|
| 697 | global $db; |
|---|
| 698 | $retval = array (); |
|---|
| 699 | $sql = "SELECT user_id FROM content_has_owners WHERE content_id='$this->id' AND is_author=TRUE"; |
|---|
| 700 | $db->ExecSqlUniqueRes($sql, $content_owner_row, false); |
|---|
| 701 | if ($content_owner_row != null) |
|---|
| 702 | { |
|---|
| 703 | $user = User :: getObject($content_owner_row['user_id']); |
|---|
| 704 | $retval[] = $user; |
|---|
| 705 | } |
|---|
| 706 | |
|---|
| 707 | return $retval; |
|---|
| 708 | } |
|---|
| 709 | /** @see GenricObject |
|---|
| 710 | * @return The id */ |
|---|
| 711 | public function getId() |
|---|
| 712 | { |
|---|
| 713 | return $this->id; |
|---|
| 714 | } |
|---|
| 715 | |
|---|
| 716 | /** When a content object is set as trivial, it means that is is used merely to contain it's own data. No title, description or other data will be set or displayed, during display or administration |
|---|
| 717 | * @param $is_trivial true or false */ |
|---|
| 718 | public function setIsTrivialContent($is_trivial) |
|---|
| 719 | { |
|---|
| 720 | $this->is_trivial_content = $is_trivial; |
|---|
| 721 | } |
|---|
| 722 | |
|---|
| 723 | /** Retreives the user interface of this object. Anything that overrides this method should call the parent method with it's output at the END of processing. |
|---|
| 724 | * @param $subclass_admin_interface Html content of the interface element of a children |
|---|
| 725 | * @return The HTML fragment for this interface */ |
|---|
| 726 | public function getUserUI($subclass_user_interface = null) |
|---|
| 727 | { |
|---|
| 728 | $html = ''; |
|---|
| 729 | $html .= "<div class='user_ui_main_outer'>\n"; |
|---|
| 730 | $html .= "<div class='user_ui_main_inner'>\n"; |
|---|
| 731 | $html .= "<div class='user_ui_object_class'>Content (".get_class($this)." instance)</div>\n"; |
|---|
| 732 | |
|---|
| 733 | if (!empty ($this->content_row['title'])) |
|---|
| 734 | { |
|---|
| 735 | $html .= "<div class='user_ui_title'>\n"; |
|---|
| 736 | $title = self :: getObject($this->content_row['title']); |
|---|
| 737 | // If the content logging is disabled, all the children will inherit this property temporarly |
|---|
| 738 | if ($this->getLoggingStatus() == false) |
|---|
| 739 | $title->setLoggingStatus(false); |
|---|
| 740 | $html .= $title->getUserUI(); |
|---|
| 741 | $html .= "</div>\n"; |
|---|
| 742 | } |
|---|
| 743 | |
|---|
| 744 | $html .= "<table><tr><td>\n"; |
|---|
| 745 | $authors = $this->getAuthors(); |
|---|
| 746 | if (count($authors) > 0) |
|---|
| 747 | { |
|---|
| 748 | $html .= "<div class='user_ui_authors'>\n"; |
|---|
| 749 | $html .= _("Author(s):"); |
|---|
| 750 | foreach ($authors as $user) |
|---|
| 751 | { |
|---|
| 752 | $html .= $user->getUsername()." "; |
|---|
| 753 | } |
|---|
| 754 | $html .= "</div>\n"; |
|---|
| 755 | } |
|---|
| 756 | |
|---|
| 757 | if (!empty ($this->content_row['description'])) |
|---|
| 758 | { |
|---|
| 759 | $html .= "<div class='user_ui_description'>\n"; |
|---|
| 760 | $description = self :: getObject($this->content_row['description']); |
|---|
| 761 | // If the content logging is disabled, all the children will inherit this property temporarly |
|---|
| 762 | if ($this->getLoggingStatus() == false) |
|---|
| 763 | $description->setLoggingStatus(false); |
|---|
| 764 | $html .= $description->getUserUI(); |
|---|
| 765 | $html .= "</div>\n"; |
|---|
| 766 | } |
|---|
| 767 | |
|---|
| 768 | if (!empty ($this->content_row['project_info']) || !empty ($this->content_row['sponsor_info'])) |
|---|
| 769 | { |
|---|
| 770 | if (!empty ($this->content_row['project_info'])) |
|---|
| 771 | { |
|---|
| 772 | $html .= "<div class='user_ui_projet_info'>\n"; |
|---|
| 773 | $html .= "<b>"._("Project information:")."</b>"; |
|---|
| 774 | $project_info = self :: getObject($this->content_row['project_info']); |
|---|
| 775 | // If the content logging is disabled, all the children will inherit this property temporarly |
|---|
| 776 | if ($this->getLoggingStatus() == false) |
|---|
| 777 | $project_info->setLoggingStatus(false); |
|---|
| 778 | $html .= $project_info->getUserUI(); |
|---|
| 779 | $html .= "</div>\n"; |
|---|
| 780 | } |
|---|
| 781 | |
|---|
| 782 | if (!empty ($this->content_row['sponsor_info'])) |
|---|
| 783 | { |
|---|
| 784 | $html .= "<div class='user_ui_sponsor_info'>\n"; |
|---|
| 785 | $html .= "<b>"._("Project sponsor:")."</b>"; |
|---|
| 786 | $sponsor_info = self :: getObject($this->content_row['sponsor_info']); |
|---|
| 787 | // If the content logging is disabled, all the children will inherit this property temporarly |
|---|
| 788 | if ($this->getLoggingStatus() == false) |
|---|
| 789 | $sponsor_info->setLoggingStatus(false); |
|---|
| 790 | $html .= $sponsor_info->getUserUI(); |
|---|
| 791 | $html .= "</div>\n"; |
|---|
| 792 | } |
|---|
| 793 | } |
|---|
| 794 | |
|---|
| 795 | $html .= "</td>\n"; |
|---|
| 796 | |
|---|
| 797 | $html .= "<td>\n$subclass_user_interface</td>\n"; |
|---|
| 798 | $html .= "</tr></table>\n"; |
|---|
| 799 | |
|---|
| 800 | $html .= "</div>\n"; |
|---|
| 801 | $html .= "</div>\n"; |
|---|
| 802 | $this->logContentDisplay(); |
|---|
| 803 | return $html; |
|---|
| 804 | } |
|---|
| 805 | |
|---|
| 806 | /** Log that this content has just been displayed to the user. Will only log if the user is logged in */ |
|---|
| 807 | private function logContentDisplay() |
|---|
| 808 | { |
|---|
| 809 | if ($this->getLoggingStatus() == true) |
|---|
| 810 | { |
|---|
| 811 | // DEBUG:: |
|---|
| 812 | //echo "Logging ".get_class($this)." :: ".$this->__toString()."<br>"; |
|---|
| 813 | $user = User :: getCurrentUser(); |
|---|
| 814 | $node = Node :: getCurrentNode(); |
|---|
| 815 | if ($user != null && $node != null) |
|---|
| 816 | { |
|---|
| 817 | $user_id = $user->getId(); |
|---|
| 818 | $node_id = $node->getId(); |
|---|
| 819 | global $db; |
|---|
| 820 | |
|---|
| 821 | $sql = "SELECT * FROM content_display_log WHERE user_id='$user_id' AND node_id='$node_id' AND content_id='$this->id'"; |
|---|
| 822 | $db->ExecSql($sql, $log_rows, false); |
|---|
| 823 | if ($log_rows != null) |
|---|
| 824 | { |
|---|
| 825 | $sql = "UPDATE content_display_log SET last_display_timestamp = NOW() WHERE user_id='$user_id' AND content_id='$this->id' AND node_id='$node_id'"; |
|---|
| 826 | } |
|---|
| 827 | else |
|---|
| 828 | { |
|---|
| 829 | $sql = "INSERT INTO content_display_log (user_id, content_id, node_id) VALUES ('$user_id', '$this->id', '$node_id')"; |
|---|
| 830 | } |
|---|
| 831 | $db->ExecSqlUpdate($sql, false); |
|---|
| 832 | } |
|---|
| 833 | } |
|---|
| 834 | } |
|---|
| 835 | |
|---|
| 836 | /** Retreives the list interface of this object. Anything that overrides this method should call the parent method with it's output at the END of processing. |
|---|
| 837 | * @param $subclass_admin_interface Html content of the interface element of a children |
|---|
| 838 | * @return The HTML fragment for this interface */ |
|---|
| 839 | public function getListUI($subclass_list_interface = null) |
|---|
| 840 | { |
|---|
| 841 | $html = ''; |
|---|
| 842 | $html .= "<div class='list_ui_container'>\n"; |
|---|
| 843 | $html .= $this->__toString()." (".get_class($this).")\n"; |
|---|
| 844 | $html .= $subclass_list_interface; |
|---|
| 845 | $html .= "</div>\n"; |
|---|
| 846 | return $html; |
|---|
| 847 | } |
|---|
| 848 | |
|---|
| 849 | /** Retreives the admin interface of this object. Anything that overrides this method should call the parent method with it's output at the END of processing. |
|---|
| 850 | * @param $subclass_admin_interface Html content of the interface element of a children |
|---|
| 851 | * @return The HTML fragment for this interface */ |
|---|
| 852 | public function getAdminUI($subclass_admin_interface = null) |
|---|
| 853 | { |
|---|
| 854 | global $db; |
|---|
| 855 | $html = ''; |
|---|
| 856 | $html .= "<div class='admin_container'>\n"; |
|---|
| 857 | $html .= "<div class='admin_class'>Content (".get_class($this)." instance)</div>\n"; |
|---|
| 858 | if ($this->getObjectType() == 'Content') /* The object hasn't yet been typed */ |
|---|
| 859 | { |
|---|
| 860 | $html .= _("You must select a content type: "); |
|---|
| 861 | $i = 0; |
|---|
| 862 | foreach (self :: getAvailableContentTypes() as $classname) |
|---|
| 863 | { |
|---|
| 864 | $tab[$i][0] = $classname; |
|---|
| 865 | $tab[$i][1] = $classname; |
|---|
| 866 | $i ++; |
|---|
| 867 | } |
|---|
| 868 | $html .= FormSelectGenerator :: generateFromArray($tab, null, "content_".$this->id."_content_type", "Content", false); |
|---|
| 869 | } |
|---|
| 870 | else |
|---|
| 871 | if ($this->is_trivial_content == false) |
|---|
| 872 | { |
|---|
| 873 | /* title */ |
|---|
| 874 | $html .= "<div class='admin_section_container'>\n"; |
|---|
| 875 | $html .= "<div class='admin_section_title'>"._("Title:")."</div>\n"; |
|---|
| 876 | $html .= "<div class='admin_section_data'>\n"; |
|---|
| 877 | if (empty ($this->content_row['title'])) |
|---|
| 878 | { |
|---|
| 879 | $html .= self :: getNewContentUI("title_{$this->id}_new"); |
|---|
| 880 | $html .= "</div>\n"; |
|---|
| 881 | } |
|---|
| 882 | else |
|---|
| 883 | { |
|---|
| 884 | $title = self :: getObject($this->content_row['title']); |
|---|
| 885 | $html .= $title->getAdminUI(); |
|---|
| 886 | $html .= "</div>\n"; |
|---|
| 887 | $html .= "<div class='admin_section_tools'>\n"; |
|---|
| 888 | $name = "content_".$this->id."_title_erase"; |
|---|
| 889 | $html .= "<input type='submit' name='$name' value='"._("Delete")."'>"; |
|---|
| 890 | $html .= "</div>\n"; |
|---|
| 891 | } |
|---|
| 892 | $html .= "</div>\n"; |
|---|
| 893 | |
|---|
| 894 | /* is_persistent */ |
|---|
| 895 | $html .= "<div class='admin_section_container'>\n"; |
|---|
| 896 | $html .= "<div class='admin_section_title'>Is persistent (reusable and read-only)?: </div>\n"; |
|---|
| 897 | $html .= "<div class='admin_section_data'>\n"; |
|---|
| 898 | $name = "content_".$this->id."_is_persistent"; |
|---|
| 899 | $this->isPersistent() ? $checked = 'CHECKED' : $checked = ''; |
|---|
| 900 | $html .= "<input type='checkbox' name='$name' $checked>\n"; |
|---|
| 901 | $html .= "</div>\n"; |
|---|
| 902 | $html .= "</div>\n"; |
|---|
| 903 | |
|---|
| 904 | /* description */ |
|---|
| 905 | $html .= "<div class='admin_section_container'>\n"; |
|---|
| 906 | $html .= "<div class='admin_section_title'>"._("Description:")."</div>\n"; |
|---|
| 907 | $html .= "<div class='admin_section_data'>\n"; |
|---|
| 908 | if (empty ($this->content_row['description'])) |
|---|
| 909 | { |
|---|
| 910 | $html .= self :: getNewContentUI("description_{$this->id}_new"); |
|---|
| 911 | $html .= "</div>\n"; |
|---|
| 912 | } |
|---|
| 913 | else |
|---|
| 914 | { |
|---|
| 915 | $description = self :: getObject($this->content_row['description']); |
|---|
| 916 | $html .= $description->getAdminUI(); |
|---|
| 917 | $html .= "</div>\n"; |
|---|
| 918 | $html .= "<div class='admin_section_tools'>\n"; |
|---|
| 919 | $name = "content_".$this->id."_description_erase"; |
|---|
| 920 | $html .= "<input type='submit' name='$name' value='"._("Delete")."'>"; |
|---|
| 921 | $html .= "</div>\n"; |
|---|
| 922 | } |
|---|
| 923 | $html .= "</div>\n"; |
|---|
| 924 | |
|---|
| 925 | /* long description */ |
|---|
| 926 | $html .= "<div class='admin_section_container'>\n"; |
|---|
| 927 | $html .= "<div class='admin_section_title'>"._("Long description:")."</div>\n"; |
|---|
| 928 | $html .= "<div class='admin_section_data'>\n"; |
|---|
| 929 | if (empty ($this->content_row['long_description'])) |
|---|
| 930 | { |
|---|
| 931 | $html .= self :: getNewContentUI("long_description_{$this->id}_new"); |
|---|
| 932 | $html .= "</div>\n"; |
|---|
| 933 | } |
|---|
| 934 | else |
|---|
| 935 | { |
|---|
| 936 | $description = self :: getObject($this->content_row['long_description']); |
|---|
| 937 | $html .= $description->getAdminUI(); |
|---|
| 938 | $html .= "</div>\n"; |
|---|
| 939 | $html .= "<div class='admin_section_tools'>\n"; |
|---|
| 940 | $name = "content_".$this->id."_long_description_erase"; |
|---|
| 941 | $html .= "<input type='submit' name='$name' value='"._("Delete")."'>"; |
|---|
| 942 | $html .= "</div>\n"; |
|---|
| 943 | } |
|---|
| 944 | $html .= "</div>\n"; |
|---|
| 945 | |
|---|
| 946 | /* project_info */ |
|---|
| 947 | $html .= "<div class='admin_section_container'>\n"; |
|---|
| 948 | $html .= "<div class='admin_section_title'>"._("Information on this project:")."</div>\n"; |
|---|
| 949 | $html .= "<div class='admin_section_data'>\n"; |
|---|
| 950 | if (empty ($this->content_row['project_info'])) |
|---|
| 951 | { |
|---|
| 952 | $html .= self :: getNewContentUI("project_info_{$this->id}_new"); |
|---|
| 953 | $html .= "</div>\n"; |
|---|
| 954 | } |
|---|
| 955 | else |
|---|
| 956 | { |
|---|
| 957 | $project_info = self :: getObject($this->content_row['project_info']); |
|---|
| 958 | $html .= $project_info->getAdminUI(); |
|---|
| 959 | $html .= "</div>\n"; |
|---|
| 960 | $html .= "<div class='admin_section_tools'>\n"; |
|---|
| 961 | $name = "content_".$this->id."_project_info_erase"; |
|---|
| 962 | $html .= "<input type='submit' name='$name' value='"._("Delete")."'>"; |
|---|
| 963 | $html .= "</div>\n"; |
|---|
| 964 | } |
|---|
| 965 | $html .= "</div>\n"; |
|---|
| 966 | |
|---|
| 967 | /* sponsor_info */ |
|---|
| 968 | $html .= "<div class='admin_section_container'>\n"; |
|---|
| 969 | $html .= "<div class='admin_section_title'>"._("Sponsor of this project:")."</div>\n"; |
|---|
| 970 | $html .= "<div class='admin_section_data'>\n"; |
|---|
| 971 | if (empty ($this->content_row['sponsor_info'])) |
|---|
| 972 | { |
|---|
| 973 | $html .= self :: getNewContentUI("sponsor_info_{$this->id}_new"); |
|---|
| 974 | $html .= "</div>\n"; |
|---|
| 975 | } |
|---|
| 976 | else |
|---|
| 977 | { |
|---|
| 978 | $sponsor_info = self :: getObject($this->content_row['sponsor_info']); |
|---|
| 979 | $html .= $sponsor_info->getAdminUI(); |
|---|
| 980 | $html .= "</div>\n"; |
|---|
| 981 | $html .= "<div class='admin_section_tools'>\n"; |
|---|
| 982 | $name = "content_".$this->id."_sponsor_info_erase"; |
|---|
| 983 | $html .= "<input type='submit' name='$name' value='"._("Delete")."'>"; |
|---|
| 984 | $html .= "</div>\n"; |
|---|
| 985 | } |
|---|
| 986 | $html .= "</div>\n"; |
|---|
| 987 | |
|---|
| 988 | /* content_has_owners */ |
|---|
| 989 | $html .= "<div class='admin_section_container'>\n"; |
|---|
| 990 | $html .= "<span class='admin_section_title'>"._("Content owner list")."</span>\n"; |
|---|
| 991 | $html .= "<ul class='admin_section_list'>\n"; |
|---|
| 992 | |
|---|
| 993 | global $db; |
|---|
| 994 | $sql = "SELECT * FROM content_has_owners WHERE content_id='$this->id'"; |
|---|
| 995 | $db->ExecSql($sql, $content_owner_rows, false); |
|---|
| 996 | if ($content_owner_rows != null) |
|---|
| 997 | { |
|---|
| 998 | foreach ($content_owner_rows as $content_owner_row) |
|---|
| 999 | { |
|---|
| 1000 | $html .= "<li class='admin_section_list_item'>\n"; |
|---|
| 1001 | $html .= "<div class='admin_section_data'>\n"; |
|---|
| 1002 | $user = User :: getObject($content_owner_row['user_id']); |
|---|
| 1003 | |
|---|
| 1004 | $html .= $user->getUserListUI(); |
|---|
| 1005 | $name = "content_".$this->id."_owner_".$user->GetId()."_is_author"; |
|---|
| 1006 | $html .= " Is content author? "; |
|---|
| 1007 | |
|---|
| 1008 | $content_owner_row['is_author'] == 't' ? $checked = 'CHECKED' : $checked = ''; |
|---|
| 1009 | $html .= "<input type='checkbox' name='$name' $checked>\n"; |
|---|
| 1010 | $html .= "</div>\n"; |
|---|
| 1011 | $html .= "<div class='admin_section_tools'>\n"; |
|---|
| 1012 | $name = "content_".$this->id."_owner_".$user->GetId()."_remove"; |
|---|
| 1013 | $html .= "<input type='submit' name='$name' value='"._("Remove")."'>"; |
|---|
| 1014 | $html .= "</div>\n"; |
|---|
| 1015 | $html .= "</li>\n"; |
|---|
| 1016 | } |
|---|
| 1017 | } |
|---|
| 1018 | |
|---|
| 1019 | $html .= "<li class='admin_section_list_item'>\n"; |
|---|
| 1020 | $html .= "<div class='admin_section_data'>\n"; |
|---|
| 1021 | $html .= User :: getSelectUserUI("content_{$this->id}_new_owner"); |
|---|
| 1022 | $html .= "</div>\n"; |
|---|
| 1023 | $html .= "<div class='admin_section_tools'>\n"; |
|---|
| 1024 | $name = "content_{$this->id}_add_owner_submit"; |
|---|
| 1025 | $value = _("Add owner"); |
|---|
| 1026 | $html .= "<input type='submit' name='$name' value='$value'>"; |
|---|
| 1027 | $html .= "</div>\n"; |
|---|
| 1028 | $html .= "</li>\n"; |
|---|
| 1029 | $html .= "</ul>\n"; |
|---|
| 1030 | $html .= "</div>\n"; |
|---|
| 1031 | } |
|---|
| 1032 | $html .= $subclass_admin_interface; |
|---|
| 1033 | $html .= "</div>\n"; |
|---|
| 1034 | return $html; |
|---|
| 1035 | } |
|---|
| 1036 | /** Process admin interface of this object. When an object overrides this method, they should call the parent processAdminUI at the BEGINING of processing. |
|---|
| 1037 | |
|---|
| 1038 | */ |
|---|
| 1039 | public function processAdminUI() |
|---|
| 1040 | { |
|---|
| 1041 | if ($this->isOwner(User :: getCurrentUser()) || User :: getCurrentUser()->isSuperAdmin()) |
|---|
| 1042 | { |
|---|
| 1043 | global $db; |
|---|
| 1044 | if ($this->getObjectType() == 'Content') /* The object hasn't yet been typed */ |
|---|
| 1045 | { |
|---|
| 1046 | $content_type = FormSelectGenerator :: getResult("content_".$this->id."_content_type", "Content"); |
|---|
| 1047 | $this->setContentType($content_type); |
|---|
| 1048 | } |
|---|
| 1049 | else |
|---|
| 1050 | if ($this->is_trivial_content == false) |
|---|
| 1051 | { |
|---|
| 1052 | /* title */ |
|---|
| 1053 | if (empty ($this->content_row['title'])) |
|---|
| 1054 | { |
|---|
| 1055 | $title = self :: processNewContentUI("title_{$this->id}_new"); |
|---|
| 1056 | if ($title != null) |
|---|
| 1057 | { |
|---|
| 1058 | $title_id = $title->GetId(); |
|---|
| 1059 | $db->ExecSqlUpdate("UPDATE content SET title = '$title_id' WHERE content_id = '$this->id'", FALSE); |
|---|
| 1060 | } |
|---|
| 1061 | } |
|---|
| 1062 | else |
|---|
| 1063 | { |
|---|
| 1064 | $title = self :: getObject($this->content_row['title']); |
|---|
| 1065 | $name = "content_".$this->id."_title_erase"; |
|---|
| 1066 | if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) |
|---|
| 1067 | { |
|---|
| 1068 | $db->ExecSqlUpdate("UPDATE content SET title = NULL WHERE content_id = '$this->id'", FALSE); |
|---|
| 1069 | $title->delete($errmsg); |
|---|
| 1070 | } |
|---|
| 1071 | else |
|---|
| 1072 | { |
|---|
| 1073 | $title->processAdminUI(); |
|---|
| 1074 | } |
|---|
| 1075 | } |
|---|
| 1076 | |
|---|
| 1077 | /* is_persistent */ |
|---|
| 1078 | $name = "content_".$this->id."_is_persistent"; |
|---|
| 1079 | !empty ($_REQUEST[$name]) ? $this->setIsPersistent(true) : $this->setIsPersistent(false); |
|---|
| 1080 | |
|---|
| 1081 | /* description */ |
|---|
| 1082 | if (empty ($this->content_row['description'])) |
|---|
| 1083 | { |
|---|
| 1084 | $description = self :: processNewContentUI("description_{$this->id}_new"); |
|---|
| 1085 | if ($description != null) |
|---|
| 1086 | { |
|---|
| 1087 | $description_id = $description->GetId(); |
|---|
| 1088 | $db->ExecSqlUpdate("UPDATE content SET description = '$description_id' WHERE content_id = '$this->id'", FALSE); |
|---|
| 1089 | } |
|---|
| 1090 | } |
|---|
| 1091 | else |
|---|
| 1092 | { |
|---|
| 1093 | $description = self :: getObject($this->content_row['description']); |
|---|
| 1094 | $name = "content_".$this->id."_description_erase"; |
|---|
| 1095 | if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) |
|---|
| 1096 | { |
|---|
| 1097 | $db->ExecSqlUpdate("UPDATE content SET description = NULL WHERE content_id = '$this->id'", FALSE); |
|---|
| 1098 | $description->delete($errmsg); |
|---|
| 1099 | } |
|---|
| 1100 | else |
|---|
| 1101 | { |
|---|
| 1102 | $description->processAdminUI(); |
|---|
| 1103 | } |
|---|
| 1104 | } |
|---|
| 1105 | |
|---|
| 1106 | /* long description */ |
|---|
| 1107 | if (empty ($this->content_row['long_description'])) |
|---|
| 1108 | { |
|---|
| 1109 | $long_description = self :: processNewContentUI("long_description_{$this->id}_new"); |
|---|
| 1110 | if ($long_description != null) |
|---|
| 1111 | { |
|---|
| 1112 | $long_description_id = $long_description->GetId(); |
|---|
| 1113 | $db->ExecSqlUpdate("UPDATE content SET long_description = '$long_description_id' WHERE content_id = '$this->id'", FALSE); |
|---|
| 1114 | } |
|---|
| 1115 | } |
|---|
| 1116 | else |
|---|
| 1117 | { |
|---|
| 1118 | $long_description = self :: getObject($this->content_row['long_description']); |
|---|
| 1119 | $name = "content_".$this->id."_long_description_erase"; |
|---|
| 1120 | if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) |
|---|
| 1121 | { |
|---|
| 1122 | $db->ExecSqlUpdate("UPDATE content SET long_description = NULL WHERE content_id = '$this->id'", FALSE); |
|---|
| 1123 | $long_description->delete($errmsg); |
|---|
| 1124 | } |
|---|
| 1125 | else |
|---|
| 1126 | { |
|---|
| 1127 | $long_description->processAdminUI(); |
|---|
| 1128 | } |
|---|
| 1129 | } |
|---|
| 1130 | |
|---|
| 1131 | /* project_info */ |
|---|
| 1132 | if (empty ($this->content_row['project_info'])) |
|---|
| 1133 | { |
|---|
| 1134 | $project_info = self :: processNewContentUI("project_info_{$this->id}_new"); |
|---|
| 1135 | if ($project_info != null) |
|---|
| 1136 | { |
|---|
| 1137 | $project_info_id = $project_info->GetId(); |
|---|
| 1138 | $db->ExecSqlUpdate("UPDATE content SET project_info = '$project_info_id' WHERE content_id = '$this->id'", FALSE); |
|---|
| 1139 | } |
|---|
| 1140 | } |
|---|
| 1141 | else |
|---|
| 1142 | { |
|---|
| 1143 | $project_info = self :: getObject($this->content_row['project_info']); |
|---|
| 1144 | $name = "content_".$this->id."_project_info_erase"; |
|---|
| 1145 | if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) |
|---|
| 1146 | { |
|---|
| 1147 | $db->ExecSqlUpdate("UPDATE content SET project_info = NULL WHERE content_id = '$this->id'", FALSE); |
|---|
| 1148 | $project_info->delete($errmsg); |
|---|
| 1149 | } |
|---|
| 1150 | else |
|---|
| 1151 | { |
|---|
| 1152 | $project_info->processAdminUI(); |
|---|
| 1153 | } |
|---|
| 1154 | } |
|---|
| 1155 | |
|---|
| 1156 | /* sponsor_info */ |
|---|
| 1157 | if (empty ($this->content_row['sponsor_info'])) |
|---|
| 1158 | { |
|---|
| 1159 | $sponsor_info = self :: processNewContentUI("sponsor_info_{$this->id}_new"); |
|---|
| 1160 | if ($sponsor_info != null) |
|---|
| 1161 | { |
|---|
| 1162 | $sponsor_info_id = $sponsor_info->GetId(); |
|---|
| 1163 | $db->ExecSqlUpdate("UPDATE content SET sponsor_info = '$sponsor_info_id' WHERE content_id = '$this->id'", FALSE); |
|---|
| 1164 | } |
|---|
| 1165 | } |
|---|
| 1166 | else |
|---|
| 1167 | { |
|---|
| 1168 | $sponsor_info = self :: getObject($this->content_row['sponsor_info']); |
|---|
| 1169 | $name = "content_".$this->id."_sponsor_info_erase"; |
|---|
| 1170 | if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) |
|---|
| 1171 | { |
|---|
| 1172 | $db->ExecSqlUpdate("UPDATE content SET sponsor_info = NULL WHERE content_id = '$this->id'", FALSE); |
|---|
| 1173 | $sponsor_info->delete($errmsg); |
|---|
| 1174 | } |
|---|
| 1175 | else |
|---|
| 1176 | { |
|---|
| 1177 | $sponsor_info->processAdminUI(); |
|---|
| 1178 | } |
|---|
| 1179 | } |
|---|
| 1180 | /* content_has_owners */ |
|---|
| 1181 | $sql = "SELECT * FROM content_has_owners WHERE content_id='$this->id'"; |
|---|
| 1182 | $db->ExecSql($sql, $content_owner_rows, false); |
|---|
| 1183 | if ($content_owner_rows != null) |
|---|
| 1184 | { |
|---|
| 1185 | foreach ($content_owner_rows as $content_owner_row) |
|---|
| 1186 | { |
|---|
| 1187 | $user = User :: getObject($content_owner_row['user_id']); |
|---|
| 1188 | $user_id = $user->getId(); |
|---|
| 1189 | $name = "content_".$this->id."_owner_".$user->GetId()."_remove"; |
|---|
| 1190 | if (!empty ($_REQUEST[$name])) |
|---|
| 1191 | { |
|---|
| 1192 | $this->deleteOwner($user); |
|---|
| 1193 | } |
|---|
| 1194 | else |
|---|
| 1195 | { |
|---|
| 1196 | $name = "content_".$this->id."_owner_".$user->GetId()."_is_author"; |
|---|
| 1197 | $content_owner_row['is_author'] == 't' ? $is_author = true : $is_author = false; |
|---|
| 1198 | !empty ($_REQUEST[$name]) ? $should_be_author = true : $should_be_author = false; |
|---|
| 1199 | if ($is_author != $should_be_author) |
|---|
| 1200 | { |
|---|
| 1201 | $should_be_author ? $is_author_sql = 'TRUE' : $is_author_sql = 'FALSE'; |
|---|
| 1202 | $sql = "UPDATE content_has_owners SET is_author=$is_author_sql WHERE content_id='$this->id' AND user_id='$user_id'"; |
|---|
| 1203 | |
|---|
| 1204 | if (!$db->ExecSqlUpdate($sql, false)) |
|---|
| 1205 | { |
|---|
| 1206 | throw new Exception(_('Unable to set as author in the database.')); |
|---|
| 1207 | } |
|---|
| 1208 | |
|---|
| 1209 | } |
|---|
| 1210 | |
|---|
| 1211 | } |
|---|
| 1212 | } |
|---|
| 1213 | } |
|---|
| 1214 | $user = User :: processSelectUserUI("content_{$this->id}_new_owner"); |
|---|
| 1215 | $name = "content_{$this->id}_add_owner_submit"; |
|---|
| 1216 | if (!empty ($_REQUEST[$name]) && $user != null) |
|---|
| 1217 | { |
|---|
| 1218 | $this->addOwner($user); |
|---|
| 1219 | } |
|---|
| 1220 | |
|---|
| 1221 | } |
|---|
| 1222 | $this->refresh(); |
|---|
| 1223 | } |
|---|
| 1224 | } |
|---|
| 1225 | |
|---|
| 1226 | /** |
|---|
| 1227 | * Tell if a given user is already subscribed to this content |
|---|
| 1228 | * @param User the given user |
|---|
| 1229 | * @return boolean |
|---|
| 1230 | */ |
|---|
| 1231 | public function isUserSubscribed(User $user) |
|---|
| 1232 | { |
|---|
| 1233 | global $db; |
|---|
| 1234 | $sql = "SELECT content_id FROM user_has_content WHERE user_id = '{$user->getId()}' AND content_id = '{$this->getId()}';"; |
|---|
| 1235 | $db->ExecSqlUniqueRes($sql, $row, false); |
|---|
| 1236 | |
|---|
| 1237 | if ($row) |
|---|
| 1238 | return true; |
|---|
| 1239 | else |
|---|
| 1240 | return false; |
|---|
| 1241 | } |
|---|
| 1242 | |
|---|
| 1243 | /** Subscribe to the project |
|---|
| 1244 | * @return true on success, false on failure */ |
|---|
| 1245 | public function subscribe(User $user) |
|---|
| 1246 | { |
|---|
| 1247 | return $user->addContent($this); |
|---|
| 1248 | } |
|---|
| 1249 | /** Unsubscribe to the project |
|---|
| 1250 | * @return true on success, false on failure */ |
|---|
| 1251 | public function unsubscribe(User $user) |
|---|
| 1252 | { |
|---|
| 1253 | return $user->removeContent($this); |
|---|
| 1254 | } |
|---|
| 1255 | |
|---|
| 1256 | /** Persistent (or read-only) content is meant for re-use. It will not be deleted when the delete() method is called. When a containing element (ContentGroup, ContentGroupElement) is deleted, it calls delete on all the content it includes. If the content is persistent, only the association will be removed. |
|---|
| 1257 | * @return true or false */ |
|---|
| 1258 | public function isPersistent() |
|---|
| 1259 | { |
|---|
| 1260 | if ($this->content_row['is_persistent'] == 't') |
|---|
| 1261 | { |
|---|
| 1262 | $retval = true; |
|---|
| 1263 | } |
|---|
| 1264 | else |
|---|
| 1265 | { |
|---|
| 1266 | $retval = false; |
|---|
| 1267 | } |
|---|
| 1268 | return $retval; |
|---|
| 1269 | } |
|---|
| 1270 | |
|---|
| 1271 | /** Set if the content group is persistent |
|---|
| 1272 | * @param $is_locative_content true or false |
|---|
| 1273 | * */ |
|---|
| 1274 | public function setIsPersistent($is_persistent) |
|---|
| 1275 | { |
|---|
| 1276 | if ($is_persistent != $this->isPersistent()) /* Only update database if there is an actual change */ |
|---|
| 1277 | { |
|---|
| 1278 | $is_persistent ? $is_persistent_sql = 'TRUE' : $is_persistent_sql = 'FALSE'; |
|---|
| 1279 | |
|---|
| 1280 | global $db; |
|---|
| 1281 | $db->ExecSqlUpdate("UPDATE content SET is_persistent = $is_persistent_sql WHERE content_id = '$this->id'", false); |
|---|
| 1282 | $this->refresh(); |
|---|
| 1283 | } |
|---|
| 1284 | |
|---|
| 1285 | } |
|---|
| 1286 | |
|---|
| 1287 | /** Reloads the object from the database. Should normally be called after a set operation. |
|---|
| 1288 | * This function is private because calling it from a subclass will call the |
|---|
| 1289 | * constructor from the wrong scope */ |
|---|
| 1290 | private function refresh() |
|---|
| 1291 | { |
|---|
| 1292 | $this->__construct($this->id); |
|---|
| 1293 | } |
|---|
| 1294 | |
|---|
| 1295 | /** @see GenericObject |
|---|
| 1296 | * @note Persistent content will not be deleted |
|---|
| 1297 | */ |
|---|
| 1298 | public function delete(& $errmsg) |
|---|
| 1299 | { |
|---|
| 1300 | $retval = false; |
|---|
| 1301 | if ($this->isPersistent()) |
|---|
| 1302 | { |
|---|
| 1303 | $errmsg = _("Content is persistent (you must make it non persistent before you can delete it)"); |
|---|
| 1304 | } |
|---|
| 1305 | else |
|---|
| 1306 | { |
|---|
| 1307 | global $db; |
|---|
| 1308 | if ($this->isOwner(User :: getCurrentUser()) || User :: getCurrentUser()->isSuperAdmin()) |
|---|
| 1309 | { |
|---|
| 1310 | $sql = "DELETE FROM content WHERE content_id='$this->id'"; |
|---|
| 1311 | $db->ExecSqlUpdate($sql, false); |
|---|
| 1312 | $retval = true; |
|---|
| 1313 | } |
|---|
| 1314 | else |
|---|
| 1315 | { |
|---|
| 1316 | $errmsg = _("Access denied (not owner of content)"); |
|---|
| 1317 | } |
|---|
| 1318 | } |
|---|
| 1319 | return $retval; |
|---|
| 1320 | } |
|---|
| 1321 | |
|---|
| 1322 | } // End class |
|---|
| 1323 | |
|---|
| 1324 | /* This allows the class to enumerate it's children properly */ |
|---|
| 1325 | $class_names = Content :: getAvailableContentTypes(); |
|---|
| 1326 | foreach ($class_names as $class_name) |
|---|
| 1327 | { |
|---|
| 1328 | require_once BASEPATH."classes/Content/{$class_name}/{$class_name}.php"; |
|---|
| 1329 | } |
|---|
| 1330 | ?> |
|---|