* License: GPLv2 * Description: Annotate images * Documentation: */ class Notes extends Extension { public function onInitExt(InitExtEvent $event) { global $config, $database; // shortcut to latest if ($config->get_int("ext_notes_version") < 1) { $database->Execute("ALTER TABLE images ADD COLUMN notes INTEGER NOT NULL DEFAULT 0"); $database->create_table("notes", " id SCORE_AIPK, enable INTEGER NOT NULL, image_id INTEGER NOT NULL, user_id INTEGER NOT NULL, user_ip CHAR(15) NOT NULL, date SCORE_DATETIME NOT NULL, x1 INTEGER NOT NULL, y1 INTEGER NOT NULL, height INTEGER NOT NULL, width INTEGER NOT NULL, note TEXT NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE, FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE "); $database->execute("CREATE INDEX notes_image_id_idx ON notes(image_id)", array()); $database->create_table("note_request", " id SCORE_AIPK, image_id INTEGER NOT NULL, user_id INTEGER NOT NULL, date SCORE_DATETIME NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE, FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE "); $database->execute("CREATE INDEX note_request_image_id_idx ON note_request(image_id)", array()); $database->create_table("note_histories", " id SCORE_AIPK, note_enable INTEGER NOT NULL, note_id INTEGER NOT NULL, review_id INTEGER NOT NULL, image_id INTEGER NOT NULL, user_id INTEGER NOT NULL, user_ip CHAR(15) NOT NULL, date SCORE_DATETIME NOT NULL, x1 INTEGER NOT NULL, y1 INTEGER NOT NULL, height INTEGER NOT NULL, width INTEGER NOT NULL, note TEXT NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE, FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE "); $database->execute("CREATE INDEX note_histories_image_id_idx ON note_histories(image_id)", array()); $config->set_int("notesNotesPerPage", 20); $config->set_int("notesRequestsPerPage", 20); $config->set_int("notesHistoriesPerPage", 20); $config->set_int("ext_notes_version", 1); log_info("notes", "extension installed"); } } public function onPageRequest(PageRequestEvent $event) { global $page, $user; if($event->page_matches("note")) { switch($event->get_arg(0)) { case "list": //index $this->get_notes_list($event); // This should show images like post/list but i don't know how do that. break; case "requests": // The same as post/list but only for note_request table. $this->get_notes_requests($event); // This should show images like post/list but i don't know how do that. break; case "search": if(!$user->is_anonymous()) $this->theme->search_notes_page($page); break; case "updated": //Thinking how to build this function. $this->get_histories($event); break; case "history": //Thinking how to build this function. $this->get_history($event); break; case "revert": $noteID = $event->get_arg(1); $reviewID = $event->get_arg(2); if(!$user->is_anonymous()){ $this->revert_history($noteID, $reviewID); } $page->set_mode("redirect"); $page->set_redirect(make_link("note/updated")); break; case "add_note": if(!$user->is_anonymous()) $this->add_new_note(); $page->set_mode("redirect"); $page->set_redirect(make_link("post/view/".$_POST["image_id"])); break; case "add_request": if(!$user->is_anonymous()) $this->add_note_request(); $page->set_mode("redirect"); $page->set_redirect(make_link("post/view/".$_POST["image_id"])); break; case "nuke_notes": if($user->is_admin()) $this->nuke_notes(); $page->set_mode("redirect"); $page->set_redirect(make_link("post/view/".$_POST["image_id"])); break; case "nuke_requests": if($user->is_admin()) $this->nuke_requests(); $page->set_mode("redirect"); $page->set_redirect(make_link("post/view/".$_POST["image_id"])); break; case "edit_note": if (!$user->is_anonymous()) { $this->update_note(); $page->set_mode("redirect"); $page->set_redirect(make_link("post/view/" . $_POST["image_id"])); } break; case "delete_note": if ($user->is_admin()) { $this->delete_note(); $page->set_mode("redirect"); $page->set_redirect(make_link("post/view/".$_POST["image_id"])); } break; default: $page->set_mode("redirect"); $page->set_redirect(make_link("note/list")); break; } } } /* * HERE WE LOAD THE NOTES IN THE IMAGE */ public function onDisplayingImage(DisplayingImageEvent $event) { global $page, $user; //display form on image event $notes = $this->get_notes($event->image->id); $this->theme->display_note_system($page, $event->image->id, $notes, $user->is_admin()); } /* * HERE WE ADD THE BUTTONS ON SIDEBAR */ public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { global $user; if(!$user->is_anonymous()) { $event->add_part($this->theme->note_button($event->image->id)); $event->add_part($this->theme->request_button($event->image->id)); if($user->is_admin()) { $event->add_part($this->theme->nuke_notes_button($event->image->id)); $event->add_part($this->theme->nuke_requests_button($event->image->id)); } } } /* * HERE WE ADD QUERYLETS TO ADD SEARCH SYSTEM */ public function onSearchTermParse(SearchTermParseEvent $event) { $matches = array(); if(preg_match("/^note[=|:](.*)$/i", $event->term, $matches)) { $notes = int_escape($matches[1]); $event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM notes WHERE note = $notes)")); } else if(preg_match("/^notes([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)%/i", $event->term, $matches)) { $cmp = ltrim($matches[1], ":") ?: "="; $notes = $matches[2]; $event->add_querylet(new Querylet("images.id IN (SELECT id FROM images WHERE notes $cmp $notes)")); } else if(preg_match("/^notes_by[=|:](.*)$/i", $event->term, $matches)) { $user = User::by_name($matches[1]); if(!is_null($user)) { $user_id = $user->id; } else { $user_id = -1; } $event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM notes WHERE user_id = $user_id)")); } else if(preg_match("/^notes_by_userno[=|:](\d+)$/i", $event->term, $matches)) { $user_id = int_escape($matches[1]); $event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM notes WHERE user_id = $user_id)")); } } /** * HERE WE GET ALL NOTES FOR DISPLAYED IMAGE. * * @param int $imageID * @return array */ private function get_notes($imageID) { global $database; return $database->get_all( "SELECT * ". "FROM notes ". "WHERE enable = ? AND image_id = ? ". "ORDER BY date ASC", array('1', $imageID)); } /* * HERE WE ADD A NOTE TO DATABASE */ private function add_new_note() { global $database, $user; $imageID = int_escape($_POST["image_id"]); $user_id = $user->id; $noteX1 = int_escape($_POST["note_x1"]); $noteY1 = int_escape($_POST["note_y1"]); $noteHeight = int_escape($_POST["note_height"]); $noteWidth = int_escape($_POST["note_width"]); $noteText = html_escape($_POST["note_text"]); $database->execute(" INSERT INTO notes (enable, image_id, user_id, user_ip, date, x1, y1, height, width, note) VALUES (?, ?, ?, ?, now(), ?, ?, ?, ?, ?)", array(1, $imageID, $user_id, $_SERVER['REMOTE_ADDR'], $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText)); $noteID = $database->get_last_insert_id('notes_id_seq'); log_info("notes", "Note added {$noteID} by {$user->name}"); $database->execute("UPDATE images SET notes=(SELECT COUNT(*) FROM notes WHERE image_id=?) WHERE id=?", array($imageID, $imageID)); $this->add_history(1, $noteID, $imageID, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText); } /* * HERE WE ADD A REQUEST TO DATABASE */ private function add_note_request() { global $database, $user; $image_id = int_escape($_POST["image_id"]); $user_id = $user->id; $database->execute(" INSERT INTO note_request (image_id, user_id, date) VALUES (?, ?, now())", array($image_id, $user_id)); $resultID = $database->get_last_insert_id('note_request_id_seq'); log_info("notes", "Note requested {$resultID} by {$user->name}"); } /* * HERE WE EDIT THE NOTE */ private function update_note() { global $database; $note = array( "noteX1" => int_escape($_POST["note_x1"]), "noteY1" => int_escape($_POST["note_y1"]), "noteHeight" => int_escape($_POST["note_height"]), "noteWidth" => int_escape($_POST["note_width"]), "noteText" => sql_escape(html_escape($_POST["note_text"])), "imageID" => int_escape($_POST["image_id"]), "noteID" => int_escape($_POST["note_id"]) ); // validate parameters if (array_search(NULL, $note)|| strlen($note['noteText']) == 0) { return; } $database->execute("UPDATE notes ". "SET x1 = ?, ". "y1 = ?, ". "height = ?, ". "width = ?,". "note = ? ". "WHERE image_id = ? AND id = ?", array_values($note)); $this->add_history(1, $note['noteID'], $note['imageID'], $note['noteX1'], $note['noteY1'], $note['noteHeight'], $note['noteWidth'], $note['noteText']); } /* * HERE WE DELETE THE NOTE */ private function delete_note() { global $user, $database; $imageID = int_escape($_POST["image_id"]); $noteID = int_escape($_POST["note_id"]); // validate parameters if(is_null($imageID) || !is_numeric($imageID) || is_null($noteID) || !is_numeric($noteID)) { return; } $database->execute("UPDATE notes ". "SET enable = ? ". "WHERE image_id = ? AND id = ?", array(0, $imageID, $noteID)); log_info("notes", "Note deleted {$noteID} by {$user->name}"); } /* * HERE WE DELETE ALL NOTES FROM IMAGE */ private function nuke_notes() { global $database, $user; $image_id = int_escape($_POST["image_id"]); $database->execute("DELETE FROM notes WHERE image_id = ?", array($image_id)); log_info("notes", "Notes deleted from {$image_id} by {$user->name}"); } /* * HERE WE DELETE ALL REQUESTS FOR IMAGE */ private function nuke_requests() { global $database, $user; $image_id = int_escape($_POST["image_id"]); $database->execute("DELETE FROM note_request WHERE image_id = ?", array($image_id)); log_info("notes", "Requests deleted from {$image_id} by {$user->name}"); } /** * HERE WE ALL IMAGES THAT HAVE NOTES * @param PageRequestEvent $event */ private function get_notes_list(PageRequestEvent $event) { global $database, $config; $pageNumber = $event->get_arg(1); if(is_null($pageNumber) || !is_numeric($pageNumber) || $pageNumber <= 0) { $pageNumber = 0; } else { $pageNumber--; } $notesPerPage = $config->get_int('notesNotesPerPage'); //$result = $database->get_all("SELECT * FROM pool_images WHERE pool_id=?", array($poolID)); $result = $database->execute("SELECT DISTINCT image_id". "FROM notes ". "WHERE enable = ? ". "ORDER BY date DESC LIMIT ?, ?", array(1, $pageNumber * $notesPerPage, $notesPerPage)); $totalPages = ceil($database->get_one("SELECT COUNT(DISTINCT image_id) FROM notes") / $notesPerPage); $images = array(); while($row = $result->fetch()) { $images[] = array(Image::by_id($row["image_id"])); } $this->theme->display_note_list($images, $pageNumber + 1, $totalPages); } /** * HERE WE GET ALL NOTE REQUESTS * @param PageRequestEvent $event */ private function get_notes_requests(PageRequestEvent $event) { global $config, $database; $pageNumber = $event->get_arg(1); if(is_null($pageNumber) || !is_numeric($pageNumber) || $pageNumber <= 0) { $pageNumber = 0; } else { $pageNumber--; } $requestsPerPage = $config->get_int('notesRequestsPerPage'); //$result = $database->get_all("SELECT * FROM pool_images WHERE pool_id=?", array($poolID)); $result = $database->execute(" SELECT DISTINCT image_id FROM note_request ORDER BY date DESC LIMIT ?, ?", array($pageNumber * $requestsPerPage, $requestsPerPage)); $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_request") / $requestsPerPage); $images = array(); while($row = $result->fetch()) { $images[] = array(Image::by_id($row["image_id"])); } $this->theme->display_note_requests($images, $pageNumber + 1, $totalPages); } /* * HERE WE ADD HISTORY TO TRACK THE CHANGES OF THE NOTES FOR THE IMAGES. */ private function add_history($noteEnable, $noteID, $imageID, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText){ global $user, $database; $reviewID = $database->get_one("SELECT COUNT(*) FROM note_histories WHERE note_id = ?", array($noteID)); $reviewID = $reviewID + 1; $database->execute(" INSERT INTO note_histories (note_enable, note_id, review_id, image_id, user_id, user_ip, date, x1, y1, height, width, note) VALUES (?, ?, ?, ?, ?, ?, now(), ?, ?, ?, ?, ?)", array($noteEnable, $noteID, $reviewID, $imageID, $user->id, $_SERVER['REMOTE_ADDR'], $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText)); } /** * HERE WE GET ALL HISTORIES. * @param PageRequestEvent $event */ private function get_histories(PageRequestEvent $event){ global $config, $database; $pageNumber = $event->get_arg(1); if (is_null($pageNumber) || !is_numeric($pageNumber) || $pageNumber <= 0) { $pageNumber = 0; } else { $pageNumber--; } $historiesPerPage = $config->get_int('notesHistoriesPerPage'); //ORDER BY IMAGE & DATE $histories = $database->get_all("SELECT h.note_id, h.review_id, h.image_id, h.date, h.note, u.name AS user_name ". "FROM note_histories AS h ". "INNER JOIN users AS u ". "ON u.id = h.user_id ". "ORDER BY date DESC LIMIT ?, ?", array($pageNumber * $historiesPerPage, $historiesPerPage)); $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_histories") / $historiesPerPage); $this->theme->display_histories($histories, $pageNumber + 1, $totalPages); } /** * HERE WE THE HISTORY FOR A SPECIFIC NOTE. * @param PageRequestEvent $event */ private function get_history(PageRequestEvent $event){ global $config, $database; $noteID = $event->get_arg(1); $pageNumber = $event->get_arg(2); if (is_null($pageNumber) || !is_numeric($pageNumber) || $pageNumber <= 0) { $pageNumber = 0; } else { $pageNumber--; } $historiesPerPage = $config->get_int('notesHistoriesPerPage'); $histories = $database->get_all("SELECT h.note_id, h.review_id, h.image_id, h.date, h.note, u.name AS user_name ". "FROM note_histories AS h ". "INNER JOIN users AS u ". "ON u.id = h.user_id ". "WHERE note_id = ? ". "ORDER BY date DESC LIMIT ?, ?", array($noteID, $pageNumber * $historiesPerPage, $historiesPerPage)); $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_histories WHERE note_id = ?", array($noteID)) / $historiesPerPage); $this->theme->display_history($histories, $pageNumber + 1, $totalPages); } /** * HERE GO BACK IN HISTORY AND SET THE OLD NOTE. IF WAS REMOVED WE RE-ADD IT. * @param int $noteID * @param int $reviewID */ private function revert_history($noteID, $reviewID){ global $database; $history = $database->get_row("SELECT * FROM note_histories WHERE note_id = ? AND review_id = ?", array($noteID, $reviewID)); $noteEnable = $history['note_enable']; $noteID = $history['note_id']; $imageID = $history['image_id']; $noteX1 = $history['x1']; $noteY1 = $history['y1']; $noteHeight = $history['height']; $noteWidth = $history['width']; $noteText = $history['note']; $database->execute("UPDATE notes ". "SET enable = ?, x1 = ?, y1 = ?, height = ?, width = ?, note = ? ". "WHERE image_id = ? AND id = ?", array(1, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText, $imageID, $noteID)); $this->add_history($noteEnable, $noteID, $imageID, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText); } }