This repository has been archived on 2024-09-05. You can view files and clone it, but cannot push or open issues or pull requests.
shimmie2/ext/notes/main.php
Matthew Barbour a18589ee0a Help extension
Provides foundation for help pages that are generated from loaded extensions, starting with comprehensive search documentation. Addresses #522
2019-08-05 09:03:49 -05:00

574 lines
20 KiB
PHP

<?php
/**
* Name: [Beta] Notes
* Author: Sein Kraft <mail@seinkraft.info>
* 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)", []);
$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)", []);
$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)", []);
$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(PageMode::REDIRECT);
$page->set_redirect(make_link("note/updated"));
break;
case "add_note":
if (!$user->is_anonymous()) {
$this->add_new_note();
}
$page->set_mode(PageMode::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(PageMode::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(PageMode::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(PageMode::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(PageMode::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(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$_POST["image_id"]));
}
break;
default:
$page->set_mode(PageMode::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 = [];
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)"));
} elseif (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)"));
} elseif (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)"));
} elseif (preg_match("/^(notes_by_userno|notes_by_user_id)[=|:](\d+)$/i", $event->term, $matches)) {
$user_id = int_escape($matches[2]);
$event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM notes WHERE user_id = $user_id)"));
}
}
public function onHelpPageBuilding(HelpPageBuildingEvent $event)
{
if($event->key===HelpPages::SEARCH) {
$block = new Block();
$block->header = "Notes";
$block->body = $this->theme->get_help_html();
$event->add_block($block);
}
}
/**
* HERE WE GET ALL NOTES FOR DISPLAYED IMAGE.
*/
private function get_notes(int $imageID): array
{
global $database;
return $database->get_all(
"SELECT * ".
"FROM notes ".
"WHERE enable = ? AND image_id = ? ".
"ORDER BY date ASC",
['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(), ?, ?, ?, ?, ?)",
[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=?", [$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())",
[$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 = [
"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 = ?", [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 = ?", [$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 = ?", [$image_id]);
log_info("notes", "Requests deleted from {$image_id} by {$user->name}");
}
/**
* HERE WE ALL IMAGES THAT HAVE NOTES
*/
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 ?, ?",
[1, $pageNumber * $notesPerPage, $notesPerPage]
);
$totalPages = ceil($database->get_one("SELECT COUNT(DISTINCT image_id) FROM notes") / $notesPerPage);
$images = [];
while ($row = $result->fetch()) {
$images[] = [Image::by_id($row["image_id"])];
}
$this->theme->display_note_list($images, $pageNumber + 1, $totalPages);
}
/**
* HERE WE GET ALL NOTE REQUESTS
*/
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 ?, ?",
[$pageNumber * $requestsPerPage, $requestsPerPage]
);
$totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_request") / $requestsPerPage);
$images = [];
while ($row = $result->fetch()) {
$images[] = [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 = ?", [$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(), ?, ?, ?, ?, ?)",
[$noteEnable, $noteID, $reviewID, $imageID, $user->id, $_SERVER['REMOTE_ADDR'], $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText]
);
}
/**
* HERE WE GET ALL HISTORIES.
*/
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 ?, ?",
[$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.
*/
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 ?, ?",
[$noteID, $pageNumber * $historiesPerPage, $historiesPerPage]
);
$totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_histories WHERE note_id = ?", [$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.
*/
private function revert_history(int $noteID, int $reviewID)
{
global $database;
$history = $database->get_row("SELECT * FROM note_histories WHERE note_id = ? AND review_id = ?", [$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 = ?",
[1, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText, $imageID, $noteID]
);
$this->add_history($noteEnable, $noteID, $imageID, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText);
}
}