[core] merge method-check and permission-check into page_matches()

This commit is contained in:
Shish 2024-02-10 23:03:14 +00:00
parent 5735320a95
commit cc9de6b4b2
61 changed files with 1472 additions and 1799 deletions

View file

@ -37,15 +37,6 @@ class BaseThemelet
$page->add_block(new Block("Error", $message));
}
/**
* A specific, common error message
*/
public function display_permission_denied(): void
{
$this->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
/**
* Generic thumbnail code; returns HTML rather than adding
* a block since thumbs tend to go inside blocks...

View file

@ -59,6 +59,7 @@ class PageRequestEvent extends Event
public array $args;
public int $arg_count;
public int $part_count;
public bool $is_authed;
/**
* @param string $method The HTTP method used to make the request
@ -68,6 +69,7 @@ class PageRequestEvent extends Event
*/
public function __construct(string $method, string $path, array $get, array $post)
{
global $user;
parent::__construct();
global $config;
@ -81,6 +83,7 @@ class PageRequestEvent extends Event
$this->path = $path;
$this->GET = $get;
$this->POST = $post;
$this->is_authed = $user->check_auth_token();
// break the path into parts
$args = explode('/', $path);
@ -163,28 +166,40 @@ class PageRequestEvent extends Event
*
* If it matches, store the remaining path elements in $args
*/
public function page_matches(string $name): bool
public function page_matches(string $name, ?string $method = null, ?bool $authed = null, ?string $permission = null): bool
{
$parts = explode("/", $name);
$this->part_count = count($parts);
global $user;
if ($this->part_count > $this->arg_count) {
assert($method === null || in_array($method, ["GET", "POST", "OPTIONS"]));
$authed = $authed ?? $method == "POST";
// method check is fast so do that first
if($method !== null && $this->method !== $method) {
return false;
}
// check if the path matches
$parts = explode("/", $name);
$this->part_count = count($parts);
if ($this->part_count > $this->arg_count) {
return false;
}
for ($i = 0; $i < $this->part_count; $i++) {
if ($parts[$i] != $this->args[$i]) {
return false;
}
}
return true;
}
// if we matched the method and the path, but the page requires
// authentication and the user is not authenticated, then complain
if($authed && $this->is_authed === false) {
throw new PermissionDeniedException("Permission Denied");
}
if($permission !== null && !$user->can($permission)) {
throw new PermissionDeniedException("Permission Denied");
}
public function authed_page_matches(string $name): bool
{
global $user;
return $this->page_matches($name) && $user->check_auth_token();
return true;
}
/**

View file

@ -88,7 +88,7 @@ abstract class Permissions
public const BULK_EDIT_VOTE = "bulk_edit_vote";
public const EDIT_OTHER_VOTE = "edit_other_vote";
public const VIEW_SYSINTO = "view_sysinfo";
public const VIEW_SYSINFO = "view_sysinfo";
public const HELLBANNED = "hellbanned";
public const VIEW_HELLBANNED = "view_hellbanned";

View file

@ -188,7 +188,7 @@ new UserClass("admin", "base", [
Permissions::BULK_EDIT_VOTE => true,
Permissions::EDIT_OTHER_VOTE => true,
Permissions::CREATE_VOTE => true,
Permissions::VIEW_SYSINTO => true,
Permissions::VIEW_SYSINFO => true,
Permissions::HELLBANNED => false,
Permissions::VIEW_HELLBANNED => true,

View file

@ -49,29 +49,22 @@ class AdminPage extends Extension
{
global $database, $page, $user;
if ($event->page_matches("admin")) {
if (!$user->can(Permissions::MANAGE_ADMINTOOLS)) {
$this->theme->display_permission_denied();
if ($event->page_matches("admin", permission: Permissions::MANAGE_ADMINTOOLS)) {
if ($event->count_args() == 0) {
send_event(new AdminBuildingEvent($page));
} else {
if ($event->count_args() == 0) {
send_event(new AdminBuildingEvent($page));
} else {
$action = $event->get_arg(0);
$aae = new AdminActionEvent($action, $event->POST);
$action = $event->get_arg(0);
$aae = new AdminActionEvent($action, $event->POST);
if ($user->check_auth_token()) {
log_info("admin", "Util: $action");
shm_set_timeout(null);
$database->set_timeout(null);
send_event($aae);
} else {
throw new SCoreException("Invalid CSRF token");
}
$user->ensure_authed();
log_info("admin", "Util: $action");
shm_set_timeout(null);
$database->set_timeout(null);
send_event($aae);
if ($aae->redirect) {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin"));
}
if ($aae->redirect) {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin"));
}
}
}

View file

@ -9,14 +9,14 @@ class AdminPageTest extends ShimmiePHPUnitTestCase
public function testAuth(): void
{
send_event(new UserLoginEvent(User::by_name(self::$anon_name)));
$page = $this->get_page('admin');
$this->assertEquals(403, $page->code);
$this->assertEquals("Permission Denied", $page->title);
$this->assertException(PermissionDeniedException::class, function () {
$this->get_page('admin');
});
send_event(new UserLoginEvent(User::by_name(self::$user_name)));
$page = $this->get_page('admin');
$this->assertEquals(403, $page->code);
$this->assertEquals("Permission Denied", $page->title);
$this->assertException(PermissionDeniedException::class, function () {
$this->get_page('admin');
});
send_event(new UserLoginEvent(User::by_name(self::$admin_name)));
$page = $this->get_page('admin');

View file

@ -66,27 +66,23 @@ class AliasEditor extends Extension
global $config, $database, $page, $user;
if ($event->page_matches("alias")) {
if ($event->get_arg(0) == "add") {
if ($user->can(Permissions::MANAGE_ALIAS_LIST)) {
$user->ensure_authed();
$input = validate_input(["c_oldtag" => "string", "c_newtag" => "string"]);
try {
send_event(new AddAliasEvent($input['c_oldtag'], $input['c_newtag']));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("alias/list"));
} catch (AddAliasException $ex) {
$this->theme->display_error(500, "Error adding alias", $ex->getMessage());
}
}
} elseif ($event->get_arg(0) == "remove") {
if ($user->can(Permissions::MANAGE_ALIAS_LIST)) {
$user->ensure_authed();
$input = validate_input(["d_oldtag" => "string"]);
send_event(new DeleteAliasEvent($input['d_oldtag']));
if ($event->page_matches("alias/add", method: "POST", permission: Permissions::MANAGE_ALIAS_LIST)) {
$input = validate_input(["c_oldtag" => "string", "c_newtag" => "string"]);
try {
send_event(new AddAliasEvent($input['c_oldtag'], $input['c_newtag']));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("alias/list"));
} catch (AddAliasException $ex) {
$this->theme->display_error(500, "Error adding alias", $ex->getMessage());
}
} elseif ($event->get_arg(0) == "list") {
}
if ($event->page_matches("alias/remove", method: "POST", permission: Permissions::MANAGE_ALIAS_LIST)) {
$input = validate_input(["d_oldtag" => "string"]);
send_event(new DeleteAliasEvent($input['d_oldtag']));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("alias/list"));
}
if ($event->page_matches("alias/list")) {
$t = new AliasTable($database->raw_db());
$t->token = $user->get_auth_token();
$t->inputs = $event->GET;
@ -96,25 +92,23 @@ class AliasEditor extends Extension
$t->delete_url = make_link("alias/remove");
}
$this->theme->display_aliases($t->table($t->query()), $t->paginator());
} elseif ($event->get_arg(0) == "export") {
}
if ($event->page_matches("alias/export")) {
$page->set_mode(PageMode::DATA);
$page->set_mime(MimeType::CSV);
$page->set_filename("aliases.csv");
$page->set_data($this->get_alias_csv($database));
} elseif ($event->get_arg(0) == "import") {
if ($user->can(Permissions::MANAGE_ALIAS_LIST)) {
if (count($_FILES) > 0) {
$tmp = $_FILES['alias_file']['tmp_name'];
$contents = file_get_contents_ex($tmp);
$this->add_alias_csv($contents);
log_info("alias_editor", "Imported aliases from file", "Imported aliases"); # FIXME: how many?
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("alias/list"));
} else {
$this->theme->display_error(400, "No File Specified", "You have to upload a file");
}
}
if ($event->page_matches("alias/import", method: "POST", permission: Permissions::MANAGE_ALIAS_LIST)) {
if (count($_FILES) > 0) {
$tmp = $_FILES['alias_file']['tmp_name'];
$contents = file_get_contents_ex($tmp);
$this->add_alias_csv($contents);
log_info("alias_editor", "Imported aliases from file", "Imported aliases"); # FIXME: how many?
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("alias/list"));
} else {
$this->theme->display_error(401, "Admins Only", "Only admins can edit the alias list");
$this->theme->display_error(400, "No File Specified", "You have to upload a file");
}
}
}

View file

@ -40,16 +40,14 @@ class Approval extends Extension
{
global $page, $user;
if ($event->page_matches("approve_image") && $user->can(Permissions::APPROVE_IMAGE)) {
// Try to get the image ID
if ($event->page_matches("approve_image", method: "POST", permission: Permissions::APPROVE_IMAGE)) {
$image_id = int_escape(null_throws($event->get_arg(0)));
self::approve_image($image_id);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/" . $image_id));
}
if ($event->page_matches("disapprove_image") && $user->can(Permissions::APPROVE_IMAGE)) {
// Try to get the image ID
if ($event->page_matches("disapprove_image", method: "POST", permission: Permissions::APPROVE_IMAGE)) {
$image_id = int_escape(null_throws($event->get_arg(0)));
self::disapprove_image($image_id);
$page->set_mode(PageMode::REDIRECT);

View file

@ -169,262 +169,182 @@ class Artists extends Extension
{
global $page, $user;
if ($event->page_matches("artist")) {
switch ($event->get_arg(0)) {
//*************ARTIST SECTION**************
case "list":
{
$this->get_listing($event);
$this->theme->sidebar_options("neutral");
break;
}
case "new":
{
if (!$user->is_anonymous()) {
$this->theme->new_artist_composer();
} else {
$this->theme->display_error(401, "Error", "You must be registered and logged in to create a new artist.");
}
break;
}
case "new_artist":
{
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/new"));
break;
}
case "create":
{
if (!$user->is_anonymous()) {
$newArtistID = $this->add_artist();
if ($newArtistID == -1) {
$this->theme->display_error(400, "Error", "Error when entering artist data.");
} else {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$newArtistID));
}
} else {
$this->theme->display_error(401, "Error", "You must be registered and logged in to create a new artist.");
}
break;
}
case "view":
{
$artistID = int_escape($event->get_arg(1));
$artist = $this->get_artist($artistID);
$aliases = $this->get_alias($artist['id']);
$members = $this->get_members($artist['id']);
$urls = $this->get_urls($artist['id']);
$userIsLogged = !$user->is_anonymous();
$userIsAdmin = $user->can(Permissions::ARTISTS_ADMIN);
$images = Search::find_images(limit: 4, tags: Tag::explode($artist['name']));
$this->theme->show_artist($artist, $aliases, $members, $urls, $images, $userIsLogged, $userIsAdmin);
/*
if ($userIsLogged) {
$this->theme->show_new_alias_composer($artistID);
$this->theme->show_new_member_composer($artistID);
$this->theme->show_new_url_composer($artistID);
}
*/
$this->theme->sidebar_options("editor", $artistID, $userIsAdmin);
break;
}
case "edit":
{
$artistID = int_escape($event->get_arg(1));
$artist = $this->get_artist($artistID);
$aliases = $this->get_alias($artistID);
$members = $this->get_members($artistID);
$urls = $this->get_urls($artistID);
if (!$user->is_anonymous()) {
$this->theme->show_artist_editor($artist, $aliases, $members, $urls);
$userIsAdmin = $user->can(Permissions::ARTISTS_ADMIN);
$this->theme->sidebar_options("editor", $artistID, $userIsAdmin);
} else {
$this->theme->display_error(401, "Error", "You must be registered and logged in to edit an artist.");
}
break;
}
case "edit_artist":
{
$artistID = int_escape($event->req_POST('artist_id'));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/edit/".$artistID));
break;
}
case "edited":
{
$artistID = int_escape($event->get_POST('id'));
$this->update_artist();
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID));
break;
}
case "nuke_artist":
{
$artistID = int_escape($event->req_POST('artist_id'));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/nuke/".$artistID));
break;
}
case "nuke":
{
$artistID = int_escape($event->get_arg(1));
$this->delete_artist($artistID); // this will delete the artist, its alias, its urls and its members
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/list"));
break;
}
case "add_alias":
{
$artistID = int_escape($event->req_POST('artist_id'));
$this->theme->show_new_alias_composer($artistID);
break;
}
case "add_member":
{
$artistID = int_escape($event->req_POST('artist_id'));
$this->theme->show_new_member_composer($artistID);
break;
}
case "add_url":
{
$artistID = int_escape($event->req_POST('artist_id'));
$this->theme->show_new_url_composer($artistID);
break;
}
//***********ALIAS SECTION ***********************
case "alias":
{
switch ($event->get_arg(1)) {
case "add":
{
$artistID = int_escape($event->req_POST('artist_id'));
$this->add_alias();
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID));
break;
}
case "delete":
{
$aliasID = int_escape($event->get_arg(2));
$artistID = $this->get_artistID_by_aliasID($aliasID);
$this->delete_alias($aliasID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID));
break;
}
case "edit":
{
$aliasID = int_escape($event->get_arg(2));
$alias = $this->get_alias_by_id($aliasID);
$this->theme->show_alias_editor($alias);
break;
}
case "edited":
{
$this->update_alias();
$aliasID = int_escape($event->req_POST('aliasID'));
$artistID = $this->get_artistID_by_aliasID($aliasID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID));
break;
}
}
break; // case: alias
}
//**************** URLS SECTION **********************
case "url":
{
switch ($event->get_arg(1)) {
case "add":
{
$artistID = int_escape($event->req_POST('artist_id'));
$this->add_urls();
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID));
break;
}
case "delete":
{
$urlID = int_escape($event->get_arg(2));
$artistID = $this->get_artistID_by_urlID($urlID);
$this->delete_url($urlID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID));
break;
}
case "edit":
{
$urlID = int_escape($event->get_arg(2));
$url = $this->get_url_by_id($urlID);
$this->theme->show_url_editor($url);
break;
}
case "edited":
{
$this->update_url();
$urlID = int_escape($event->req_POST('urlID'));
$artistID = $this->get_artistID_by_urlID($urlID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID));
break;
}
}
break; // case: urls
}
//******************* MEMBERS SECTION *********************
case "member":
{
switch ($event->get_arg(1)) {
case "add":
{
$artistID = int_escape($event->req_POST('artist_id'));
$this->add_members();
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID));
break;
}
case "delete":
{
$memberID = int_escape($event->get_arg(2));
$artistID = $this->get_artistID_by_memberID($memberID);
$this->delete_member($memberID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID));
break;
}
case "edit":
{
$memberID = int_escape($event->get_arg(2));
$member = $this->get_member_by_id($memberID);
$this->theme->show_member_editor($member);
break;
}
case "edited":
{
$this->update_member();
$memberID = int_escape($event->req_POST('memberID'));
$artistID = $this->get_artistID_by_memberID($memberID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID));
break;
}
}
break; //case: members
}
if ($event->page_matches("artist/list")) {
$this->get_listing(clamp(int_escape($event->get_arg(0)), 1, null) - 1);
$this->theme->sidebar_options("neutral");
}
if ($event->page_matches("artist/new")) {
if (!$user->is_anonymous()) {
$this->theme->new_artist_composer();
} else {
$this->theme->display_error(401, "Error", "You must be registered and logged in to create a new artist.");
}
}
if ($event->page_matches("artist/new_artist")) {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/new"));
}
if ($event->page_matches("artist/create")) {
if (!$user->is_anonymous()) {
$newArtistID = $this->add_artist();
if ($newArtistID == -1) {
$this->theme->display_error(400, "Error", "Error when entering artist data.");
} else {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $newArtistID));
}
} else {
$this->theme->display_error(401, "Error", "You must be registered and logged in to create a new artist.");
}
}
if ($event->page_matches("artist/view")) {
$artistID = int_escape($event->get_arg(0));
$artist = $this->get_artist($artistID);
$aliases = $this->get_alias($artist['id']);
$members = $this->get_members($artist['id']);
$urls = $this->get_urls($artist['id']);
$userIsLogged = !$user->is_anonymous();
$userIsAdmin = $user->can(Permissions::ARTISTS_ADMIN);
$images = Search::find_images(limit: 4, tags: Tag::explode($artist['name']));
$this->theme->show_artist($artist, $aliases, $members, $urls, $images, $userIsLogged, $userIsAdmin);
/*
if ($userIsLogged) {
$this->theme->show_new_alias_composer($artistID);
$this->theme->show_new_member_composer($artistID);
$this->theme->show_new_url_composer($artistID);
}
*/
$this->theme->sidebar_options("editor", $artistID, $userIsAdmin);
}
if ($event->page_matches("artist/edit")) {
$artistID = int_escape($event->get_arg(0));
$artist = $this->get_artist($artistID);
$aliases = $this->get_alias($artistID);
$members = $this->get_members($artistID);
$urls = $this->get_urls($artistID);
if (!$user->is_anonymous()) {
$this->theme->show_artist_editor($artist, $aliases, $members, $urls);
$userIsAdmin = $user->can(Permissions::ARTISTS_ADMIN);
$this->theme->sidebar_options("editor", $artistID, $userIsAdmin);
} else {
$this->theme->display_error(401, "Error", "You must be registered and logged in to edit an artist.");
}
}
if ($event->page_matches("artist/edit_artist")) {
$artistID = int_escape($event->req_POST('artist_id'));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/edit/" . $artistID));
}
if ($event->page_matches("artist/edited")) {
$artistID = int_escape($event->get_POST('id'));
$this->update_artist();
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $artistID));
}
if ($event->page_matches("artist/nuke_artist")) {
$artistID = int_escape($event->req_POST('artist_id'));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/nuke/" . $artistID));
}
if ($event->page_matches("artist/nuke")) {
$artistID = int_escape($event->get_arg(0));
$this->delete_artist($artistID); // this will delete the artist, its alias, its urls and its members
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/list"));
}
if ($event->page_matches("artist/add_alias")) {
$artistID = int_escape($event->req_POST('artist_id'));
$this->theme->show_new_alias_composer($artistID);
}
if ($event->page_matches("artist/add_member")) {
$artistID = int_escape($event->req_POST('artist_id'));
$this->theme->show_new_member_composer($artistID);
}
if ($event->page_matches("artist/add_url")) {
$artistID = int_escape($event->req_POST('artist_id'));
$this->theme->show_new_url_composer($artistID);
}
if ($event->page_matches("artist/alias/add")) {
$artistID = int_escape($event->req_POST('artist_id'));
$this->add_alias();
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $artistID));
}
if ($event->page_matches("artist/alias/delete")) {
$aliasID = int_escape($event->get_arg(0));
$artistID = $this->get_artistID_by_aliasID($aliasID);
$this->delete_alias($aliasID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $artistID));
}
if ($event->page_matches("artist/alias/edit")) {
$aliasID = int_escape($event->get_arg(0));
$alias = $this->get_alias_by_id($aliasID);
$this->theme->show_alias_editor($alias);
}
if ($event->page_matches("artist/alias/edited")) {
$this->update_alias();
$aliasID = int_escape($event->req_POST('aliasID'));
$artistID = $this->get_artistID_by_aliasID($aliasID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $artistID));
}
if ($event->page_matches("artist/url/add")) {
$artistID = int_escape($event->req_POST('artist_id'));
$this->add_urls();
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $artistID));
}
if ($event->page_matches("artist/url/delete")) {
$urlID = int_escape($event->get_arg(0));
$artistID = $this->get_artistID_by_urlID($urlID);
$this->delete_url($urlID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $artistID));
}
if ($event->page_matches("artist/url/edit")) {
$urlID = int_escape($event->get_arg(0));
$url = $this->get_url_by_id($urlID);
$this->theme->show_url_editor($url);
}
if ($event->page_matches("artist/url/edited")) {
$this->update_url();
$urlID = int_escape($event->req_POST('urlID'));
$artistID = $this->get_artistID_by_urlID($urlID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $artistID));
}
if ($event->page_matches("artist/member/add")) {
$artistID = int_escape($event->req_POST('artist_id'));
$this->add_members();
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $artistID));
}
if ($event->page_matches("artist/member/delete")) {
$memberID = int_escape($event->get_arg(0));
$artistID = $this->get_artistID_by_memberID($memberID);
$this->delete_member($memberID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $artistID));
}
if ($event->page_matches("artist/member/edit")) {
$memberID = int_escape($event->get_arg(0));
$member = $this->get_member_by_id($memberID);
$this->theme->show_member_editor($member);
}
if ($event->page_matches("artist/member/edited")) {
$this->update_member();
$memberID = int_escape($event->req_POST('memberID'));
$artistID = $this->get_artistID_by_memberID($memberID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/" . $artistID));
}
}
private function get_artistName_by_imageID(int $imageID): string
@ -468,37 +388,37 @@ class Artists extends Extension
private function get_artistID_by_url(string $url): int
{
global $database;
return (int)$database->get_one("SELECT artist_id FROM artist_urls WHERE url = :url", ['url' => $url]);
return (int) $database->get_one("SELECT artist_id FROM artist_urls WHERE url = :url", ['url' => $url]);
}
private function get_artistID_by_memberName(string $member): int
{
global $database;
return (int)$database->get_one("SELECT artist_id FROM artist_members WHERE name = :name", ['name' => $member]);
return (int) $database->get_one("SELECT artist_id FROM artist_members WHERE name = :name", ['name' => $member]);
}
private function get_artistName_by_artistID(int $artistID): string
{
global $database;
return (string)$database->get_one("SELECT name FROM artists WHERE id = :id", ['id' => $artistID]);
return (string) $database->get_one("SELECT name FROM artists WHERE id = :id", ['id' => $artistID]);
}
private function get_artistID_by_aliasID(int $aliasID): int
{
global $database;
return (int)$database->get_one("SELECT artist_id FROM artist_alias WHERE id = :id", ['id' => $aliasID]);
return (int) $database->get_one("SELECT artist_id FROM artist_alias WHERE id = :id", ['id' => $aliasID]);
}
private function get_artistID_by_memberID(int $memberID): int
{
global $database;
return (int)$database->get_one("SELECT artist_id FROM artist_members WHERE id = :id", ['id' => $memberID]);
return (int) $database->get_one("SELECT artist_id FROM artist_members WHERE id = :id", ['id' => $memberID]);
}
private function get_artistID_by_urlID(int $urlID): int
{
global $database;
return (int)$database->get_one("SELECT artist_id FROM artist_urls WHERE id = :id", ['id' => $urlID]);
return (int) $database->get_one("SELECT artist_id FROM artist_urls WHERE id = :id", ['id' => $urlID]);
}
private function delete_alias(int $aliasID): void
@ -818,7 +738,7 @@ class Artists extends Extension
);
$num = count($result);
for ($i = 0 ; $i < $num ; $i++) {
for ($i = 0; $i < $num; $i++) {
$result[$i]["name"] = stripslashes($result[$i]["name"]);
}
@ -837,7 +757,7 @@ class Artists extends Extension
);
$num = count($result);
for ($i = 0 ; $i < $num ; $i++) {
for ($i = 0; $i < $num; $i++) {
$result[$i]["url"] = stripslashes($result[$i]["url"]);
}
@ -847,7 +767,7 @@ class Artists extends Extension
private function get_artist_id(string $name): int
{
global $database;
return (int)$database->get_one(
return (int) $database->get_one(
"SELECT id FROM artists WHERE name = :name",
['name' => $name]
);
@ -857,7 +777,7 @@ class Artists extends Extension
{
global $database;
return (int)$database->get_one(
return (int) $database->get_one(
"SELECT artist_id FROM artist_alias WHERE alias = :alias",
['alias' => $alias]
);
@ -873,60 +793,59 @@ class Artists extends Extension
}
/*
* HERE WE GET THE LIST OF ALL ARTIST WITH PAGINATION
*/
private function get_listing(PageRequestEvent $event): void
* HERE WE GET THE LIST OF ALL ARTIST WITH PAGINATION
*/
private function get_listing(int $pageNumber): void
{
global $config, $database;
$pageNumber = clamp(int_escape($event->get_arg(1)), 1, null) - 1;
$artistsPerPage = $config->get_int("artistsPerPage");
$listing = $database->get_all(
"
(
SELECT a.id, a.user_id, a.name, u.name AS user_name, COALESCE(t.count, 0) AS posts
, 'artist' as type, a.id AS artist_id, a.name AS artist_name, a.updated
FROM artists AS a
INNER JOIN users AS u
ON a.user_id = u.id
LEFT OUTER JOIN tags AS t
ON a.name = t.tag
GROUP BY a.id, a.user_id, a.name, u.name
ORDER BY a.updated DESC
)
(
SELECT a.id, a.user_id, a.name, u.name AS user_name, COALESCE(t.count, 0) AS posts
, 'artist' as type, a.id AS artist_id, a.name AS artist_name, a.updated
FROM artists AS a
INNER JOIN users AS u
ON a.user_id = u.id
LEFT OUTER JOIN tags AS t
ON a.name = t.tag
GROUP BY a.id, a.user_id, a.name, u.name
ORDER BY a.updated DESC
)
UNION
UNION
(
SELECT aa.id, aa.user_id, aa.alias AS name, u.name AS user_name, COALESCE(t.count, 0) AS posts
, 'alias' as type, a.id AS artist_id, a.name AS artist_name, aa.updated
FROM artist_alias AS aa
INNER JOIN users AS u
ON aa.user_id = u.id
INNER JOIN artists AS a
ON aa.artist_id = a.id
LEFT OUTER JOIN tags AS t
ON aa.alias = t.tag
GROUP BY aa.id, a.user_id, aa.alias, u.name, a.id, a.name
ORDER BY aa.updated DESC
)
(
SELECT aa.id, aa.user_id, aa.alias AS name, u.name AS user_name, COALESCE(t.count, 0) AS posts
, 'alias' as type, a.id AS artist_id, a.name AS artist_name, aa.updated
FROM artist_alias AS aa
INNER JOIN users AS u
ON aa.user_id = u.id
INNER JOIN artists AS a
ON aa.artist_id = a.id
LEFT OUTER JOIN tags AS t
ON aa.alias = t.tag
GROUP BY aa.id, a.user_id, aa.alias, u.name, a.id, a.name
ORDER BY aa.updated DESC
)
UNION
UNION
(
SELECT m.id, m.user_id, m.name AS name, u.name AS user_name, COALESCE(t.count, 0) AS posts
, 'member' AS type, a.id AS artist_id, a.name AS artist_name, m.updated
FROM artist_members AS m
INNER JOIN users AS u
ON m.user_id = u.id
INNER JOIN artists AS a
ON m.artist_id = a.id
LEFT OUTER JOIN tags AS t
ON m.name = t.tag
GROUP BY m.id, m.user_id, m.name, u.name, a.id, a.name
ORDER BY m.updated DESC
)
(
SELECT m.id, m.user_id, m.name AS name, u.name AS user_name, COALESCE(t.count, 0) AS posts
, 'member' AS type, a.id AS artist_id, a.name AS artist_name, m.updated
FROM artist_members AS m
INNER JOIN users AS u
ON m.user_id = u.id
INNER JOIN artists AS a
ON m.artist_id = a.id
LEFT OUTER JOIN tags AS t
ON m.name = t.tag
GROUP BY m.id, m.user_id, m.name, u.name, a.id, a.name
ORDER BY m.updated DESC
)
ORDER BY updated DESC
LIMIT :offset, :limit
",
@ -938,7 +857,7 @@ class Artists extends Extension
$number_of_listings = count($listing);
for ($i = 0 ; $i < $number_of_listings ; $i++) {
for ($i = 0; $i < $number_of_listings; $i++) {
$listing[$i]["name"] = stripslashes($listing[$i]["name"]);
$listing[$i]["user_name"] = stripslashes($listing[$i]["user_name"]);
$listing[$i]["artist_name"] = stripslashes($listing[$i]["artist_name"]);
@ -953,14 +872,14 @@ class Artists extends Extension
ON a.id = aa.artist_id
");
$totalPages = (int)ceil($count / $artistsPerPage);
$totalPages = (int) ceil($count / $artistsPerPage);
$this->theme->list_artists($listing, $pageNumber + 1, $totalPages);
}
/*
* HERE WE ADD AN ALIAS
*/
* HERE WE ADD AN ALIAS
*/
private function add_urls(): void
{
global $user;
@ -1081,7 +1000,7 @@ class Artists extends Extension
", ['artist_id' => $artistID]);
$rc = count($result);
for ($i = 0 ; $i < $rc ; $i++) {
for ($i = 0; $i < $rc; $i++) {
$result[$i]["alias_name"] = stripslashes($result[$i]["alias_name"]);
}
return $result;

View file

@ -72,27 +72,23 @@ class AutoTagger extends Extension
global $config, $database, $page, $user;
if ($event->page_matches("auto_tag")) {
if ($event->get_arg(0) == "add") {
if ($user->can(Permissions::MANAGE_AUTO_TAG)) {
$user->ensure_authed();
$input = validate_input(["c_tag" => "string", "c_additional_tags" => "string"]);
try {
send_event(new AddAutoTagEvent($input['c_tag'], $input['c_additional_tags']));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("auto_tag/list"));
} catch (AddAutoTagException $ex) {
$this->theme->display_error(500, "Error adding auto-tag", $ex->getMessage());
}
}
} elseif ($event->get_arg(0) == "remove") {
if ($user->can(Permissions::MANAGE_AUTO_TAG)) {
$user->ensure_authed();
$input = validate_input(["d_tag" => "string"]);
send_event(new DeleteAutoTagEvent($input['d_tag']));
if ($event->page_matches("auto_tag/add", method: "POST", permission: Permissions::MANAGE_AUTO_TAG)) {
$input = validate_input(["c_tag" => "string", "c_additional_tags" => "string"]);
try {
send_event(new AddAutoTagEvent($input['c_tag'], $input['c_additional_tags']));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("auto_tag/list"));
} catch (AddAutoTagException $ex) {
$this->theme->display_error(500, "Error adding auto-tag", $ex->getMessage());
}
} elseif ($event->get_arg(0) == "list") {
}
if ($event->page_matches("auto_tag/remove", method: "POST", permission: Permissions::MANAGE_AUTO_TAG)) {
$input = validate_input(["d_tag" => "string"]);
send_event(new DeleteAutoTagEvent($input['d_tag']));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("auto_tag/list"));
}
if ($event->page_matches("auto_tag/list")) {
$t = new AutoTaggerTable($database->raw_db());
$t->token = $user->get_auth_token();
$t->inputs = $event->GET;
@ -102,25 +98,23 @@ class AutoTagger extends Extension
$t->delete_url = make_link("auto_tag/remove");
}
$this->theme->display_auto_tagtable($t->table($t->query()), $t->paginator());
} elseif ($event->get_arg(0) == "export") {
}
if ($event->page_matches("auto_tag/export")) {
$page->set_mode(PageMode::DATA);
$page->set_mime(MimeType::CSV);
$page->set_filename("auto_tag.csv");
$page->set_data($this->get_auto_tag_csv($database));
} elseif ($event->get_arg(0) == "import") {
if ($user->can(Permissions::MANAGE_AUTO_TAG)) {
if (count($_FILES) > 0) {
$tmp = $_FILES['auto_tag_file']['tmp_name'];
$contents = file_get_contents_ex($tmp);
$count = $this->add_auto_tag_csv($contents);
log_info(AutoTaggerInfo::KEY, "Imported $count auto-tag definitions from file from file", "Imported $count auto-tag definitions");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("auto_tag/list"));
} else {
$this->theme->display_error(400, "No File Specified", "You have to upload a file");
}
}
if ($event->page_matches("auto_tag/import", method: "POST", permission: Permissions::MANAGE_AUTO_TAG)) {
if (count($_FILES) > 0) {
$tmp = $_FILES['auto_tag_file']['tmp_name'];
$contents = file_get_contents_ex($tmp);
$count = $this->add_auto_tag_csv($contents);
log_info(AutoTaggerInfo::KEY, "Imported $count auto-tag definitions from file from file", "Imported $count auto-tag definitions");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("auto_tag/list"));
} else {
$this->theme->display_error(401, "Admins Only", "Only admins can edit the auto-tag list");
$this->theme->display_error(400, "No File Specified", "You have to upload a file");
}
}
}

View file

@ -26,13 +26,11 @@ class Biography extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $page, $user, $user_config;
if ($event->page_matches("biography")) {
if ($user->check_auth_token()) {
$user_config->set_string("biography", $event->get_POST('biography'));
$page->flash("Bio Updated");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
if ($event->page_matches("biography", method: "POST")) {
$user_config->set_string("biography", $event->get_POST('biography'));
$page->flash("Bio Updated");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
}
}

View file

@ -68,39 +68,36 @@ class Blocks extends Extension
}
}
if ($event->page_matches("blocks") && $user->can(Permissions::MANAGE_BLOCKS)) {
if ($event->get_arg(0) == "add") {
if ($user->check_auth_token()) {
$database->execute("
INSERT INTO blocks (pages, title, area, priority, content, userclass)
VALUES (:pages, :title, :area, :priority, :content, :userclass)
", ['pages' => $event->req_POST('pages'), 'title' => $event->req_POST('title'), 'area' => $event->req_POST('area'), 'priority' => (int)$event->req_POST('priority'), 'content' => $event->req_POST('content'), 'userclass' => $event->req_POST('userclass')]);
log_info("blocks", "Added Block #".($database->get_last_insert_id('blocks_id_seq'))." (".$event->req_POST('title').")");
$cache->delete("blocks");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blocks/list"));
}
if ($event->page_matches("blocks", permission: Permissions::MANAGE_BLOCKS)) {
if ($event->page_matches("blocks/add", method: "POST")) {
$database->execute("
INSERT INTO blocks (pages, title, area, priority, content, userclass)
VALUES (:pages, :title, :area, :priority, :content, :userclass)
", ['pages' => $event->req_POST('pages'), 'title' => $event->req_POST('title'), 'area' => $event->req_POST('area'), 'priority' => (int)$event->req_POST('priority'), 'content' => $event->req_POST('content'), 'userclass' => $event->req_POST('userclass')]);
log_info("blocks", "Added Block #".($database->get_last_insert_id('blocks_id_seq'))." (".$event->req_POST('title').")");
$cache->delete("blocks");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blocks/list"));
}
if ($event->get_arg(0) == "update") {
if ($user->check_auth_token()) {
if (!empty($event->req_POST('delete'))) {
$database->execute("
DELETE FROM blocks
WHERE id=:id
", ['id' => $event->req_POST('id')]);
log_info("blocks", "Deleted Block #".$event->req_POST('id'));
} else {
$database->execute("
UPDATE blocks SET pages=:pages, title=:title, area=:area, priority=:priority, content=:content, userclass=:userclass
WHERE id=:id
", ['pages' => $event->req_POST('pages'), 'title' => $event->req_POST('title'), 'area' => $event->req_POST('area'), 'priority' => (int)$event->req_POST('priority'), 'content' => $event->req_POST('content'), 'userclass' => $event->req_POST('userclass'), 'id' => $event->req_POST('id')]);
log_info("blocks", "Updated Block #".$event->req_POST('id')." (".$event->req_POST('title').")");
}
$cache->delete("blocks");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blocks/list"));
if ($event->page_matches("blocks/update", method: "POST")) {
if (!empty($event->req_POST('delete'))) {
$database->execute("
DELETE FROM blocks
WHERE id=:id
", ['id' => $event->req_POST('id')]);
log_info("blocks", "Deleted Block #".$event->req_POST('id'));
} else {
$database->execute("
UPDATE blocks SET pages=:pages, title=:title, area=:area, priority=:priority, content=:content, userclass=:userclass
WHERE id=:id
", ['pages' => $event->req_POST('pages'), 'title' => $event->req_POST('title'), 'area' => $event->req_POST('area'), 'priority' => (int)$event->req_POST('priority'), 'content' => $event->req_POST('content'), 'userclass' => $event->req_POST('userclass'), 'id' => $event->req_POST('id')]);
log_info("blocks", "Updated Block #".$event->req_POST('id')." (".$event->req_POST('title').")");
}
} elseif ($event->get_arg(0) == "list") {
$cache->delete("blocks");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blocks/list"));
}
if ($event->page_matches("blocks/list")) {
$this->theme->display_blocks($database->get_all("SELECT * FROM blocks ORDER BY area, priority"));
}
}

View file

@ -72,60 +72,32 @@ class Blotter extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $page, $database, $user;
if ($event->page_matches("blotter") && $event->count_args() > 0) {
switch ($event->get_arg(0)) {
case "editor":
/**
* Displays the blotter editor.
*/
if (!$user->can(Permissions::BLOTTER_ADMIN)) {
$this->theme->display_permission_denied();
} else {
$entries = $database->get_all("SELECT * FROM blotter ORDER BY id DESC");
$this->theme->display_editor($entries);
}
break;
case "add":
/**
* Adds an entry
*/
if (!$user->can(Permissions::BLOTTER_ADMIN) || !$user->check_auth_token()) {
$this->theme->display_permission_denied();
} else {
$entry_text = $event->req_POST('entry_text');
$important = !is_null($event->get_POST('important'));
// Now insert into db:
$database->execute(
"INSERT INTO blotter (entry_date, entry_text, important) VALUES (now(), :text, :important)",
["text" => $entry_text, "important" => $important]
);
log_info("blotter", "Added Message: $entry_text");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blotter/editor"));
}
break;
case "remove":
/**
* Removes an entry
*/
if (!$user->can(Permissions::BLOTTER_ADMIN) || !$user->check_auth_token()) {
$this->theme->display_permission_denied();
} else {
$id = int_escape($event->req_POST('id'));
$database->execute("DELETE FROM blotter WHERE id=:id", ["id" => $id]);
log_info("blotter", "Removed Entry #$id");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blotter/editor"));
}
break;
case "list":
/**
* Displays all blotter entries
*/
$entries = $database->get_all("SELECT * FROM blotter ORDER BY id DESC");
$this->theme->display_blotter_page($entries);
break;
}
if ($event->page_matches("blotter/editor", method: "GET", permission: Permissions::BLOTTER_ADMIN)) {
$entries = $database->get_all("SELECT * FROM blotter ORDER BY id DESC");
$this->theme->display_editor($entries);
}
if ($event->page_matches("blotter/add", method: "POST", permission: Permissions::BLOTTER_ADMIN)) {
$entry_text = $event->req_POST('entry_text');
$important = !is_null($event->get_POST('important'));
// Now insert into db:
$database->execute(
"INSERT INTO blotter (entry_date, entry_text, important) VALUES (now(), :text, :important)",
["text" => $entry_text, "important" => $important]
);
log_info("blotter", "Added Message: $entry_text");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blotter/editor"));
}
if ($event->page_matches("blotter/remove", method: "POST", permission: Permissions::BLOTTER_ADMIN)) {
$id = int_escape($event->req_POST('id'));
$database->execute("DELETE FROM blotter WHERE id=:id", ["id" => $id]);
log_info("blotter", "Removed Entry #$id");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blotter/editor"));
}
if ($event->page_matches("blotter/list", method: "GET")) {
$entries = $database->get_all("SELECT * FROM blotter ORDER BY id DESC");
$this->theme->display_blotter_page($entries);
}
/**
* Finally, display the blotter on whatever page we're viewing.
@ -137,7 +109,7 @@ class Blotter extends Extension
{
global $database, $config;
$limit = $config->get_int("blotter_recent", 5);
$sql = 'SELECT * FROM blotter ORDER BY id DESC LIMIT '.intval($limit);
$sql = 'SELECT * FROM blotter ORDER BY id DESC LIMIT ' . intval($limit);
$entries = $database->get_all($sql);
$this->theme->display_blotter($entries);
}

View file

@ -8,12 +8,15 @@ class BlotterTest extends ShimmiePHPUnitTestCase
{
public function testDenial(): void
{
$this->get_page("blotter/editor");
$this->assert_response(403);
$this->get_page("blotter/add");
$this->assert_response(403);
$this->get_page("blotter/remove");
$this->assert_response(403);
$this->assertException(PermissionDeniedException::class, function () {
$this->get_page("blotter/editor");
});
$this->assertException(PermissionDeniedException::class, function () {
$this->post_page("blotter/add");
});
$this->assertException(PermissionDeniedException::class, function () {
$this->post_page("blotter/remove");
});
}
public function testAddViewRemove(): void

View file

@ -169,7 +169,7 @@ class BulkActions extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $page, $user;
if ($event->page_matches("bulk_action") && $user->can(Permissions::PERFORM_BULK_ACTIONS)) {
if ($event->page_matches("bulk_action", method: "POST", permission: Permissions::PERFORM_BULK_ACTIONS)) {
$action = $event->req_POST('bulk_action');
try {

View file

@ -30,13 +30,11 @@ class BulkAdd extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $page, $user;
if ($event->page_matches("bulk_add")) {
$dir = $event->get_POST('dir');
if ($user->can(Permissions::BULK_ADD) && $user->check_auth_token() && $dir) {
shm_set_timeout(null);
$bae = send_event(new BulkAddEvent($dir));
$this->theme->display_upload_results($page, $bae->results);
}
if ($event->page_matches("bulk_add", method: "POST", permission: Permissions::BULK_ADD)) {
$dir = $event->req_POST('dir');
shm_set_timeout(null);
$bae = send_event(new BulkAddEvent($dir));
$this->theme->display_upload_results($page, $bae->results);
}
}

View file

@ -16,13 +16,11 @@ class BulkAddCSV extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $page, $user;
if ($event->page_matches("bulk_add_csv")) {
$csv = $event->get_POST('csv');
if ($user->can(Permissions::BULK_ADD) && $user->check_auth_token() && $csv) {
shm_set_timeout(null);
$this->add_csv($csv);
$this->theme->display_upload_results($page);
}
if ($event->page_matches("bulk_add_csv", method: "POST", permission: Permissions::BULK_ADD)) {
$csv = $event->req_POST('csv');
shm_set_timeout(null);
$this->add_csv($csv);
$this->theme->display_upload_results($page);
}
}

View file

@ -201,74 +201,32 @@ class CommentList extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
if ($event->page_matches("comment")) {
switch ($event->get_arg(0)) {
case "add":
$this->onPageRequest_add($event);
break;
case "delete":
$this->onPageRequest_delete($event);
break;
case "bulk_delete":
$this->onPageRequest_bulk_delete($event);
break;
case "list":
$this->onPageRequest_list($event);
break;
case "beta-search":
$this->onPageRequest_beta_search($event);
break;
}
}
}
public function onRobotsBuilding(RobotsBuildingEvent $event): void
{
// comment lists change all the time, crawlers should
// index individual image's comments
$event->add_disallow("comment");
}
private function onPageRequest_add(PageRequestEvent $event): void
{
global $user, $page;
try {
$i_iid = int_escape($event->req_POST('image_id'));
send_event(new CommentPostingEvent($i_iid, $user, $event->req_POST('comment')));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$i_iid", null, "comment_on_$i_iid"));
} catch (CommentPostingException $ex) {
$this->theme->display_error(403, "Comment Blocked", $ex->getMessage());
}
}
private function onPageRequest_delete(PageRequestEvent $event): void
{
global $user, $page;
if ($user->can(Permissions::DELETE_COMMENT)) {
// FIXME: post, not args
if ($event->count_args() === 3) {
send_event(new CommentDeletionEvent(int_escape($event->get_arg(1))));
$page->flash("Deleted comment");
global $cache, $config, $database, $user, $page;
if ($event->page_matches("comment/add", method: "POST", permission: Permissions::CREATE_COMMENT)) {
try {
$i_iid = int_escape($event->req_POST('image_id'));
send_event(new CommentPostingEvent($i_iid, $user, $event->req_POST('comment')));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link("post/view/" . $event->get_arg(2))));
$page->set_redirect(make_link("post/view/$i_iid", null, "comment_on_$i_iid"));
} catch (CommentPostingException $ex) {
$this->theme->display_error(403, "Comment Blocked", $ex->getMessage());
}
} else {
$this->theme->display_permission_denied();
}
}
private function onPageRequest_bulk_delete(PageRequestEvent $event): void
{
global $user, $database, $page;
if ($user->can(Permissions::DELETE_COMMENT)) {
if ($event->page_matches("comment/delete", permission: Permissions::DELETE_COMMENT)) {
// FIXME: post, not args
send_event(new CommentDeletionEvent(int_escape($event->get_arg(0))));
$page->flash("Deleted comment");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link("post/view/" . $event->get_arg(1))));
}
if ($event->page_matches("comment/bulk_delete", method: "POST", permission: Permissions::DELETE_COMMENT)) {
$ip = $event->req_POST('ip');
$comment_ids = $database->get_col("
SELECT id
FROM comments
WHERE owner_ip=:ip
", ["ip" => $ip]);
SELECT id
FROM comments
WHERE owner_ip=:ip
", ["ip" => $ip]);
$num = count($comment_ids);
log_warning("comment", "Deleting $num comments from $ip");
foreach ($comment_ids as $cid) {
@ -278,74 +236,73 @@ class CommentList extends Extension
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin"));
} else {
$this->theme->display_permission_denied();
}
if ($event->page_matches("comment/list")) {
$threads_per_page = 10;
$where = SPEED_HAX ? "WHERE posted > now() - interval '24 hours'" : "";
$total_pages = cache_get_or_set("comment_pages", fn () => (int)ceil($database->get_one("
SELECT COUNT(c1)
FROM (SELECT COUNT(image_id) AS c1 FROM comments $where GROUP BY image_id) AS s1
") / $threads_per_page), 600);
$total_pages = max($total_pages, 1);
$current_page = $event->try_page_num(1, $total_pages);
$start = $threads_per_page * $current_page;
$result = $database->execute("
SELECT image_id,MAX(posted) AS latest
FROM comments
$where
GROUP BY image_id
ORDER BY latest DESC
LIMIT :limit OFFSET :offset
", ["limit" => $threads_per_page, "offset" => $start]);
$user_ratings = Extension::is_enabled(RatingsInfo::KEY) ? Ratings::get_user_class_privs($user) : [];
$images = [];
while ($row = $result->fetch()) {
$image = Image::by_id((int)$row["image_id"]);
if (
Extension::is_enabled(RatingsInfo::KEY) && !is_null($image) &&
!in_array($image['rating'], $user_ratings)
) {
$image = null; // this is "clever", I may live to regret it
}
if (
Extension::is_enabled(ApprovalInfo::KEY) && !is_null($image) &&
$config->get_bool(ApprovalConfig::IMAGES) &&
$image['approved'] !== true
) {
$image = null;
}
if (!is_null($image)) {
$comments = $this->get_comments($image->id);
$images[] = [$image, $comments];
}
}
$this->theme->display_comment_list($images, $current_page + 1, $total_pages, $user->can(Permissions::CREATE_COMMENT));
}
if ($event->page_matches("comment/beta-search")) {
$search = $event->get_arg(0);
$page_num = $event->try_page_num(1);
$duser = User::by_name($search);
$i_comment_count = Comment::count_comments_by_user($duser);
$com_per_page = 50;
$total_pages = (int)ceil($i_comment_count / $com_per_page);
$comments = $this->get_user_comments($duser->id, $com_per_page, $page_num * $com_per_page);
$this->theme->display_all_user_comments($comments, $page_num + 1, $total_pages, $duser);
}
}
private function onPageRequest_list(PageRequestEvent $event): void
public function onRobotsBuilding(RobotsBuildingEvent $event): void
{
global $cache, $config, $database, $user;
$threads_per_page = 10;
$where = SPEED_HAX ? "WHERE posted > now() - interval '24 hours'" : "";
$total_pages = cache_get_or_set("comment_pages", fn () => (int)ceil($database->get_one("
SELECT COUNT(c1)
FROM (SELECT COUNT(image_id) AS c1 FROM comments $where GROUP BY image_id) AS s1
") / $threads_per_page), 600);
$total_pages = max($total_pages, 1);
$current_page = $event->try_page_num(1, $total_pages);
$start = $threads_per_page * $current_page;
$result = $database->execute("
SELECT image_id,MAX(posted) AS latest
FROM comments
$where
GROUP BY image_id
ORDER BY latest DESC
LIMIT :limit OFFSET :offset
", ["limit" => $threads_per_page, "offset" => $start]);
$user_ratings = Extension::is_enabled(RatingsInfo::KEY) ? Ratings::get_user_class_privs($user) : [];
$images = [];
while ($row = $result->fetch()) {
$image = Image::by_id((int)$row["image_id"]);
if (
Extension::is_enabled(RatingsInfo::KEY) && !is_null($image) &&
!in_array($image['rating'], $user_ratings)
) {
$image = null; // this is "clever", I may live to regret it
}
if (
Extension::is_enabled(ApprovalInfo::KEY) && !is_null($image) &&
$config->get_bool(ApprovalConfig::IMAGES) &&
$image['approved'] !== true
) {
$image = null;
}
if (!is_null($image)) {
$comments = $this->get_comments($image->id);
$images[] = [$image, $comments];
}
}
$this->theme->display_comment_list($images, $current_page + 1, $total_pages, $user->can(Permissions::CREATE_COMMENT));
}
private function onPageRequest_beta_search(PageRequestEvent $event): void
{
$search = $event->get_arg(1);
$page_num = $event->try_page_num(2);
$duser = User::by_name($search);
$i_comment_count = Comment::count_comments_by_user($duser);
$com_per_page = 50;
$total_pages = (int)ceil($i_comment_count / $com_per_page);
$comments = $this->get_user_comments($duser->id, $com_per_page, $page_num * $com_per_page);
$this->theme->display_all_user_comments($comments, $page_num + 1, $total_pages, $duser);
// comment lists change all the time, crawlers should
// index individual image's comments
$event->add_disallow("comment");
}
public function onAdminBuilding(AdminBuildingEvent $event): void

View file

@ -16,10 +16,8 @@ class ET extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $user;
if ($event->page_matches("system_info")) {
if ($user->can(Permissions::VIEW_SYSINTO)) {
$this->theme->display_info_page($this->to_yaml($this->get_info()));
}
if ($event->page_matches("system_info", permission: Permissions::VIEW_SYSINFO)) {
$this->theme->display_info_page($this->to_yaml($this->get_info()));
}
}
@ -27,7 +25,7 @@ class ET extends Extension
{
global $user;
if ($event->parent === "system") {
if ($user->can(Permissions::VIEW_SYSINTO)) {
if ($user->can(Permissions::VIEW_SYSINFO)) {
$event->add_nav_link("system_info", new Link('system_info'), "System Info", null, 10);
}
}
@ -36,7 +34,7 @@ class ET extends Extension
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
{
global $user;
if ($user->can(Permissions::VIEW_SYSINTO)) {
if ($user->can(Permissions::VIEW_SYSINFO)) {
$event->add_link("System Info", make_link("system_info"), 99);
}
}

View file

@ -67,13 +67,13 @@ class Favorites extends Extension
return;
} // FIXME: proper permissions
if ($event->authed_page_matches("favourite/add")) {
if ($event->page_matches("favourite/add", method: "POST")) {
$image_id = int_escape($event->get_arg(0));
send_event(new FavoriteSetEvent($image_id, $user, true));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
}
if ($event->authed_page_matches("favourite/remove")) {
if ($event->page_matches("favourite/remove", method: "POST")) {
$image_id = int_escape($event->get_arg(0));
send_event(new FavoriteSetEvent($image_id, $user, false));
$page->set_mode(PageMode::REDIRECT);

View file

@ -19,16 +19,14 @@ class Featured extends Extension
{
global $config, $page, $user;
if ($event->page_matches("featured_image")) {
if ($event->get_arg(0) == "set" && $user->check_auth_token()) {
$id = int_escape($event->get_POST('image_id'));
if ($user->can(Permissions::EDIT_FEATURE) && $id > 0) {
$config->set_int("featured_id", $id);
log_info("featured", "Featured post set to >>$id", "Featured post set");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$id"));
}
if ($event->page_matches("featured_image/set", method: "POST", permission: Permissions::EDIT_FEATURE)) {
$id = int_escape($event->req_POST('image_id'));
$config->set_int("featured_id", $id);
log_info("featured", "Featured post set to >>$id", "Featured post set");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$id"));
}
if ($event->get_arg(0) == "download") {
if ($event->page_matches("featured_image/download")) {
$image = Image::by_id($config->get_int("featured_id"));
if (!is_null($image)) {
$page->set_mode(PageMode::DATA);
@ -36,7 +34,7 @@ class Featured extends Extension
$page->set_data(file_get_contents_ex($image->get_image_filename()));
}
}
if ($event->get_arg(0) == "view") {
if ($event->page_matches("featured_image/view")) {
$image = Image::by_id($config->get_int("featured_id"));
if (!is_null($image)) {
send_event(new DisplayingImageEvent($image));

View file

@ -99,99 +99,97 @@ class Forum extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $page, $user;
if ($event->page_matches("forum")) {
switch ($event->get_arg(0)) {
case "index":
$this->show_last_threads($page, $event, $user->can(Permissions::FORUM_ADMIN));
if (!$user->is_anonymous()) {
$this->theme->display_new_thread_composer($page);
}
break;
case "view":
$threadID = int_escape($event->get_arg(1));
// $pageNumber = int_escape($event->get_arg(2));
$errors = $this->sanity_check_viewed_thread($threadID);
if (count($errors) > 0) {
$this->theme->display_error(500, "Error", implode("<br>", $errors));
break;
}
$this->show_posts($event, $user->can(Permissions::FORUM_ADMIN));
if ($user->can(Permissions::FORUM_ADMIN)) {
$this->theme->add_actions_block($page, $threadID);
}
if (!$user->is_anonymous()) {
$this->theme->display_new_post_composer($page, $threadID);
}
break;
case "new":
global $page;
$this->theme->display_new_thread_composer($page);
break;
case "create":
$redirectTo = "forum/index";
if (!$user->is_anonymous()) {
$errors = $this->sanity_check_new_thread();
if (count($errors) > 0) {
$this->theme->display_error(500, "Error", implode("<br>", $errors));
break;
}
$newThreadID = $this->save_new_thread($user);
$this->save_new_post($newThreadID, $user);
$redirectTo = "forum/view/".$newThreadID."/1";
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link($redirectTo));
break;
case "delete":
$threadID = int_escape($event->get_arg(1));
$postID = int_escape($event->get_arg(2));
if ($user->can(Permissions::FORUM_ADMIN)) {
$this->delete_post($postID);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/view/".$threadID));
break;
case "nuke":
$threadID = int_escape($event->get_arg(1));
if ($user->can(Permissions::FORUM_ADMIN)) {
$this->delete_thread($threadID);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/index"));
break;
case "answer":
$threadID = int_escape($event->req_POST("threadID"));
$total_pages = $this->get_total_pages_for_thread($threadID);
if (!$user->is_anonymous()) {
$errors = $this->sanity_check_new_post();
if (count($errors) > 0) {
$this->theme->display_error(500, "Error", implode("<br>", $errors));
break;
}
$this->save_new_post($threadID, $user);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/view/".$threadID."/".$total_pages));
break;
default:
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/index"));
//$this->theme->display_error(400, "Invalid action", "You should check forum/index.");
break;
if ($event->page_matches("forum/index")) {
if ($event->count_args() >= 2) {
$pageNumber = page_number($event->get_arg(1));
} else {
$pageNumber = 0;
}
$this->show_last_threads($page, $pageNumber, $user->can(Permissions::FORUM_ADMIN));
if (!$user->is_anonymous()) {
$this->theme->display_new_thread_composer($page);
}
}
if ($event->page_matches("forum/view")) {
$threadID = int_escape($event->get_arg(1));
// $pageNumber = int_escape($event->get_arg(2));
$errors = $this->sanity_check_viewed_thread($threadID);
if (count($errors) > 0) {
throw new UserErrorException(implode("<br>", $errors));
}
$threadID = int_escape($event->get_arg(1));
if ($event->count_args() >= 3) {
$pageNumber = page_number($event->get_arg(2));
} else {
$pageNumber = 0;
}
$this->show_posts($threadID, $pageNumber, $user->can(Permissions::FORUM_ADMIN));
if ($user->can(Permissions::FORUM_ADMIN)) {
$this->theme->add_actions_block($page, $threadID);
}
if (!$user->is_anonymous()) {
$this->theme->display_new_post_composer($page, $threadID);
}
}
if ($event->page_matches("forum/new")) {
$this->theme->display_new_thread_composer($page);
}
if ($event->page_matches("forum/create")) {
$redirectTo = "forum/index";
if (!$user->is_anonymous()) {
$errors = $this->sanity_check_new_thread();
if (count($errors) > 0) {
throw new UserErrorException(implode("<br>", $errors));
}
$newThreadID = $this->save_new_thread($user);
$this->save_new_post($newThreadID, $user);
$redirectTo = "forum/view/" . $newThreadID . "/1";
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link($redirectTo));
}
if ($event->page_matches("forum/delete")) {
$threadID = int_escape($event->get_arg(1));
$postID = int_escape($event->get_arg(2));
if ($user->can(Permissions::FORUM_ADMIN)) {
$this->delete_post($postID);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/view/" . $threadID));
}
if ($event->page_matches("forum/nuke")) {
$threadID = int_escape($event->get_arg(1));
if ($user->can(Permissions::FORUM_ADMIN)) {
$this->delete_thread($threadID);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/index"));
}
if ($event->page_matches("forum/answer")) {
$threadID = int_escape($event->req_POST("threadID"));
$total_pages = $this->get_total_pages_for_thread($threadID);
if (!$user->is_anonymous()) {
$errors = $this->sanity_check_new_post();
if (count($errors) > 0) {
throw new UserErrorException(implode("<br>", $errors));
}
$this->save_new_post($threadID, $user);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/view/" . $threadID . "/" . $total_pages));
}
}
private function get_total_pages_for_thread(int $threadID): int
@ -203,7 +201,7 @@ class Forum extends Extension
WHERE thread_id = :thread_id
", ['thread_id' => $threadID]);
return (int)ceil($result["count"] / $config->get_int("forumPostsPerPage"));
return (int) ceil($result["count"] / $config->get_int("forumPostsPerPage"));
}
/**
@ -268,55 +266,42 @@ class Forum extends Extension
return $database->get_one("SELECT t.title FROM forum_threads AS t WHERE t.id = :id ", ['id' => $threadID]);
}
private function show_last_threads(Page $page, PageRequestEvent $event, bool $showAdminOptions = false): void
private function show_last_threads(Page $page, int $pageNumber, bool $showAdminOptions = false): void
{
global $config, $database;
$threadsPerPage = $config->get_int('forumThreadsPerPage', 15);
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM forum_threads") / $threadsPerPage);
if ($event->count_args() >= 2) {
$pageNumber = page_number($event->get_arg(1), $totalPages);
} else {
$pageNumber = 0;
}
$totalPages = (int) ceil($database->get_one("SELECT COUNT(*) FROM forum_threads") / $threadsPerPage);
$threads = $database->get_all(
"SELECT f.id, f.sticky, f.title, f.date, f.uptodate, u.name AS user_name, u.email AS user_email, u.class AS user_class, sum(1) - 1 AS response_count ".
"FROM forum_threads AS f ".
"INNER JOIN users AS u ".
"ON f.user_id = u.id ".
"INNER JOIN forum_posts AS p ".
"ON p.thread_id = f.id ".
"GROUP BY f.id, f.sticky, f.title, f.date, u.name, u.email, u.class ".
"ORDER BY f.sticky ASC, f.uptodate DESC LIMIT :limit OFFSET :offset",
"SELECT f.id, f.sticky, f.title, f.date, f.uptodate, u.name AS user_name, u.email AS user_email, u.class AS user_class, sum(1) - 1 AS response_count " .
"FROM forum_threads AS f " .
"INNER JOIN users AS u " .
"ON f.user_id = u.id " .
"INNER JOIN forum_posts AS p " .
"ON p.thread_id = f.id " .
"GROUP BY f.id, f.sticky, f.title, f.date, u.name, u.email, u.class " .
"ORDER BY f.sticky ASC, f.uptodate DESC LIMIT :limit OFFSET :offset",
["limit" => $threadsPerPage, "offset" => $pageNumber * $threadsPerPage]
);
$this->theme->display_thread_list($page, $threads, $showAdminOptions, $pageNumber + 1, $totalPages);
}
private function show_posts(PageRequestEvent $event, bool $showAdminOptions = false): void
private function show_posts(int $threadID, int $pageNumber, bool $showAdminOptions = false): void
{
global $config, $database;
$threadID = int_escape($event->get_arg(1));
$postsPerPage = $config->get_int('forumPostsPerPage', 15);
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM forum_posts WHERE thread_id = :id", ['id' => $threadID]) / $postsPerPage);
$totalPages = (int) ceil($database->get_one("SELECT COUNT(*) FROM forum_posts WHERE thread_id = :id", ['id' => $threadID]) / $postsPerPage);
$threadTitle = $this->get_thread_title($threadID);
if ($event->count_args() >= 3) {
$pageNumber = page_number($event->get_arg(2), $totalPages);
} else {
$pageNumber = 0;
}
$posts = $database->get_all(
"SELECT p.id, p.date, p.message, u.name as user_name, u.email AS user_email, u.class AS user_class ".
"FROM forum_posts AS p ".
"INNER JOIN users AS u ".
"ON p.user_id = u.id ".
"WHERE thread_id = :thread_id ".
"ORDER BY p.date ASC ".
"LIMIT :limit OFFSET :offset",
"SELECT p.id, p.date, p.message, u.name as user_name, u.email AS user_email, u.class AS user_class " .
"FROM forum_posts AS p " .
"INNER JOIN users AS u " .
"ON p.user_id = u.id " .
"WHERE thread_id = :thread_id " .
"ORDER BY p.date ASC " .
"LIMIT :limit OFFSET :offset",
["thread_id" => $threadID, "offset" => $pageNumber * $postsPerPage, "limit" => $postsPerPage]
);
$this->theme->display_thread($posts, $showAdminOptions, $threadTitle, $threadID, $pageNumber + 1, $totalPages);

View file

@ -88,19 +88,17 @@ class ImageIO extends Extension
$thumb_height = $config->get_int(ImageConfig::THUMB_HEIGHT, 192);
$page->add_html_header("<style>:root {--thumb-width: {$thumb_width}px; --thumb-height: {$thumb_height}px;}</style>");
if ($event->page_matches("image/delete")) {
if ($event->page_matches("image/delete", method: "POST", permission: Permissions::DELETE_IMAGE)) {
global $page, $user;
if ($user->can(Permissions::DELETE_IMAGE) && $event->get_POST('image_id') && $user->check_auth_token()) {
$image = Image::by_id(int_escape($event->get_POST('image_id')));
if ($image) {
send_event(new ImageDeletionEvent($image));
$image = Image::by_id(int_escape($event->req_POST('image_id')));
if ($image) {
send_event(new ImageDeletionEvent($image));
if ($config->get_string(ImageConfig::ON_DELETE) === ImageConfig::ON_DELETE_NEXT) {
redirect_to_next_image($image, $event->get_GET('search'));
} else {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link(), ['post/view']));
}
if ($config->get_string(ImageConfig::ON_DELETE) === ImageConfig::ON_DELETE_NEXT) {
redirect_to_next_image($image, $event->get_GET('search'));
} else {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link(), ['post/view']));
}
}
} elseif ($event->page_matches("image")) {

View file

@ -89,41 +89,39 @@ class ImageBan extends Extension
{
global $database, $page, $user;
if ($event->page_matches("image_hash_ban")) {
if ($user->can(Permissions::BAN_IMAGE)) {
if ($event->get_arg(0) == "add") {
$user->ensure_authed();
$input = validate_input(["c_hash" => "optional,string", "c_reason" => "string", "c_image_id" => "optional,int"]);
$image = isset($input['c_image_id']) ? Image::by_id($input['c_image_id']) : null;
$hash = isset($input["c_hash"]) ? $input["c_hash"] : $image->hash;
$reason = isset($input['c_reason']) ? $input['c_reason'] : "DNP";
if ($event->page_matches("image_hash_ban", permission: Permissions::BAN_IMAGE)) {
if ($event->page_matches("image_hash_ban/add", method: "POST")) {
$input = validate_input(["c_hash" => "optional,string", "c_reason" => "string", "c_image_id" => "optional,int"]);
$image = isset($input['c_image_id']) ? Image::by_id($input['c_image_id']) : null;
$hash = isset($input["c_hash"]) ? $input["c_hash"] : $image->hash;
$reason = isset($input['c_reason']) ? $input['c_reason'] : "DNP";
if ($hash) {
send_event(new AddImageHashBanEvent($hash, $reason));
$page->flash("Post ban added");
if ($hash) {
send_event(new AddImageHashBanEvent($hash, $reason));
$page->flash("Post ban added");
if ($image) {
send_event(new ImageDeletionEvent($image));
$page->flash("Post deleted");
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
if ($image) {
send_event(new ImageDeletionEvent($image));
$page->flash("Post deleted");
}
} elseif ($event->get_arg(0) == "remove") {
$user->ensure_authed();
$input = validate_input(["d_hash" => "string"]);
send_event(new RemoveImageHashBanEvent($input['d_hash']));
$page->flash("Post ban removed");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
} elseif ($event->get_arg(0) == "list") {
$t = new HashBanTable($database->raw_db());
$t->token = $user->get_auth_token();
$t->inputs = $event->GET;
$this->theme->display_crud("Post Bans", $t->table($t->query()), $t->paginator());
}
}
if ($event->page_matches("image_hash_ban/remove", method: "POST")) {
$input = validate_input(["d_hash" => "string"]);
send_event(new RemoveImageHashBanEvent($input['d_hash']));
$page->flash("Post ban removed");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
if ($event->page_matches("image_hash_ban/list")) {
$t = new HashBanTable($database->raw_db());
$t->token = $user->get_auth_token();
$t->inputs = $event->GET;
$this->theme->display_crud("Post Bans", $t->table($t->query()), $t->paginator());
}
}
}

View file

@ -180,33 +180,31 @@ class IPBan extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
if ($event->page_matches("ip_ban")) {
if ($event->page_matches("ip_ban", permission: Permissions::BAN_IP)) {
global $database, $page, $user;
if ($user->can(Permissions::BAN_IP)) {
if ($event->get_arg(0) == "create") {
$user->ensure_authed();
$input = validate_input(["c_ip" => "string", "c_mode" => "string", "c_reason" => "string", "c_expires" => "optional,date"]);
send_event(new AddIPBanEvent($input['c_ip'], $input['c_mode'], $input['c_reason'], $input['c_expires']));
$page->flash("Ban for {$input['c_ip']} added");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("ip_ban/list"));
} elseif ($event->get_arg(0) == "delete") {
$user->ensure_authed();
$input = validate_input(["d_id" => "int"]);
send_event(new RemoveIPBanEvent($input['d_id']));
$page->flash("Ban removed");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("ip_ban/list"));
} elseif ($event->get_arg(0) == "list") {
$event->GET['c_banner'] = $user->name;
$event->GET['c_added'] = date('Y-m-d');
$t = new IPBanTable($database->raw_db());
$t->token = $user->get_auth_token();
$t->inputs = $event->GET;
$this->theme->display_bans($page, $t->table($t->query()), $t->paginator());
}
} else {
$this->theme->display_permission_denied();
if ($event->page_matches("ip_ban/create", method: "POST")) {
$user->ensure_authed();
$input = validate_input(["c_ip" => "string", "c_mode" => "string", "c_reason" => "string", "c_expires" => "optional,date"]);
send_event(new AddIPBanEvent($input['c_ip'], $input['c_mode'], $input['c_reason'], $input['c_expires']));
$page->flash("Ban for {$input['c_ip']} added");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("ip_ban/list"));
}
if ($event->page_matches("ip_ban/delete", method: "POST")) {
$user->ensure_authed();
$input = validate_input(["d_id" => "int"]);
send_event(new RemoveIPBanEvent($input['d_id']));
$page->flash("Ban removed");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("ip_ban/list"));
}
if ($event->page_matches("ip_ban/list")) {
$event->GET['c_banner'] = $user->name;
$event->GET['c_added'] = date('Y-m-d');
$t = new IPBanTable($database->raw_db());
$t->token = $user->get_auth_token();
$t->inputs = $event->GET;
$this->theme->display_bans($page, $t->table($t->query()), $t->paginator());
}
}
}

View file

@ -10,9 +10,9 @@ class IPBanTest extends ShimmiePHPUnitTestCase
public function testAccess(): void
{
$page = $this->get_page('ip_ban/list');
$this->assertEquals(403, $page->code);
$this->assertEquals("Permission Denied", $page->title);
$this->assertException(PermissionDeniedException::class, function () {
$this->get_page('ip_ban/list');
});
}
public function testIPBan(): void

View file

@ -278,12 +278,10 @@ class LogDatabase extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $database, $user;
if ($event->page_matches("log/view")) {
if ($user->can(Permissions::VIEW_EVENTLOG)) {
$t = new LogTable($database->raw_db());
$t->inputs = $event->GET;
$this->theme->display_crud("Event Log", $t->table($t->query()), $t->paginator());
}
if ($event->page_matches("log/view", permission: Permissions::VIEW_EVENTLOG)) {
$t = new LogTable($database->raw_db());
$t->inputs = $event->GET;
$this->theme->display_crud("Event Log", $t->table($t->query()), $t->paginator());
}
}

View file

@ -75,7 +75,7 @@ class Media extends Extension
global $page, $user;
if (
$event->authed_page_matches("media_rescan") &&
$event->page_matches("media_rescan", method: "POST") &&
$user->can(Permissions::RESCAN_MEDIA)
) {
$image = Image::by_id(int_escape($event->get_arg(0)));

View file

@ -126,33 +126,31 @@ class NotATag extends Extension
{
global $database, $page, $user;
if ($event->page_matches("untag")) {
if ($user->can(Permissions::BAN_IMAGE)) {
if ($event->get_arg(0) == "add") {
$user->ensure_authed();
$input = validate_input(["c_tag" => "string", "c_redirect" => "string"]);
$database->execute(
"INSERT INTO untags(tag, redirect) VALUES (:tag, :redirect)",
["tag" => $input['c_tag'], "redirect" => $input['c_redirect']]
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
} elseif ($event->get_arg(0) == "remove") {
$user->ensure_authed();
$input = validate_input(["d_tag" => "string"]);
$database->execute(
"DELETE FROM untags WHERE LOWER(tag) = LOWER(:tag)",
["tag" => $input['d_tag']]
);
$page->flash("Post ban removed");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
} elseif ($event->get_arg(0) == "list") {
$t = new NotATagTable($database->raw_db());
$t->token = $user->get_auth_token();
$t->inputs = $event->GET;
$this->theme->display_crud("UnTags", $t->table($t->query()), $t->paginator());
}
if ($event->page_matches("untag", permission: Permissions::BAN_IMAGE)) {
if ($event->page_matches("untag/add", method: "POST")) {
$input = validate_input(["c_tag" => "string", "c_redirect" => "string"]);
$database->execute(
"INSERT INTO untags(tag, redirect) VALUES (:tag, :redirect)",
["tag" => $input['c_tag'], "redirect" => $input['c_redirect']]
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
if ($event->page_matches("untag/remove", method: "POST")) {
$input = validate_input(["d_tag" => "string"]);
$database->execute(
"DELETE FROM untags WHERE LOWER(tag) = LOWER(:tag)",
["tag" => $input['d_tag']]
);
$page->flash("Post ban removed");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
if ($event->page_matches("untag/list")) {
$t = new NotATagTable($database->raw_db());
$t->token = $user->get_auth_token();
$t->inputs = $event->GET;
$this->theme->display_crud("UnTags", $t->table($t->query()), $t->paginator());
}
}
}

View file

@ -78,92 +78,81 @@ class Notes extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
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 = int_escape($event->get_arg(1));
$reviewID = int_escape($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_request":
$image_id = int_escape($event->req_POST("image_id"));
if (!$user->is_anonymous()) {
$this->add_note_request($image_id);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
break;
case "nuke_requests":
$image_id = int_escape($event->req_POST("image_id"));
if ($user->can(Permissions::NOTES_ADMIN)) {
$this->nuke_requests($image_id);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
break;
case "create_note":
$page->set_mode(PageMode::DATA);
if (!$user->is_anonymous()) {
$note_id = $this->add_new_note();
$page->set_data(json_encode_ex([
'status' => 'success',
'note_id' => $note_id,
]));
}
break;
case "update_note":
$page->set_mode(PageMode::DATA);
if (!$user->is_anonymous()) {
$this->update_note();
$page->set_data(json_encode_ex(['status' => 'success']));
}
break;
case "delete_note":
$page->set_mode(PageMode::DATA);
if ($user->can(Permissions::NOTES_ADMIN)) {
$this->delete_note();
$page->set_data(json_encode_ex(['status' => 'success']));
}
break;
case "nuke_notes":
$image_id = int_escape($event->req_POST("image_id"));
if ($user->can(Permissions::NOTES_ADMIN)) {
$this->nuke_notes($image_id);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
break;
default:
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("note/list"));
break;
if ($event->page_matches("note/lost")) {
$this->get_notes_list($event->try_page_num(0)); // This should show images like post/list but i don't know how do that.
}
if ($event->page_matches("note/requests")) {
$this->get_notes_requests($event->try_page_num(0)); // This should show images like post/list but i don't know how do that.
}
if ($event->page_matches("note/search")) {
if (!$user->is_anonymous()) {
$this->theme->search_notes_page($page);
}
}
if ($event->page_matches("note/updated")) {
$this->get_histories($event->try_page_num(0));
}
if ($event->page_matches("note/history")) {
$this->get_history(int_escape($event->get_arg(0)), $event->try_page_num(1));
}
if ($event->page_matches("note/revert")) {
$noteID = int_escape($event->get_arg(0));
$reviewID = int_escape($event->get_arg(1));
if (!$user->is_anonymous()) {
$this->revert_history($noteID, $reviewID);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("note/updated"));
}
if ($event->page_matches("note/add_request")) {
$image_id = int_escape($event->req_POST("image_id"));
if (!$user->is_anonymous()) {
$this->add_note_request($image_id);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
}
if ($event->page_matches("note/nuke_requests")) {
$image_id = int_escape($event->req_POST("image_id"));
if ($user->can(Permissions::NOTES_ADMIN)) {
$this->nuke_requests($image_id);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
}
if ($event->page_matches("note/create_note")) {
$page->set_mode(PageMode::DATA);
if (!$user->is_anonymous()) {
$note_id = $this->add_new_note();
$page->set_data(json_encode_ex([
'status' => 'success',
'note_id' => $note_id,
]));
}
}
if ($event->page_matches("note/update_note")) {
$page->set_mode(PageMode::DATA);
if (!$user->is_anonymous()) {
$this->update_note();
$page->set_data(json_encode_ex(['status' => 'success']));
}
}
if ($event->page_matches("note/delete_note")) {
$page->set_mode(PageMode::DATA);
if ($user->can(Permissions::NOTES_ADMIN)) {
$this->delete_note();
$page->set_data(json_encode_ex(['status' => 'success']));
}
}
if ($event->page_matches("note/nuke_notes")) {
$image_id = int_escape($event->req_POST("image_id"));
if ($user->can(Permissions::NOTES_ADMIN)) {
$this->nuke_notes($image_id);
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
}
}
@ -364,13 +353,12 @@ class Notes extends Extension
log_info("notes", "Requests deleted from {$image_id} by {$user->name}");
}
private function get_notes_list(PageRequestEvent $event): void
private function get_notes_list(int $pageNumber): void
{
global $database, $config;
$pageNumber = $event->try_page_num(1);
$notesPerPage = $config->get_int('notesNotesPerPage');
$totalPages = (int)ceil($database->get_one("SELECT COUNT(DISTINCT image_id) FROM notes") / $notesPerPage);
$totalPages = (int) ceil($database->get_one("SELECT COUNT(DISTINCT image_id) FROM notes") / $notesPerPage);
//$result = $database->get_all("SELECT * FROM pool_images WHERE pool_id=:pool_id", ['pool_id'=>$poolID]);
$image_ids = $database->get_col(
@ -383,19 +371,17 @@ class Notes extends Extension
);
$images = [];
foreach($image_ids as $id) {
foreach ($image_ids as $id) {
$images[] = Image::by_id($id);
}
$this->theme->display_note_list($images, $pageNumber + 1, $totalPages);
}
private function get_notes_requests(PageRequestEvent $event): void
private function get_notes_requests(int $pageNumber): void
{
global $config, $database;
$pageNumber = $event->try_page_num(1);
$requestsPerPage = $config->get_int('notesRequestsPerPage');
//$result = $database->get_all("SELECT * FROM pool_images WHERE pool_id=:pool_id", ['pool_id'=>$poolID]);
@ -408,7 +394,7 @@ class Notes extends Extension
["offset" => $pageNumber * $requestsPerPage, "limit" => $requestsPerPage]
);
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM note_request") / $requestsPerPage);
$totalPages = (int) ceil($database->get_one("SELECT COUNT(*) FROM note_request") / $requestsPerPage);
$images = [];
while ($row = $result->fetch()) {
@ -430,54 +416,60 @@ class Notes extends Extension
INSERT INTO note_histories (note_enable, note_id, review_id, image_id, user_id, user_ip, date, x1, y1, height, width, note)
VALUES (:note_enable, :note_id, :review_id, :image_id, :user_id, :user_ip, now(), :x1, :y1, :height, :width, :note)
",
['note_enable' => $noteEnable, 'note_id' => $noteID, 'review_id' => $reviewID, 'image_id' => $imageID, 'user_id' => $user->id, 'user_ip' => get_real_ip(),
'x1' => $noteX1, 'y1' => $noteY1, 'height' => $noteHeight, 'width' => $noteWidth, 'note' => $noteText]
[
'note_enable' => $noteEnable,
'note_id' => $noteID,
'review_id' => $reviewID,
'image_id' => $imageID,
'user_id' => $user->id,
'user_ip' => get_real_ip(),
'x1' => $noteX1,
'y1' => $noteY1,
'height' => $noteHeight,
'width' => $noteWidth,
'note' => $noteText
]
);
}
private function get_histories(PageRequestEvent $event): void
private function get_histories(int $pageNumber): void
{
global $config, $database;
$pageNumber = $event->try_page_num(1);
$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 :limit OFFSET :offset",
"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 :limit OFFSET :offset",
['offset' => $pageNumber * $historiesPerPage, 'limit' => $historiesPerPage]
);
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM note_histories") / $historiesPerPage);
$totalPages = (int) ceil($database->get_one("SELECT COUNT(*) FROM note_histories") / $historiesPerPage);
$this->theme->display_histories($histories, $pageNumber + 1, $totalPages);
}
private function get_history(PageRequestEvent $event): void
private function get_history(int $noteID, int $pageNumber): void
{
global $config, $database;
$noteID = $event->get_arg(1);
$pageNumber = $event->try_page_num(2);
$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 = :note_id ".
"ORDER BY date DESC LIMIT :limit OFFSET :offset",
"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 = :note_id " .
"ORDER BY date DESC LIMIT :limit OFFSET :offset",
['note_id' => $noteID, 'offset' => $pageNumber * $historiesPerPage, 'limit' => $historiesPerPage]
);
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM note_histories WHERE note_id = :note_id", ['note_id' => $noteID]) / $historiesPerPage);
$totalPages = (int) ceil($database->get_one("SELECT COUNT(*) FROM note_histories WHERE note_id = :note_id", ['note_id' => $noteID]) / $historiesPerPage);
$this->theme->display_history($histories, $pageNumber + 1, $totalPages);
}
@ -492,13 +484,13 @@ class Notes extends Extension
$history = $database->get_row("SELECT * FROM note_histories WHERE note_id = :note_id AND review_id = :review_id", ['note_id' => $noteID, 'review_id' => $reviewID]);
$noteEnable = $history['note_enable'];
$noteID = $history['note_id'];
$imageID = $history['image_id'];
$noteX1 = $history['x1'];
$noteY1 = $history['y1'];
$noteID = $history['note_id'];
$imageID = $history['image_id'];
$noteX1 = $history['x1'];
$noteY1 = $history['y1'];
$noteHeight = $history['height'];
$noteWidth = $history['width'];
$noteText = $history['note'];
$noteWidth = $history['width'];
$noteText = $history['note'];
$database->execute("
UPDATE notes

View file

@ -156,36 +156,30 @@ class NumericScore extends Extension
$html .= "</td></tr>";
}
die($html);
} elseif ($event->page_matches("numeric_score_vote") && $user->check_auth_token()) {
if ($user->can(Permissions::CREATE_VOTE)) {
$image_id = int_escape($event->req_POST("image_id"));
$score = int_escape($event->req_POST("vote"));
if (($score == -1 || $score == 0 || $score == 1) && $image_id > 0) {
send_event(new NumericScoreSetEvent($image_id, $user, $score));
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
}
} elseif ($event->page_matches("numeric_score/remove_votes_on") && $user->check_auth_token()) {
if ($user->can(Permissions::EDIT_OTHER_VOTE)) {
$image_id = int_escape($event->req_POST("image_id"));
$database->execute(
"DELETE FROM numeric_score_votes WHERE image_id=:image_id",
['image_id' => $image_id]
);
$database->execute(
"UPDATE images SET numeric_score=0 WHERE id=:id",
['id' => $image_id]
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
}
} elseif ($event->page_matches("numeric_score/remove_votes_by") && $user->check_auth_token()) {
if ($user->can(Permissions::EDIT_OTHER_VOTE)) {
$this->delete_votes_by(int_escape($event->req_POST('user_id')));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link());
} elseif ($event->page_matches("numeric_score_vote", method: "POST", permission: Permissions::CREATE_VOTE)) {
$image_id = int_escape($event->req_POST("image_id"));
$score = int_escape($event->req_POST("vote"));
if (($score == -1 || $score == 0 || $score == 1) && $image_id > 0) {
send_event(new NumericScoreSetEvent($image_id, $user, $score));
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
} elseif ($event->page_matches("numeric_score/remove_votes_on", method: "POST", permission: Permissions::EDIT_OTHER_VOTE)) {
$image_id = int_escape($event->req_POST("image_id"));
$database->execute(
"DELETE FROM numeric_score_votes WHERE image_id=:image_id",
['image_id' => $image_id]
);
$database->execute(
"UPDATE images SET numeric_score=0 WHERE id=:id",
['id' => $image_id]
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
} elseif ($event->page_matches("numeric_score/remove_votes_by", method: "POST", permission: Permissions::EDIT_OTHER_VOTE)) {
$this->delete_votes_by(int_escape($event->req_POST('user_id')));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link());
} elseif ($event->page_matches("popular_by_day") || $event->page_matches("popular_by_month") || $event->page_matches("popular_by_year")) {
//FIXME: popular_by isn't linked from anywhere
list($day, $month, $year) = [date("d"), date("m"), date("Y")];

View file

@ -227,66 +227,49 @@ class PrivMsg extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $cache, $database, $page, $user;
if ($event->page_matches("pm")) {
switch ($event->get_arg(0)) {
case "read":
if ($user->can(Permissions::READ_PM)) {
$pm_id = int_escape($event->get_arg(1));
$pm = $database->get_row("SELECT * FROM private_message WHERE id = :id", ["id" => $pm_id]);
if (is_null($pm)) {
$this->theme->display_error(404, "No such PM", "There is no PM #$pm_id");
} elseif (($pm["to_id"] == $user->id) || $user->can(Permissions::VIEW_OTHER_PMS)) {
$from_user = User::by_id((int)$pm["from_id"]);
if ($pm["to_id"] == $user->id) {
$database->execute("UPDATE private_message SET is_read=true WHERE id = :id", ["id" => $pm_id]);
$cache->delete("pm-count-{$user->id}");
}
$pmo = PM::from_row($pm);
$this->theme->display_message($page, $from_user, $user, $pmo);
if($user->can(Permissions::SEND_PM)) {
$this->theme->display_composer($page, $user, $from_user, "Re: ".$pmo->subject);
}
} else {
$this->theme->display_permission_denied();
}
}
break;
case "delete":
if ($user->can(Permissions::READ_PM)) {
if ($user->check_auth_token()) {
$pm_id = int_escape($event->get_POST("pm_id"));
$pm = $database->get_row("SELECT * FROM private_message WHERE id = :id", ["id" => $pm_id]);
if (is_null($pm)) {
$this->theme->display_error(404, "No such PM", "There is no PM #$pm_id");
} elseif (($pm["to_id"] == $user->id) || $user->can(Permissions::VIEW_OTHER_PMS)) {
$database->execute("DELETE FROM private_message WHERE id = :id", ["id" => $pm_id]);
$cache->delete("pm-count-{$user->id}");
log_info("pm", "Deleted PM #$pm_id", "PM deleted");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
}
}
break;
case "send":
if ($user->can(Permissions::SEND_PM)) {
if ($user->check_auth_token()) {
$to_id = int_escape($event->get_POST("to_id"));
$from_id = $user->id;
$subject = $event->req_POST("subject");
$message = $event->req_POST("message");
send_event(new SendPMEvent(new PM($from_id, get_real_ip(), $to_id, $subject, $message)));
$page->flash("PM sent");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
}
break;
default:
$this->theme->display_error(400, "Invalid action", "That's not something you can do with a PM");
break;
if ($event->page_matches("pm/read", permission: Permissions::READ_PM)) {
$pm_id = int_escape($event->get_arg(1));
$pm = $database->get_row("SELECT * FROM private_message WHERE id = :id", ["id" => $pm_id]);
if (is_null($pm)) {
$this->theme->display_error(404, "No such PM", "There is no PM #$pm_id");
} elseif (($pm["to_id"] == $user->id) || $user->can(Permissions::VIEW_OTHER_PMS)) {
$from_user = User::by_id((int)$pm["from_id"]);
if ($pm["to_id"] == $user->id) {
$database->execute("UPDATE private_message SET is_read=true WHERE id = :id", ["id" => $pm_id]);
$cache->delete("pm-count-{$user->id}");
}
$pmo = PM::from_row($pm);
$this->theme->display_message($page, $from_user, $user, $pmo);
if($user->can(Permissions::SEND_PM)) {
$this->theme->display_composer($page, $user, $from_user, "Re: ".$pmo->subject);
}
} else {
throw new PermissionDeniedException("You do not have permission to view this PM");
}
}
if ($event->page_matches("pm/delete", method: "POST", permission: Permissions::READ_PM)) {
$pm_id = int_escape($event->req_POST("pm_id"));
$pm = $database->get_row("SELECT * FROM private_message WHERE id = :id", ["id" => $pm_id]);
if (is_null($pm)) {
$this->theme->display_error(404, "No such PM", "There is no PM #$pm_id");
} elseif (($pm["to_id"] == $user->id) || $user->can(Permissions::VIEW_OTHER_PMS)) {
$database->execute("DELETE FROM private_message WHERE id = :id", ["id" => $pm_id]);
$cache->delete("pm-count-{$user->id}");
log_info("pm", "Deleted PM #$pm_id", "PM deleted");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
}
if ($event->page_matches("pm/send", method: "POST", permission: Permissions::SEND_PM)) {
$to_id = int_escape($event->req_POST("to_id"));
$from_id = $user->id;
$subject = $event->req_POST("subject");
$message = $event->req_POST("message");
send_event(new SendPMEvent(new PM($from_id, get_real_ip(), $to_id, $subject, $message)));
$page->flash("PM sent");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
}
public function onSendPM(SendPMEvent $event): void

View file

@ -93,14 +93,14 @@ class Pool
*/
public function __construct(array $row)
{
$this->id = (int)$row['id'];
$this->user_id = (int)$row['user_id'];
$this->id = (int) $row['id'];
$this->user_id = (int) $row['user_id'];
$this->user_name = $row['user_name'] ?? null;
$this->public = bool_escape($row['public']);
$this->title = $row['title'];
$this->description = $row['description'];
$this->date = $row['date'];
$this->posts = (int)$row['posts'];
$this->posts = (int) $row['posts'];
}
/**
@ -198,7 +198,7 @@ class Pools extends Extension
// column non-deterministically, so let's check if it is there and
// add it if needed.
$cols = $database->raw_db()->describe("pools");
if(!array_key_exists("lastupdated", $cols)) {
if (!array_key_exists("lastupdated", $cols)) {
$database->execute("ALTER TABLE pools ADD COLUMN lastupdated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
}
$this->set_version("ext_pools_version", 5);
@ -240,7 +240,7 @@ class Pools extends Extension
if ($event->page_matches("pool/list")) { //index
if ($event->get_GET('search')) {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link('pool/list').'/'.url_escape($event->get_GET('search')).'/'.strval($event->try_page_num(1)));
$page->set_redirect(make_link('pool/list') . '/' . url_escape($event->get_GET('search')) . '/' . strval($event->try_page_num(1)));
return;
}
if (count($event->args) >= 4) { // Assume first 2 args are search and page num
@ -251,232 +251,218 @@ class Pools extends Extension
$page_num = $event->try_page_num(0);
}
$this->list_pools($page, $page_num, $search);
} elseif ($event->page_matches("pool")) {
// What action are we trying to perform?
switch ($event->get_arg(0)) {
case "new": // Show form for new pools
if (!$user->is_anonymous()) {
$this->theme->new_pool_composer($page);
} else {
$errMessage = "You must be registered and logged in to create a new pool.";
$this->theme->display_error(401, "Error", $errMessage);
}
break;
}
if ($event->page_matches("pool/new", method: "GET")) {
if (!$user->is_anonymous()) {
$this->theme->new_pool_composer($page);
} else {
$errMessage = "You must be registered and logged in to create a new pool.";
$this->theme->display_error(401, "Error", $errMessage);
}
}
if ($event->page_matches("pool/create", method: "POST")) {
try {
$pce = send_event(
new PoolCreationEvent(
$event->req_POST("title"),
$user,
bool_escape($event->req_POST("public")),
$event->req_POST("description")
)
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pce->new_id));
} catch (PoolCreationException $e) {
$this->theme->display_error(400, "Error", $e->error);
}
}
if ($event->page_matches("pool/view", method: "GET")) {
$poolID = int_escape($event->get_arg(0));
$this->get_posts($event->try_page_num(1), $poolID);
}
if ($event->page_matches("pool/updated")) {
$this->get_history($event->try_page_num(0));
}
if ($event->page_matches("pool/revert")) {
if (!$user->is_anonymous()) {
$historyID = int_escape($event->get_arg(0));
$this->revert_history($historyID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/updated"));
}
}
if ($event->page_matches("pool/edit")) {
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
case "create": // ADD _POST
try {
$event = send_event(new PoolCreationEvent(
$event->req_POST("title"),
$user,
bool_escape($event->req_POST("public")),
$event->req_POST("description")
));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $event->new_id));
} catch (PoolCreationException $e) {
$this->theme->display_error(400, "Error", $e->error);
}
break;
if ($this->have_permission($user, $pool)) {
$result = $database->execute("SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order ASC", ["pid" => $pool_id]);
$images = [];
while ($row = $result->fetch()) {
$images[] = Image::by_id((int) $row["image_id"]);
}
$this->theme->edit_pool($page, $pool, $images);
} else {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
}
}
if ($event->page_matches("pool/order")) {
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
case "view":
$poolID = int_escape($event->get_arg(1));
$this->get_posts($event, $poolID);
break;
if ($event->get_POST("order_view")) {
if ($this->have_permission($user, $pool)) {
$result = $database->execute(
"SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order ASC",
["pid" => $pool_id]
);
$images = [];
case "updated":
$this->get_history($event->try_page_num(1));
break;
case "revert":
if (!$user->is_anonymous()) {
$historyID = int_escape($event->get_arg(1));
$this->revert_history($historyID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/updated"));
}
break;
case "edit": // Edit the pool (remove images)
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($this->have_permission($user, $pool)) {
$result = $database->execute("SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order ASC", ["pid" => $pool_id]);
$images = [];
while ($row = $result->fetch()) {
$images[] = Image::by_id((int)$row["image_id"]);
}
$this->theme->edit_pool($page, $pool, $images);
} else {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
}
break;
case "order": // Order the pool (view and change the order of images within the pool)
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($event->get_POST("order_view")) {
if ($this->have_permission($user, $pool)) {
$result = $database->execute(
"SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order ASC",
["pid" => $pool_id]
);
$images = [];
while ($row = $result->fetch()) {
$image = $database->get_row(
"
SELECT * FROM images AS i
INNER JOIN pool_images AS p ON i.id = p.image_id
WHERE pool_id=:pid AND i.id=:iid",
["pid" => $pool_id, "iid" => (int)$row['image_id']]
);
$images[] = ($image ? new Image($image) : null);
}
$this->theme->edit_order($page, $pool, $images);
} else {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
}
} else {
if ($this->have_permission($user, $pool)) {
foreach ($event->POST as $key => $value) {
if(str_starts_with($key, "order_")) {
$imageID = (int)substr($key, 6);
$database->execute(
"
UPDATE pool_images
SET image_order = :ord
WHERE pool_id = :pid AND image_id = :iid",
["ord" => $value, "pid" => int_escape($event->req_POST('pool_id')), "iid" => $imageID]
);
}
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
}
break;
case "reverse":
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($this->have_permission($user, $pool)) {
$database->with_savepoint(function () use ($pool_id) {
global $database;
$result = $database->execute(
"SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order DESC",
["pid" => $pool_id]
);
$image_order = 1;
while ($row = $result->fetch()) {
$database->execute(
"
UPDATE pool_images
SET image_order=:ord
WHERE pool_id = :pid AND image_id = :iid",
["ord" => $image_order, "pid" => $pool_id, "iid" => (int)$row['image_id']]
);
$image_order = $image_order + 1;
}
});
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
break;
case "import":
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($this->have_permission($user, $pool)) {
$images = Search::find_images(
limit: $config->get_int(PoolsConfig::MAX_IMPORT_RESULTS, 1000),
tags: Tag::explode($event->req_POST("pool_tag"))
while ($row = $result->fetch()) {
$image = $database->get_row(
"
SELECT * FROM images AS i
INNER JOIN pool_images AS p ON i.id = p.image_id
WHERE pool_id=:pid AND i.id=:iid",
["pid" => $pool_id, "iid" => (int) $row['image_id']]
);
$this->theme->pool_result($page, $images, $pool);
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
$images[] = ($image ? new Image($image) : null);
}
break;
case "add_posts":
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($this->have_permission($user, $pool)) {
$image_ids = array_map('intval', $event->req_POST_array('check'));
send_event(new PoolAddPostsEvent($pool_id, $image_ids));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
break;
case "remove_posts":
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($this->have_permission($user, $pool)) {
$images = "";
foreach ($event->req_POST_array('check') as $imageID) {
$this->theme->edit_order($page, $pool, $images);
} else {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
}
} else {
if ($this->have_permission($user, $pool)) {
foreach ($event->POST as $key => $value) {
if (str_starts_with($key, "order_")) {
$imageID = (int) substr($key, 6);
$database->execute(
"DELETE FROM pool_images WHERE pool_id = :pid AND image_id = :iid",
["pid" => $pool_id, "iid" => $imageID]
"
UPDATE pool_images
SET image_order = :ord
WHERE pool_id = :pid AND image_id = :iid",
["ord" => $value, "pid" => int_escape($event->req_POST('pool_id')), "iid" => $imageID]
);
$images .= " " . $imageID;
}
$count = (int)$database->get_one(
"SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid",
["pid" => $pool_id]
);
$this->add_history($pool_id, 0, $images, $count);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
}
}
if ($event->page_matches("pool/reverse")) {
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
break;
case "edit_description":
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($this->have_permission($user, $pool)) {
if ($this->have_permission($user, $pool)) {
$database->with_savepoint(function () use ($pool_id) {
global $database;
$result = $database->execute(
"SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order DESC",
["pid" => $pool_id]
);
$image_order = 1;
while ($row = $result->fetch()) {
$database->execute(
"UPDATE pools SET description=:dsc,lastupdated=CURRENT_TIMESTAMP WHERE id=:pid",
["dsc" => $event->req_POST('description'), "pid" => $pool_id]
"
UPDATE pool_images
SET image_order=:ord
WHERE pool_id = :pid AND image_id = :iid",
["ord" => $image_order, "pid" => $pool_id, "iid" => (int) $row['image_id']]
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
$image_order = $image_order + 1;
}
});
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
}
if ($event->page_matches("pool/import")) {
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
break;
if ($this->have_permission($user, $pool)) {
$images = Search::find_images(
limit: $config->get_int(PoolsConfig::MAX_IMPORT_RESULTS, 1000),
tags: Tag::explode($event->req_POST("pool_tag"))
);
$this->theme->pool_result($page, $images, $pool);
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
}
if ($event->page_matches("pool/add_posts")) {
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
case "nuke":
// Completely remove the given pool.
// -> Only admins and owners may do this
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($this->have_permission($user, $pool)) {
$image_ids = array_map('intval', $event->req_POST_array('check'));
send_event(new PoolAddPostsEvent($pool_id, $image_ids));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
}
if ($event->page_matches("pool/remove_posts")) {
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($user->can(Permissions::POOLS_ADMIN) || $user->id == $pool->user_id) {
send_event(new PoolDeletionEvent($pool_id));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/list"));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
break;
if ($this->have_permission($user, $pool)) {
$images = "";
foreach ($event->req_POST_array('check') as $imageID) {
$database->execute(
"DELETE FROM pool_images WHERE pool_id = :pid AND image_id = :iid",
["pid" => $pool_id, "iid" => $imageID]
);
$images .= " " . $imageID;
}
$count = (int) $database->get_one(
"SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid",
["pid" => $pool_id]
);
$this->add_history($pool_id, 0, $images, $count);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
}
if ($event->page_matches("pool/edit_description")) {
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($this->have_permission($user, $pool)) {
$database->execute(
"UPDATE pools SET description=:dsc,lastupdated=CURRENT_TIMESTAMP WHERE id=:pid",
["dsc" => $event->req_POST('description'), "pid" => $pool_id]
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pool_id));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
}
if ($event->page_matches("pool/nuke")) {
// Completely remove the given pool.
// -> Only admins and owners may do this
$pool_id = int_escape($event->req_POST("pool_id"));
$pool = $this->get_single_pool($pool_id);
if ($user->can(Permissions::POOLS_ADMIN) || $user->id == $pool->user_id) {
send_event(new PoolDeletionEvent($pool_id));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/list"));
} else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
}
}
@ -587,19 +573,19 @@ class Pools extends Extension
$matches = [];
if (preg_match("/^pool[=|:]([^:]*|lastcreated):?([0-9]*)$/i", $event->term, $matches)) {
global $user;
$poolTag = (string)str_replace("_", " ", $matches[1]);
$poolTag = (string) str_replace("_", " ", $matches[1]);
$pool = null;
if ($poolTag == 'lastcreated') {
$pool = $this->get_last_userpool($user->id);
} elseif (ctype_digit($poolTag)) { //If only digits, assume PoolID
$pool = $this->get_single_pool((int)$poolTag);
$pool = $this->get_single_pool((int) $poolTag);
} else { //assume PoolTitle
$pool = $this->get_single_pool_from_title($poolTag);
}
if ($pool && $this->have_permission($user, $pool)) {
$image_order = (int)($matches[2] ?: 0);
$image_order = (int) ($matches[2] ?: 0);
$this->add_post($pool->id, $event->image_id, true, $image_order);
}
}
@ -612,8 +598,8 @@ class Pools extends Extension
$options = $database->get_pairs("SELECT id,title FROM pools ORDER BY title");
// TODO: Don't cast into strings, make BABBE accept HTMLElement instead.
$event->add_action("bulk_pool_add_existing", "Add To (P)ool", "p", "", (string)$this->theme->get_bulk_pool_selector($options));
$event->add_action("bulk_pool_add_new", "Create Pool", "", "", (string)$this->theme->get_bulk_pool_input($event->search_terms));
$event->add_action("bulk_pool_add_existing", "Add To (P)ool", "p", "", (string) $this->theme->get_bulk_pool_selector($options));
$event->add_action("bulk_pool_add_new", "Create Pool", "", "", (string) $this->theme->get_bulk_pool_input($event->search_terms));
}
public function onBulkAction(BulkActionEvent $event): void
@ -680,7 +666,7 @@ class Pools extends Extension
$where_clause = "WHERE LOWER(title) like '%%'";
if ($search != null) {
$where_clause = "WHERE LOWER(title) like '%".strtolower($search)."%'";
$where_clause = "WHERE LOWER(title) like '%" . strtolower($search) . "%'";
}
$pools = array_map([Pool::class, "makePool"], $database->get_all("
@ -692,7 +678,7 @@ class Pools extends Extension
$order_by
LIMIT :l OFFSET :o
", ["l" => $poolsPerPage, "o" => $pageNumber * $poolsPerPage]));
$totalPages = (int)ceil((int)$database->get_one("SELECT COUNT(*) FROM pools ".$where_clause) / $poolsPerPage);
$totalPages = (int) ceil((int) $database->get_one("SELECT COUNT(*) FROM pools " . $where_clause) / $poolsPerPage);
$this->theme->list_pools($page, $pools, $search, $pageNumber + 1, $totalPages);
}
@ -784,7 +770,7 @@ class Pools extends Extension
}
if (count($images) > 0) {
$count = (int)$database->get_one(
$count = (int) $database->get_one(
"SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid",
["pid" => $event->pool_id]
);
@ -839,11 +825,10 @@ class Pools extends Extension
/**
* Retrieve all the images in a pool, given a pool ID.
*/
private function get_posts(PageRequestEvent $event, int $poolID): void
private function get_posts(int $pageNumber, int $poolID): void
{
global $config, $user, $database;
$pageNumber = $event->try_page_num(2);
$pool = $this->get_single_pool($poolID);
$imagesPerPage = $config->get_int(PoolsConfig::IMAGES_PER_PAGE);
@ -856,7 +841,7 @@ class Pools extends Extension
// WE CHECK IF THE EXTENSION RATING IS INSTALLED, WHICH VERSION AND IF IT
// WORKS TO SHOW/HIDE SAFE, QUESTIONABLE, EXPLICIT AND UNRATED IMAGES FROM USER
if (Extension::is_enabled(RatingsInfo::KEY)) {
$query .= "AND i.rating IN (".Ratings::privs_to_sql(Ratings::get_user_class_privs($user)).")";
$query .= "AND i.rating IN (" . Ratings::privs_to_sql(Ratings::get_user_class_privs($user)) . ")";
}
if (Extension::is_enabled(TrashInfo::KEY)) {
$query .= " AND trash != :true";
@ -876,14 +861,14 @@ class Pools extends Extension
] + $params
);
$totalPages = (int)ceil((int)$database->get_one(
$totalPages = (int) ceil((int) $database->get_one(
"SELECT COUNT(*) FROM pool_images p $query",
["pid" => $poolID] + $params
) / $imagesPerPage);
$images = [];
foreach ($result as $singleResult) {
$images[] = Image::by_id((int)$singleResult["image_id"]);
$images[] = Image::by_id((int) $singleResult["image_id"]);
}
$this->theme->view_pool($pool, $images, $pageNumber + 1, $totalPages);
@ -897,7 +882,7 @@ class Pools extends Extension
global $user, $database;
$poolID = $event->pool_id;
$owner_id = (int)$database->get_one("SELECT user_id FROM pools WHERE id = :pid", ["pid" => $poolID]);
$owner_id = (int) $database->get_one("SELECT user_id FROM pools WHERE id = :pid", ["pid" => $poolID]);
if ($owner_id == $user->id || $user->can(Permissions::POOLS_ADMIN)) {
$database->execute("DELETE FROM pool_history WHERE pool_id = :pid", ["pid" => $poolID]);
$database->execute("DELETE FROM pool_images WHERE pool_id = :pid", ["pid" => $poolID]);
@ -940,7 +925,7 @@ class Pools extends Extension
LIMIT :l OFFSET :o
", ["l" => $historiesPerPage, "o" => $pageNumber * $historiesPerPage]);
$totalPages = (int)ceil((int)$database->get_one("SELECT COUNT(*) FROM pool_history") / $historiesPerPage);
$totalPages = (int) ceil((int) $database->get_one("SELECT COUNT(*) FROM pool_history") / $historiesPerPage);
$this->theme->show_history($history, $pageNumber + 1, $totalPages);
}
@ -956,7 +941,7 @@ class Pools extends Extension
foreach ($status as $entry) {
$images = trim($entry['images']);
$images = explode(" ", $images);
$poolID = (int)$entry['pool_id'];
$poolID = (int) $entry['pool_id'];
$imageArray = "";
$newAction = -1;
@ -985,7 +970,7 @@ class Pools extends Extension
continue; // go on to the next one.
}
$count = (int)$database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid" => $poolID]);
$count = (int) $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid" => $poolID]);
$this->add_history($poolID, $newAction, $imageArray, $count);
}
}
@ -998,14 +983,14 @@ class Pools extends Extension
{
global $database, $config;
$result = (int)$database->get_one(
$result = (int) $database->get_one(
"SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid AND image_id=:iid",
["pid" => $poolID, "iid" => $imageID]
);
if ($result == 0) {
if ($config->get_bool(PoolsConfig::AUTO_INCREMENT_ORDER) && $imageOrder === 0) {
$imageOrder = (int)$database->get_one(
$imageOrder = (int) $database->get_one(
"
SELECT COALESCE(MAX(image_order),0) + 1
FROM pool_images
@ -1028,8 +1013,8 @@ class Pools extends Extension
$this->update_count($poolID);
if ($history) {
$count = (int)$database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid" => $poolID]);
$this->add_history($poolID, 1, (string)$imageID, $count);
$count = (int) $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid" => $poolID]);
$this->add_history($poolID, 1, (string) $imageID, $count);
}
return true;
}

View file

@ -43,7 +43,7 @@ class PrivateImage extends Extension
{
global $page, $user, $user_config;
if ($event->page_matches("privatize_image") && $user->can(Permissions::SET_PRIVATE_IMAGE)) {
if ($event->page_matches("privatize_image", method: "POST", permission: Permissions::SET_PRIVATE_IMAGE)) {
// Try to get the image ID
$image_id = int_escape(null_throws($event->get_arg(0)));
$image = Image::by_id($image_id);
@ -59,7 +59,7 @@ class PrivateImage extends Extension
$page->set_redirect(make_link("post/view/" . $image_id));
}
if ($event->page_matches("publicize_image")) {
if ($event->page_matches("publicize_image", method: "POST")) {
// Try to get the image ID
$image_id = int_escape(null_throws($event->get_arg(0)));
$image = Image::by_id($image_id);
@ -75,29 +75,22 @@ class PrivateImage extends Extension
$page->set_redirect(make_link("post/view/".$image_id));
}
if ($event->page_matches("user_admin")) {
if (!$user->check_auth_token()) {
return;
if ($event->page_matches("user_admin/private_image", method: "POST")) {
$id = int_escape($event->req_POST('id'));
if ($id != $user->id) {
throw new SCoreException("Cannot change another user's settings");
}
switch ($event->get_arg(0)) {
case "private_image":
$id = int_escape($event->req_POST('id'));
if ($id != $user->id) {
throw new SCoreException("Cannot change another user's settings");
}
$set_default = array_key_exists("set_default", $event->POST);
$view_default = array_key_exists("view_default", $event->POST);
$set_default = array_key_exists("set_default", $event->POST);
$view_default = array_key_exists("view_default", $event->POST);
$user_config->set_bool(PrivateImageConfig::USER_SET_DEFAULT, $set_default);
$user_config->set_bool(PrivateImageConfig::USER_VIEW_DEFAULT, $view_default);
$user_config->set_bool(PrivateImageConfig::USER_SET_DEFAULT, $set_default);
$user_config->set_bool(PrivateImageConfig::USER_VIEW_DEFAULT, $view_default);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user"));
break;
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user"));
}
}
public function onDisplayingImage(DisplayingImageEvent $event): void
{
global $user, $page;
@ -108,7 +101,6 @@ class PrivateImage extends Extension
}
}
public const SEARCH_REGEXP = "/^private:(yes|no|any)/";
public function onSearchTermParse(SearchTermParseEvent $event): void
{

View file

@ -374,27 +374,23 @@ class Ratings extends Extension
{
global $user, $page;
if ($event->page_matches("admin/bulk_rate")) {
if (!$user->can(Permissions::BULK_EDIT_IMAGE_RATING)) {
throw new PermissionDeniedException("Permission denied");
} else {
$n = 0;
while (true) {
$images = Search::find_images($n, 100, Tag::explode($event->req_POST("query")));
if (count($images) == 0) {
break;
}
reset($images); // rewind to first element in array.
foreach ($images as $image) {
send_event(new RatingSetEvent($image, $event->req_POST('rating')));
}
$n += 100;
if ($event->page_matches("admin/bulk_rate", method: "POST", permission: Permissions::BULK_EDIT_IMAGE_RATING)) {
$n = 0;
while (true) {
$images = Search::find_images($n, 100, Tag::explode($event->req_POST("query")));
if (count($images) == 0) {
break;
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link());
reset($images); // rewind to first element in array.
foreach ($images as $image) {
send_event(new RatingSetEvent($image, $event->req_POST('rating')));
}
$n += 100;
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link());
}
}

View file

@ -21,8 +21,8 @@ class RegenThumb extends Extension
{
global $page, $user;
if ($event->page_matches("regen_thumb") && $user->can(Permissions::DELETE_IMAGE)) {
if ($event->authed_page_matches("regen_thumb/one")) {
if ($event->page_matches("regen_thumb", method: "POST", permission: Permissions::DELETE_IMAGE)) {
if ($event->page_matches("regen_thumb/one")) {
$image = Image::by_id(int_escape($event->get_arg(0)));
$this->regenerate_thumbnail($image);

View file

@ -13,12 +13,7 @@ class ReplaceFile extends Extension
{
global $cache, $page, $user;
if ($event->page_matches("replace")) {
if (!$user->can(Permissions::REPLACE_IMAGE)) {
$this->theme->display_error(403, "Error", "{$user->name} doesn't have permission to replace images");
return;
}
if ($event->page_matches("replace", permission: Permissions::REPLACE_IMAGE)) {
$image_id = int_escape($event->get_arg(0));
$image = Image::by_id($image_id);
if (is_null($image)) {
@ -28,6 +23,7 @@ class ReplaceFile extends Extension
if($event->method == "GET") {
$this->theme->display_replace_page($page, $image_id);
} elseif($event->method == "POST") {
$user->ensure_authed();
if (!empty($event->get_POST("url"))) {
$tmp_filename = shm_tempnam("transload");
fetch_url($event->req_POST("url"), $tmp_filename);

View file

@ -52,27 +52,24 @@ class ReportImage extends Extension
{
global $page, $user;
if ($event->page_matches("image_report")) {
if ($event->get_arg(0) == "add") {
if ($event->page_matches("image_report/add")) {
$image_id = int_escape($event->req_POST('image_id'));
send_event(new AddReportedImageEvent(new ImageReport($image_id, $user->id, $event->req_POST('reason'))));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id"));
} elseif ($event->get_arg(0) == "remove") {
if ($user->can(Permissions::VIEW_IMAGE_REPORT)) {
send_event(new RemoveReportedImageEvent(int_escape($event->req_POST('id'))));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("image_report/list"));
}
} elseif ($event->get_arg(0) == "remove_reports_by" && $user->check_auth_token()) {
if ($user->can(Permissions::VIEW_IMAGE_REPORT)) {
$this->delete_reports_by(int_escape($event->req_POST('user_id')));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link());
}
} elseif ($event->get_arg(0) == "list") {
if ($user->can(Permissions::VIEW_IMAGE_REPORT)) {
$this->theme->display_reported_images($page, $this->get_reported_images());
}
}
if ($event->page_matches("image_report/remove", method: "POST", permission: Permissions::VIEW_IMAGE_REPORT)) {
send_event(new RemoveReportedImageEvent(int_escape($event->req_POST('id'))));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("image_report/list"));
}
if ($event->page_matches("image_report/remove_reports_by", method: "POST", permission: Permissions::VIEW_IMAGE_REPORT)) {
$this->delete_reports_by(int_escape($event->req_POST('user_id')));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link());
}
if ($event->page_matches("image_report/list", permission: Permissions::VIEW_IMAGE_REPORT)) {
$this->theme->display_reported_images($page, $this->get_reported_images());
}
}
}

View file

@ -141,7 +141,7 @@ class ResizeImage extends Extension
{
global $page, $user;
if ($event->authed_page_matches("resize") && $user->can(Permissions::EDIT_FILES)) {
if ($event->page_matches("resize", method: "POST", permission: Permissions::EDIT_FILES)) {
// Try to get the image ID
$image_id = int_escape(null_throws($event->get_arg(0)));
$image = Image::by_id($image_id);

View file

@ -59,7 +59,7 @@ class RotateImage extends Extension
{
global $page, $user;
if ($event->authed_page_matches("rotate") && $user->can(Permissions::EDIT_FILES)) {
if ($event->page_matches("rotate", method: "POST", permission: Permissions::EDIT_FILES)) {
// Try to get the image ID
$image_id = int_escape(null_throws($event->get_arg(0)));
$image = Image::by_id($image_id);

View file

@ -129,10 +129,7 @@ class S3 extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $config, $page, $user;
if (
$event->authed_page_matches("s3/sync") &&
$user->can(Permissions::DELETE_IMAGE)
) {
if ($event->page_matches("s3/sync", method: "POST", permission: Permissions::DELETE_IMAGE)) {
$id = int_escape($event->get_arg(0));
$this->sync_post(Image::by_id($id));
log_info("s3", "Manual resync for >>$id", "File re-sync'ed");

View file

@ -336,23 +336,19 @@ class Setup extends Extension
$page->set_data("ok");
}
if ($event->page_matches("setup")) {
if (!$user->can(Permissions::CHANGE_SETTING)) {
$this->theme->display_permission_denied();
} else {
if ($event->count_args() == 0) {
$panel = new SetupPanel($config);
send_event(new SetupBuildingEvent($panel));
$this->theme->display_page($page, $panel);
} elseif ($event->get_arg(0) == "save" && $user->check_auth_token()) {
send_event(new ConfigSaveEvent($config, $event->POST));
$config->save();
$page->flash("Config saved");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("setup"));
} elseif ($event->get_arg(0) == "advanced") {
$this->theme->display_advanced($page, $config->values);
}
if ($event->page_matches("setup", permission: Permissions::CHANGE_SETTING)) {
if ($event->count_args() == 0) {
$panel = new SetupPanel($config);
send_event(new SetupBuildingEvent($panel));
$this->theme->display_page($page, $panel);
} elseif ($event->get_arg(0) == "save" && $user->check_auth_token()) {
send_event(new ConfigSaveEvent($config, $event->POST));
$config->save();
$page->flash("Config saved");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("setup"));
} elseif ($event->get_arg(0) == "advanced") {
$this->theme->display_advanced($page, $config->values);
}
}
}

View file

@ -18,17 +18,17 @@ class SetupTest extends ShimmiePHPUnitTestCase
public function testAuthAnon(): void
{
$this->get_page('setup');
$this->assert_response(403);
$this->assert_title("Permission Denied");
$this->assertException(PermissionDeniedException::class, function () {
$this->get_page('setup');
});
}
public function testAuthUser(): void
{
$this->log_in_as_user();
$this->get_page('setup');
$this->assert_response(403);
$this->assert_title("Permission Denied");
$this->assertException(PermissionDeniedException::class, function () {
$this->get_page('setup');
});
}
public function testAuthAdmin(): void

View file

@ -32,15 +32,11 @@ class SourceHistory extends Extension
{
global $page, $user;
if ($event->page_matches("source_history/revert")) {
if ($event->page_matches("source_history/revert", method: "POST", permission: Permissions::EDIT_IMAGE_TAG)) {
// this is a request to revert to a previous version of the source
if ($user->can(Permissions::EDIT_IMAGE_TAG)) {
$this->process_revert_request((int)$event->req_POST('revert'));
}
} elseif ($event->page_matches("source_history/bulk_revert")) {
if ($user->can(Permissions::BULK_EDIT_IMAGE_TAG) && $user->check_auth_token()) {
$this->process_bulk_revert_request();
}
$this->process_revert_request((int)$event->req_POST('revert'));
} elseif ($event->page_matches("source_history/bulk_revert", method: "POST", permission: Permissions::BULK_EDIT_IMAGE_TAG)) {
$this->process_bulk_revert_request();
} elseif ($event->page_matches("source_history/all")) {
$page_id = int_escape($event->get_arg(0));
$this->theme->display_global_page($page, $this->get_global_source_history($page_id), $page_id);

View file

@ -69,11 +69,11 @@ class TagCategories extends Extension
{
global $database, $page, $user;
if ($event->page_matches("tags/categories")) {
if ($user->can(Permissions::EDIT_TAG_CATEGORIES)) {
$this->page_update();
$this->theme->show_tag_categories($page, $database->get_all('SELECT * FROM image_tag_categories'));
}
if ($event->page_matches("tags/categories", method: "GET")) {
$this->theme->show_tag_categories($page, $database->get_all('SELECT * FROM image_tag_categories'));
}
if ($event->page_matches("tags/categories", method: "POST", permission: Permissions::EDIT_TAG_CATEGORIES)) {
$this->page_update();
}
}

View file

@ -146,22 +146,18 @@ class TagEdit extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $user, $page;
if ($event->page_matches("tag_edit")) {
if ($event->page_matches("tag_edit", method: "POST", permission: Permissions::MASS_TAG_EDIT)) {
if ($event->get_arg(0) == "replace") {
if ($user->can(Permissions::MASS_TAG_EDIT)) {
$search = $event->req_POST('search');
$replace = $event->req_POST('replace');
$this->mass_tag_edit($search, $replace, true);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin"));
}
$search = $event->req_POST('search');
$replace = $event->req_POST('replace');
$this->mass_tag_edit($search, $replace, true);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin"));
}
if ($event->get_arg(0) == "mass_source_set") {
if ($user->can(Permissions::MASS_TAG_EDIT)) {
$this->mass_source_edit($event->req_POST('tags'), $event->req_POST('source'));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(search_link());
}
$this->mass_source_edit($event->req_POST('tags'), $event->req_POST('source'));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(search_link());
}
}
}

View file

@ -26,15 +26,11 @@ class TagHistory extends Extension
{
global $page, $user;
if ($event->page_matches("tag_history/revert")) {
if ($event->page_matches("tag_history/revert", method: "POST", permission: Permissions::EDIT_IMAGE_TAG)) {
// this is a request to revert to a previous version of the tags
if ($user->can(Permissions::EDIT_IMAGE_TAG)) {
$this->process_revert_request((int)$event->req_POST('revert'));
}
} elseif ($event->page_matches("tag_history/bulk_revert")) {
if ($user->can(Permissions::BULK_EDIT_IMAGE_TAG) && $user->check_auth_token()) {
$this->process_bulk_revert_request();
}
$this->process_revert_request((int)$event->req_POST('revert'));
} elseif ($event->page_matches("tag_history/bulk_revert", method: "POST", permission: Permissions::BULK_EDIT_IMAGE_TAG)) {
$this->process_bulk_revert_request();
} elseif ($event->page_matches("tag_history/all")) {
$page_id = int_escape($event->get_arg(0));
$this->theme->display_global_page($page, $this->get_global_tag_history($page_id), $page_id);

View file

@ -67,38 +67,32 @@ class Tips extends Extension
$this->getTip();
if ($event->page_matches("tips") && $user->can(Permissions::TIPS_ADMIN)) {
switch ($event->get_arg(0)) {
case "list":
$this->manageTips();
$this->getAll();
break;
case "save":
if ($user->check_auth_token()) {
send_event(new CreateTipEvent(
$event->get_POST("enable") == "on",
$event->req_POST("image"),
$event->req_POST("text")
));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("tips/list"));
}
break;
case "status":
// FIXME: HTTP GET CSRF
$tipID = int_escape($event->get_arg(1));
$this->setStatus($tipID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("tips/list"));
break;
case "delete":
// FIXME: HTTP GET CSRF
$tipID = int_escape($event->get_arg(1));
send_event(new DeleteTipEvent($tipID));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("tips/list"));
break;
}
if ($event->page_matches("tips/list", permission: Permissions::TIPS_ADMIN)) {
$this->manageTips();
$this->getAll();
}
if ($event->page_matches("tips/save", method: "POST", permission: Permissions::TIPS_ADMIN)) {
send_event(new CreateTipEvent(
$event->get_POST("enable") == "on",
$event->req_POST("image"),
$event->req_POST("text")
));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("tips/list"));
}
if ($event->page_matches("tips/status", permission: Permissions::TIPS_ADMIN)) {
// FIXME: HTTP GET CSRF
$tipID = int_escape($event->get_arg(1));
$this->setStatus($tipID);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("tips/list"));
}
if ($event->page_matches("tips/delete", permission: Permissions::TIPS_ADMIN)) {
// FIXME: HTTP GET CSRF
$tipID = int_escape($event->get_arg(1));
send_event(new DeleteTipEvent($tipID));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("tips/list"));
}
}

View file

@ -207,7 +207,7 @@ class TranscodeImage extends Extension
{
global $page, $user;
if ($event->page_matches("transcode") && $user->can(Permissions::EDIT_FILES)) {
if ($event->page_matches("transcode", method: "POST", permission: Permissions::EDIT_FILES)) {
$image_id = int_escape($event->get_arg(0));
$image_obj = Image::by_id($image_id);
if (is_null($image_obj)) {

View file

@ -101,7 +101,7 @@ class TranscodeVideo extends Extension
{
global $page, $user;
if ($event->page_matches("transcode_video") && $user->can(Permissions::EDIT_FILES)) {
if ($event->page_matches("transcode_video", method: "POST", permission: Permissions::EDIT_FILES)) {
$image_id = int_escape($event->get_arg(0));
$image_obj = Image::by_id($image_id);
if (is_null($image_obj)) {

View file

@ -29,7 +29,7 @@ class Trash extends Extension
{
global $page, $user;
if ($event->page_matches("trash_restore") && $user->can(Permissions::VIEW_TRASH)) {
if ($event->page_matches("trash_restore", method: "POST", permission: Permissions::VIEW_TRASH)) {
$image_id = int_escape(null_throws($event->get_arg(0)));
self::set_trash($image_id, false);
$page->set_mode(PageMode::REDIRECT);

View file

@ -36,27 +36,29 @@ class Update extends Extension
global $user, $page;
$sha = $event->get_GET('sha');
if ($user->can(Permissions::EDIT_FILES) && $sha) {
if ($event->page_matches("update/download")) {
$ok = $this->download_shimmie($sha);
// FIXME: use POST
if ($event->page_matches("update/download", permission: Permissions::EDIT_FILES)) {
assert(!is_null($sha));
$ok = $this->download_shimmie($sha);
$page->set_mode(PageMode::REDIRECT);
if ($ok) {
$page->set_redirect(make_link("update/update", "sha=".$sha));
} else {
$page->set_redirect(make_link("admin"));
} //TODO: Show error?
} elseif ($event->page_matches("update/update")) {
$ok = $this->update_shimmie($sha);
$page->set_mode(PageMode::REDIRECT);
if ($ok) {
$page->set_redirect(make_link("update/update", "sha=".$sha));
} else {
$page->set_redirect(make_link("admin"));
} //TODO: Show error?
}
if ($event->page_matches("update/update", permission: Permissions::EDIT_FILES)) {
assert(!is_null($sha));
$ok = $this->update_shimmie($sha);
$page->set_mode(PageMode::REDIRECT);
if ($ok) {
$page->set_redirect(make_link("admin"));
} //TODO: Show success?
else {
$page->set_redirect(make_link("admin"));
} //TODO: Show error?
}
$page->set_mode(PageMode::REDIRECT);
if ($ok) {
$page->set_redirect(make_link("admin"));
} //TODO: Show success?
else {
$page->set_redirect(make_link("admin"));
} //TODO: Show error?
}
}

View file

@ -216,11 +216,7 @@ class Upload extends Extension
}
}
if ($event->page_matches("upload")) {
if (!$user->can(Permissions::CREATE_IMAGE)) {
$this->theme->display_error(403, "Error", "{$user->name} doesn't have permission to upload images");
return;
}
if ($event->page_matches("upload", permission: Permissions::CREATE_IMAGE)) {
if ($this->is_full) {
$this->theme->display_error(507, "Error", "Can't upload images: disk nearly full");
return;

View file

@ -165,92 +165,154 @@ class UserPage extends Extension
if ($user->can(Permissions::VIEW_HELLBANNED)) {
$page->add_html_header("<style>DIV.hb, TR.hb TD {border: 1px solid red !important;}</style>");
} elseif(!$user->can(Permissions::HELLBANNED)) {
} elseif (!$user->can(Permissions::HELLBANNED)) {
$page->add_html_header("<style>.hb {display: none !important;}</style>");
}
if ($event->page_matches("user_admin")) {
if ($event->get_arg(0) == "login") {
if ($event->method == "POST") {
$this->page_login($event->req_POST('user'), $event->req_POST('pass'));
} else {
$this->theme->display_login_page($page);
}
} elseif ($event->get_arg(0) == "recover") {
$this->page_recover($event->req_POST('username'));
} elseif ($event->get_arg(0) == "create") {
$this->page_create($event);
} elseif ($event->get_arg(0) == "create_other") {
send_event(new UserCreationEvent(
if ($event->page_matches("user_admin/login", method: "GET")) {
$this->theme->display_login_page($page);
}
if ($event->page_matches("user_admin/login", method: "POST", authed: false)) {
$this->page_login($event->req_POST('user'), $event->req_POST('pass'));
}
if ($event->page_matches("user_admin/recover", method: "POST")) {
$this->page_recover($event->req_POST('username'));
}
if ($event->page_matches("user_admin/create", method: "GET", permission: Permissions::CREATE_USER)) {
global $config, $page, $user;
if (!$config->get_bool("login_signup_enabled")) {
$this->theme->display_signups_disabled($page);
return;
}
$this->theme->display_signup_page($page);
}
if ($event->page_matches("user_admin/create", method: "POST", authed: false, permission: Permissions::CREATE_USER)) {
global $config, $page, $user;
if (!$config->get_bool("login_signup_enabled")) {
$this->theme->display_signups_disabled($page);
return;
}
try {
$uce = send_event(
new UserCreationEvent(
$event->req_POST('name'),
$event->req_POST('pass1'),
$event->req_POST('pass2'),
$event->req_POST('email'),
true
)
);
$this->set_login_cookie($uce->username);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user"));
} catch (UserCreationException $ex) {
$this->theme->display_error(400, "User Creation Error", $ex->getMessage());
}
}
if ($event->page_matches("user_admin/create_other", method: "POST", permission: Permissions::CREATE_OTHER_USER)) {
send_event(
new UserCreationEvent(
$event->req_POST("name"),
$event->req_POST("pass1"),
$event->req_POST("pass1"),
$event->req_POST("email"),
false
));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin"));
$page->flash("Created new user");
} elseif ($event->get_arg(0) == "list") {
$t = new UserTable($database->raw_db());
$t->token = $user->get_auth_token();
$t->inputs = $event->GET;
if ($user->can(Permissions::DELETE_USER)) {
$col = new TextColumn("email", "Email");
// $t->columns[] = $col;
array_splice($t->columns, 2, 0, [$col]);
}
$this->theme->display_crud("Users", $t->table($t->query()), $t->paginator());
} elseif ($event->get_arg(0) == "classes") {
$this->theme->display_user_classes(
$page,
UserClass::$known_classes,
(new \ReflectionClass(Permissions::class))->getReflectionConstants()
);
} elseif ($event->get_arg(0) == "logout") {
$this->page_logout();
)
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin"));
$page->flash("Created new user");
}
if ($event->page_matches("user_admin/list", method: "GET")) {
$t = new UserTable($database->raw_db());
$t->token = $user->get_auth_token();
$t->inputs = $event->GET;
if ($user->can(Permissions::DELETE_USER)) {
$col = new TextColumn("email", "Email");
// $t->columns[] = $col;
array_splice($t->columns, 2, 0, [$col]);
}
$this->theme->display_crud("Users", $t->table($t->query()), $t->paginator());
}
if ($event->page_matches("user_admin/classes", method: "GET")) {
$this->theme->display_user_classes(
$page,
UserClass::$known_classes,
(new \ReflectionClass(Permissions::class))->getReflectionConstants()
);
}
if ($event->page_matches("user_admin/logout", method: "GET")) {
// FIXME: security
$this->page_logout();
}
if (!$user->check_auth_token()) {
return;
} elseif ($event->get_arg(0) == "change_name") {
$input = validate_input([
'id' => 'user_id,exists',
'name' => 'user_name',
]);
$duser = User::by_id($input['id']);
$this->change_name_wrapper($duser, $input['name']);
} elseif ($event->get_arg(0) == "change_pass") {
$input = validate_input([
'id' => 'user_id,exists',
'pass1' => 'password',
'pass2' => 'password',
]);
$duser = User::by_id($input['id']);
$this->change_password_wrapper($duser, $input['pass1'], $input['pass2']);
} elseif ($event->get_arg(0) == "change_email") {
$input = validate_input([
'id' => 'user_id,exists',
'address' => 'email',
]);
$duser = User::by_id($input['id']);
$this->change_email_wrapper($duser, $input['address']);
} elseif ($event->get_arg(0) == "change_class") {
$input = validate_input([
'id' => 'user_id,exists',
'class' => 'user_class',
]);
$duser = User::by_id($input['id']);
$this->change_class_wrapper($duser, $input['class']);
} elseif ($event->get_arg(0) == "delete_user") {
$this->delete_user(
$page,
int_escape($event->req_POST('id')),
$event->get_POST("with_images") == "on",
$event->get_POST("with_comments") == "on"
);
if ($event->page_matches("user_admin/change_name", method: "POST", permission: Permissions::EDIT_USER_NAME)) {
$input = validate_input([
'id' => 'user_id,exists',
'name' => 'user_name',
]);
$duser = User::by_id($input['id']);
if ($this->user_can_edit_user($user, $duser)) {
$duser->set_name($input['name']);
$page->flash("Username changed");
// TODO: set login cookie if user changed themselves
$this->redirect_to_user($duser);
}
}
if ($event->page_matches("user_admin/change_pass", method: "POST")) {
$input = validate_input([
'id' => 'user_id,exists',
'pass1' => 'password',
'pass2' => 'password',
]);
$duser = User::by_id($input['id']);
if ($this->user_can_edit_user($user, $duser)) {
if ($input['pass1'] != $input['pass2']) {
throw new UserErrorException("Passwords don't match");
} else {
// FIXME: send_event()
$duser->set_password($input['pass1']);
if ($duser->id == $user->id) {
$this->set_login_cookie($duser->name);
}
$page->flash("Password changed");
$this->redirect_to_user($duser);
}
}
}
if ($event->page_matches("user_admin/change_email", method: "POST")) {
$input = validate_input([
'id' => 'user_id,exists',
'address' => 'email',
]);
$duser = User::by_id($input['id']);
if ($this->user_can_edit_user($user, $duser)) {
$duser->set_email($input['address']);
$page->flash("Email changed");
$this->redirect_to_user($duser);
}
}
if ($event->page_matches("user_admin/change_class", method: "POST")) {
$input = validate_input([
'id' => 'user_id,exists',
'class' => 'user_class',
]);
$duser = User::by_id($input['id']);
// hard-coded that only admins can change people's classes
if ($user->class->name == "admin") {
$duser->set_class($input['class']);
$page->flash("Class changed");
$this->redirect_to_user($duser);
}
}
if ($event->page_matches("user_admin/delete_user", method: "POST", permission: Permissions::DELETE_USER)) {
$this->delete_user(
$page,
int_escape($event->req_POST('id')),
$event->get_POST("with_images") == "on",
$event->get_POST("with_comments") == "on"
);
}
if ($event->page_matches("user")) {
$display_user = ($event->count_args() == 0) ? $user : User::by_name($event->get_arg(0));
@ -267,7 +329,7 @@ class UserPage extends Extension
$this->theme->display_error(
404,
"No Such User",
"If you typed the ID by hand, try again; if you came from a link on this ".
"If you typed the ID by hand, try again; if you came from a link on this " .
"site, it might be bug report time..."
);
}
@ -294,13 +356,14 @@ class UserPage extends Extension
$av = $event->display_user->get_avatar_html();
if ($av) {
$event->add_stats($av, 0);
} elseif ((
$config->get_string("avatar_host") == "gravatar"
) &&
} elseif (
(
$config->get_string("avatar_host") == "gravatar"
) &&
($user->id == $event->display_user->id)
) {
$event->add_stats(
"No avatar? This gallery uses <a href='https://gravatar.com'>Gravatar</a> for avatar hosting, use the".
"No avatar? This gallery uses <a href='https://gravatar.com'>Gravatar</a> for avatar hosting, use the" .
"<br>same email address here and there to have your avatar synced<br>",
0
);
@ -459,8 +522,8 @@ class UserPage extends Extension
}
if (!preg_match('/^[a-zA-Z0-9-_]+$/', $name)) {
throw new UserCreationException(
"Username contains invalid characters. Allowed characters are ".
"letters, numbers, dash, and underscore"
"Username contains invalid characters. Allowed characters are " .
"letters, numbers, dash, and underscore"
);
}
if (User::by_name($name)) {
@ -472,7 +535,7 @@ class UserPage extends Extension
if ($event->password != $event->password2) {
throw new UserCreationException("Passwords don't match");
}
if(
if (
// Users who can create other users (ie, admins) are exempt
// from the email requirement
!$user->can(Permissions::CREATE_OTHER_USER) &&
@ -496,8 +559,10 @@ class UserPage extends Extension
public static function has_user_query(array $context): bool
{
foreach ($context as $term) {
if (preg_match(self::USER_SEARCH_REGEX, $term) ||
preg_match(self::USER_ID_SEARCH_REGEX, $term)) {
if (
preg_match(self::USER_SEARCH_REGEX, $term) ||
preg_match(self::USER_ID_SEARCH_REGEX, $term)
) {
return true;
}
}
@ -517,7 +582,7 @@ class UserPage extends Extension
$duser = User::by_name($matches[2]);
if (is_null($duser)) {
throw new SearchTermParseException(
"Can't find the user named ".html_escape($matches[2])
"Can't find the user named " . html_escape($matches[2])
);
}
$event->add_querylet(new Querylet("images.owner_id {$matches[1]}= {$duser->id}"));
@ -535,7 +600,7 @@ class UserPage extends Extension
if ($event->key === HelpPages::SEARCH) {
$block = new Block();
$block->header = "Users";
$block->body = (string)$this->theme->get_help_html();
$block->body = (string) $this->theme->get_help_html();
$event->add_block($block);
}
}
@ -606,38 +671,6 @@ class UserPage extends Extension
}
}
private function page_create(PageRequestEvent $event): void
{
global $config, $page, $user;
if (!$user->can(Permissions::CREATE_USER)) {
$this->theme->display_error(403, "Account creation blocked", "Account creation is currently disabled");
return;
}
if (!$config->get_bool("login_signup_enabled")) {
$this->theme->display_signups_disabled($page);
return;
}
if ($event->method == "GET") {
$this->theme->display_signup_page($page);
} else {
try {
$uce = send_event(new UserCreationEvent(
$event->req_POST('name'),
$event->req_POST('pass1'),
$event->req_POST('pass2'),
$event->req_POST('email'),
true
));
$this->set_login_cookie($uce->username);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user"));
} catch (UserCreationException $ex) {
$this->theme->display_error(400, "User Creation Error", $ex->getMessage());
}
}
}
private function create_user(UserCreationEvent $event): User
{
global $database;
@ -666,7 +699,7 @@ class UserPage extends Extension
global $config;
$addr = get_session_ip($config);
$hash = User::by_name($name)->passhash;
return md5($hash.$addr);
return md5($hash . $addr);
}
private function set_login_cookie(string $name): void
@ -720,64 +753,6 @@ class UserPage extends Extension
}
}
private function change_name_wrapper(User $duser, string $name): void
{
global $page, $user;
if ($user->can(Permissions::EDIT_USER_NAME) && $this->user_can_edit_user($user, $duser)) {
$duser->set_name($name);
$page->flash("Username changed");
// TODO: set login cookie if user changed themselves
$this->redirect_to_user($duser);
} else {
$this->theme->display_error(400, "Error", "Permission denied");
}
}
private function change_password_wrapper(User $duser, string $pass1, string $pass2): void
{
global $page, $user;
if ($this->user_can_edit_user($user, $duser)) {
if ($pass1 != $pass2) {
$this->theme->display_error(400, "Error", "Passwords don't match");
} else {
// FIXME: send_event()
$duser->set_password($pass1);
if ($duser->id == $user->id) {
$this->set_login_cookie($duser->name);
}
$page->flash("Password changed");
$this->redirect_to_user($duser);
}
}
}
private function change_email_wrapper(User $duser, string $address): void
{
global $page, $user;
if ($this->user_can_edit_user($user, $duser)) {
$duser->set_email($address);
$page->flash("Email changed");
$this->redirect_to_user($duser);
}
}
private function change_class_wrapper(User $duser, string $class): void
{
global $page, $user;
if ($user->class->name == "admin") {
$duser->set_class($class);
$page->flash("Class changed");
$this->redirect_to_user($duser);
}
}
/**
* @return array<string, int>
*/
@ -837,47 +812,43 @@ class UserPage extends Extension
$page->set_heading("Error");
$page->add_block(new NavBlock());
if (!$user->can(Permissions::DELETE_USER)) {
$page->add_block(new Block("Not Admin", "Only admins can delete accounts"));
} else {
$duser = User::by_id($uid);
log_warning("user", "Deleting user #{$uid} (@{$duser->name})");
$duser = User::by_id($uid);
log_warning("user", "Deleting user #{$uid} (@{$duser->name})");
if ($with_images) {
log_warning("user", "Deleting user #{$uid} (@{$duser->name})'s uploads");
$image_ids = $database->get_col("SELECT id FROM images WHERE owner_id = :owner_id", ["owner_id" => $uid]);
foreach ($image_ids as $image_id) {
$image = Image::by_id((int)$image_id);
if ($image) {
send_event(new ImageDeletionEvent($image));
}
if ($with_images) {
log_warning("user", "Deleting user #{$uid} (@{$duser->name})'s uploads");
$image_ids = $database->get_col("SELECT id FROM images WHERE owner_id = :owner_id", ["owner_id" => $uid]);
foreach ($image_ids as $image_id) {
$image = Image::by_id((int) $image_id);
if ($image) {
send_event(new ImageDeletionEvent($image));
}
} else {
$database->execute(
"UPDATE images SET owner_id = :new_owner_id WHERE owner_id = :old_owner_id",
["new_owner_id" => $config->get_int('anon_id'), "old_owner_id" => $uid]
);
}
if ($with_comments) {
log_warning("user", "Deleting user #{$uid} (@{$duser->name})'s comments");
$database->execute("DELETE FROM comments WHERE owner_id = :owner_id", ["owner_id" => $uid]);
} else {
$database->execute(
"UPDATE comments SET owner_id = :new_owner_id WHERE owner_id = :old_owner_id",
["new_owner_id" => $config->get_int('anon_id'), "old_owner_id" => $uid]
);
}
send_event(new UserDeletionEvent($uid));
} else {
$database->execute(
"DELETE FROM users WHERE id = :id",
["id" => $uid]
"UPDATE images SET owner_id = :new_owner_id WHERE owner_id = :old_owner_id",
["new_owner_id" => $config->get_int('anon_id'), "old_owner_id" => $uid]
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link());
}
if ($with_comments) {
log_warning("user", "Deleting user #{$uid} (@{$duser->name})'s comments");
$database->execute("DELETE FROM comments WHERE owner_id = :owner_id", ["owner_id" => $uid]);
} else {
$database->execute(
"UPDATE comments SET owner_id = :new_owner_id WHERE owner_id = :old_owner_id",
["new_owner_id" => $config->get_int('anon_id'), "old_owner_id" => $uid]
);
}
send_event(new UserDeletionEvent($uid));
$database->execute(
"DELETE FROM users WHERE id = :id",
["id" => $uid]
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link());
}
}

View file

@ -58,7 +58,7 @@ class UserPageTest extends ShimmiePHPUnitTestCase
{
global $page;
$this->assertException(UserCreationException::class, function () {
$this->assertException(PermissionDeniedException::class, function () {
$this->log_out();
$this->post_page('user_admin/create_other', [
'name' => 'testnew',

View file

@ -125,47 +125,34 @@ class UserConfig extends Extension
}
}
if ($event->page_matches("user_admin")) {
if (!$user->check_auth_token()) {
return;
}
switch ($event->get_arg(0)) {
case "reset_api_key":
$user_config->set_string(self::API_KEY, "");
if ($event->page_matches("user_admin/reset_api_key", method: "POST")) {
$user_config->set_string(self::API_KEY, "");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user"));
break;
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user"));
}
}
if ($event->page_matches("user_config")) {
if (!$user->can(Permissions::CHANGE_USER_SETTING)) {
$this->theme->display_permission_denied();
} else {
if ($event->count_args() == 0) {
$uobe = send_event(new UserOptionsBuildingEvent($user, new SetupPanel($user_config)));
$this->theme->display_user_config_page($page, $uobe->user, $uobe->panel);
} elseif ($event->get_arg(0) == "save" && $user->check_auth_token()) {
$input = validate_input([
'id' => 'user_id,exists'
]);
$duser = User::by_id($input['id']);
if ($event->page_matches("user_config", permission: Permissions::CHANGE_USER_SETTING)) {
if ($event->count_args() == 0) {
$uobe = send_event(new UserOptionsBuildingEvent($user, new SetupPanel($user_config)));
$this->theme->display_user_config_page($page, $uobe->user, $uobe->panel);
} elseif ($event->get_arg(0) == "save" && $user->check_auth_token()) {
$input = validate_input([
'id' => 'user_id,exists'
]);
$duser = User::by_id($input['id']);
if ($user->id != $duser->id && !$user->can(Permissions::CHANGE_OTHER_USER_SETTING)) {
$this->theme->display_permission_denied();
return;
}
$target_config = UserConfig::get_for_user($duser->id);
send_event(new ConfigSaveEvent($target_config, $event->POST));
$target_config->save();
$page->flash("Config saved");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user_config"));
if ($user->id != $duser->id && !$user->can(Permissions::CHANGE_OTHER_USER_SETTING)) {
throw new PermissionDeniedException("You do not have permission to change other user's settings");
}
$target_config = UserConfig::get_for_user($duser->id);
send_event(new ConfigSaveEvent($target_config, $event->POST));
$target_config->save();
$page->flash("Config saved");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user_config"));
}
}
}

View file

@ -10,9 +10,9 @@ class UserConfigTest extends ShimmiePHPUnitTestCase
public function testUserConfigPage(): void
{
$this->get_page('user_config');
$this->assert_title("Permission Denied");
$this->assert_no_text(self::OPTIONS_BLOCK_TITLE);
$this->assertException(PermissionDeniedException::class, function () {
$this->get_page('user_config');
});
$this->log_in_as_user();
$this->get_page('user_config');

View file

@ -72,7 +72,7 @@ class ViewPost extends Extension
} else {
$this->theme->display_error(404, "Post not found", "No post in the database has the ID #$image_id");
}
} elseif ($event->page_matches("post/set")) {
} elseif ($event->page_matches("post/set", method: "POST")) {
$image_id = int_escape($event->req_POST('image_id'));
$image = Image::by_id($image_id);
if (!$image->is_locked() || $user->can(Permissions::EDIT_IMAGE_LOCK)) {

View file

@ -197,7 +197,7 @@ class Wiki extends Extension
if ($this->can_edit($user, $content)) {
$this->theme->display_page_editor($page, $content);
} else {
$this->theme->display_permission_denied();
throw new PermissionDeniedException("You are not allowed to edit this page");
}
} elseif($action == "save" && $user->check_auth_token()) {
$rev = int_escape($event->req_POST('revision'));
@ -214,7 +214,7 @@ class Wiki extends Extension
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("wiki/$u_title"));
} else {
$this->theme->display_permission_denied();
throw new PermissionDeniedException("You are not allowed to edit this page");
}
} elseif($action == "delete_revision" && $user->check_auth_token()) {
$content = $this->get_page($title);
@ -225,7 +225,7 @@ class Wiki extends Extension
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("wiki/$u_title"));
} else {
$this->theme->display_permission_denied();
throw new PermissionDeniedException("You are not allowed to edit this page");
}
} elseif($action == "delete_all" && $user->check_auth_token()) {
if ($user->can(Permissions::WIKI_ADMIN)) {

View file

@ -22,8 +22,9 @@ class WikiTest extends ShimmiePHPUnitTestCase
$this->assert_title("test");
$this->assert_text("This is a default page");
$this->get_page("wiki/test/edit");
$this->assert_no_text("Editor");
$this->assertException(PermissionDeniedException::class, function () {
$this->get_page("wiki/test/edit");
});
}
// Admins can edit

View file

@ -105,7 +105,15 @@ try {
if ($database->is_transaction_open()) {
$database->rollback();
}
_fatal_error($e);
if(is_a($e, \Shimmie2\UserErrorException::class)) {
$page->set_mode(PageMode::PAGE);
$page->set_code($e->http_code);
$page->set_title("Error");
$page->add_block(new Block(null, \MicroHTML\SPAN($e->getMessage())));
$page->display();
} else {
_fatal_error($e);
}
$exit_code = 1;
} finally {
$_tracer->end();