commit
aabc69033b
@ -81,4 +81,7 @@ abstract class Permissions
|
|||||||
public const POOLS_ADMIN = "pools_admin";
|
public const POOLS_ADMIN = "pools_admin";
|
||||||
public const TIPS_ADMIN = "tips_admin";
|
public const TIPS_ADMIN = "tips_admin";
|
||||||
public const CRON_ADMIN = "cron_admin";
|
public const CRON_ADMIN = "cron_admin";
|
||||||
|
public const APPROVE_IMAGE = "approve_image";
|
||||||
|
public const APPROVE_COMMENT = "approve_comment";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -502,7 +502,7 @@ function bool_escape($input): bool
|
|||||||
*/
|
*/
|
||||||
if (is_bool($input)) {
|
if (is_bool($input)) {
|
||||||
return $input;
|
return $input;
|
||||||
} elseif (is_int($input)) {
|
} elseif (is_numeric($input)) {
|
||||||
return ($input === 1);
|
return ($input === 1);
|
||||||
} else {
|
} else {
|
||||||
$value = filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
$value = filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||||
|
@ -151,6 +151,9 @@ new UserClass("base", null, [
|
|||||||
Permissions::POOLS_ADMIN => false,
|
Permissions::POOLS_ADMIN => false,
|
||||||
Permissions::TIPS_ADMIN => false,
|
Permissions::TIPS_ADMIN => false,
|
||||||
Permissions::CRON_ADMIN => false,
|
Permissions::CRON_ADMIN => false,
|
||||||
|
|
||||||
|
Permissions::APPROVE_IMAGE => false,
|
||||||
|
Permissions::APPROVE_COMMENT => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
new UserClass("anonymous", "base", [
|
new UserClass("anonymous", "base", [
|
||||||
@ -228,6 +231,8 @@ new UserClass("admin", "base", [
|
|||||||
Permissions::POOLS_ADMIN => true,
|
Permissions::POOLS_ADMIN => true,
|
||||||
Permissions::TIPS_ADMIN => true,
|
Permissions::TIPS_ADMIN => true,
|
||||||
Permissions::CRON_ADMIN => true,
|
Permissions::CRON_ADMIN => true,
|
||||||
|
Permissions::APPROVE_IMAGE => true,
|
||||||
|
Permissions::APPROVE_COMMENT => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
new UserClass("hellbanned", "user", [
|
new UserClass("hellbanned", "user", [
|
||||||
|
13
ext/approval/info.php
Normal file
13
ext/approval/info.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class ApprovalInfo extends ExtensionInfo
|
||||||
|
{
|
||||||
|
public const KEY = "approval";
|
||||||
|
|
||||||
|
public $key = self::KEY;
|
||||||
|
public $name = "Approval";
|
||||||
|
public $authors = ["Matthew Barbour"=>"matthew@darkholme.net"];
|
||||||
|
public $license = self::LICENSE_WTFPL;
|
||||||
|
public $description = "Adds an approval step to the upload/import process.";
|
||||||
|
public $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::PGSQL];
|
||||||
|
}
|
253
ext/approval/main.php
Normal file
253
ext/approval/main.php
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class ApprovalConfig
|
||||||
|
{
|
||||||
|
const VERSION = "ext_approval_version";
|
||||||
|
const IMAGES = "approve_images";
|
||||||
|
const COMMENTS = "approve_comments";
|
||||||
|
}
|
||||||
|
|
||||||
|
class Approval extends Extension
|
||||||
|
{
|
||||||
|
public function onInitExt(InitExtEvent $event)
|
||||||
|
{
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
$config->set_default_bool(ApprovalConfig::IMAGES, false);
|
||||||
|
$config->set_default_bool(ApprovalConfig::COMMENTS, false);
|
||||||
|
|
||||||
|
if ($config->get_int(ApprovalConfig::VERSION) < 1) {
|
||||||
|
$this->install();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onPageRequest(PageRequestEvent $event)
|
||||||
|
{
|
||||||
|
global $page, $user;
|
||||||
|
|
||||||
|
if ($event->page_matches("approve_image") && $user->can(Permissions::APPROVE_IMAGE)) {
|
||||||
|
// Try to get the image ID
|
||||||
|
$image_id = int_escape($event->get_arg(0));
|
||||||
|
if (empty($image_id)) {
|
||||||
|
$image_id = isset($_POST['image_id']) ? $_POST['image_id'] : null;
|
||||||
|
}
|
||||||
|
if (empty($image_id)) {
|
||||||
|
throw new SCoreException("Can not approve image: No valid Image ID given.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
$image_id = int_escape($event->get_arg(0));
|
||||||
|
if (empty($image_id)) {
|
||||||
|
$image_id = isset($_POST['image_id']) ? $_POST['image_id'] : null;
|
||||||
|
}
|
||||||
|
if (empty($image_id)) {
|
||||||
|
throw new SCoreException("Can not disapprove image: No valid Image ID given.");
|
||||||
|
}
|
||||||
|
|
||||||
|
self::disapprove_image($image_id);
|
||||||
|
$page->set_mode(PageMode::REDIRECT);
|
||||||
|
$page->set_redirect(make_link("post/view/".$image_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||||
|
{
|
||||||
|
$this->theme->display_admin_block($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onAdminBuilding(AdminBuildingEvent $event)
|
||||||
|
{
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
$this->theme->display_admin_form();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onAdminAction(AdminActionEvent $event)
|
||||||
|
{
|
||||||
|
global $database, $user;
|
||||||
|
|
||||||
|
$action = $event->action;
|
||||||
|
$event->redirect = true;
|
||||||
|
if($action==="approval") {
|
||||||
|
$approval_action = $_POST["approval_action"];
|
||||||
|
switch ($approval_action) {
|
||||||
|
case "approve_all":
|
||||||
|
$database->set_timeout(300000); // These updates can take a little bit
|
||||||
|
$database->execute($database->scoreql_to_sql(
|
||||||
|
"UPDATE images SET approved = SCORE_BOOL_Y, approved_by_id = :approved_by_id WHERE approved = SCORE_BOOL_N"),
|
||||||
|
["approved_by_id"=>$user->id]
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "disapprove_all":
|
||||||
|
$database->set_timeout(300000); // These updates can take a little bit
|
||||||
|
$database->execute($database->scoreql_to_sql(
|
||||||
|
"UPDATE images SET approved = SCORE_BOOL_N, approved_by_id = NULL WHERE approved = SCORE_BOOL_Y"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onDisplayingImage(DisplayingImageEvent $event)
|
||||||
|
{
|
||||||
|
global $user, $page, $config;
|
||||||
|
|
||||||
|
if ( $config->get_bool(ApprovalConfig::IMAGES) && $event->image->approved===false && !$user->can(Permissions::APPROVE_IMAGE)) {
|
||||||
|
$page->set_mode(PageMode::REDIRECT);
|
||||||
|
$page->set_redirect(make_link("post/list"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||||
|
{
|
||||||
|
global $user;
|
||||||
|
if($event->parent=="posts") {
|
||||||
|
if($user->can(Permissions::APPROVE_IMAGE)) {
|
||||||
|
$event->add_nav_link("posts_unapproved", new Link('/post/list/approved%3Ano/1'), "Pending Approval",null, 60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const SEARCH_REGEXP = "/^approved:(yes|no)/";
|
||||||
|
public function onSearchTermParse(SearchTermParseEvent $event)
|
||||||
|
{
|
||||||
|
global $user, $database, $config;
|
||||||
|
|
||||||
|
if($config->get_bool(ApprovalConfig::IMAGES)) {
|
||||||
|
$matches = [];
|
||||||
|
|
||||||
|
if (is_null($event->term) && $this->no_approval_query($event->context)) {
|
||||||
|
$event->add_querylet(new Querylet($database->scoreql_to_sql("approved = SCORE_BOOL_Y ")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (preg_match(self::SEARCH_REGEXP, strtolower($event->term), $matches)) {
|
||||||
|
if ($user->can(Permissions::APPROVE_IMAGE) && $matches[1] == "no") {
|
||||||
|
$event->add_querylet(new Querylet($database->scoreql_to_sql("approved = SCORE_BOOL_N ")));
|
||||||
|
} else {
|
||||||
|
$event->add_querylet(new Querylet($database->scoreql_to_sql("approved = SCORE_BOOL_Y ")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onHelpPageBuilding(HelpPageBuildingEvent $event)
|
||||||
|
{
|
||||||
|
global $user, $config;
|
||||||
|
if ($event->key===HelpPages::SEARCH) {
|
||||||
|
if ($user->can(Permissions::APPROVE_IMAGE) && $config->get_bool(ApprovalConfig::IMAGES)) {
|
||||||
|
$block = new Block();
|
||||||
|
$block->header = "Approval";
|
||||||
|
$block->body = $this->theme->get_help_html();
|
||||||
|
$event->add_block($block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function no_approval_query(array $context): bool
|
||||||
|
{
|
||||||
|
foreach ($context as $term) {
|
||||||
|
if (preg_match(self::SEARCH_REGEXP, $term)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function approve_image($image_id)
|
||||||
|
{
|
||||||
|
global $database, $user;
|
||||||
|
|
||||||
|
$database->execute($database->scoreql_to_sql(
|
||||||
|
"UPDATE images SET approved = SCORE_BOOL_Y, approved_by_id = :approved_by_id WHERE id = :id AND approved = SCORE_BOOL_N"),
|
||||||
|
["approved_by_id"=>$user->id, "id"=>$image_id]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function disapprove_image($image_id)
|
||||||
|
{
|
||||||
|
global $database, $user;
|
||||||
|
|
||||||
|
$database->execute($database->scoreql_to_sql(
|
||||||
|
"UPDATE images SET approved = SCORE_BOOL_N, approved_by_id = NULL WHERE id = :id AND approved = SCORE_BOOL_Y"),
|
||||||
|
["id"=>$image_id]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
|
||||||
|
{
|
||||||
|
global $user, $config;
|
||||||
|
if($user->can(Permissions::APPROVE_IMAGE) && $config->get_bool(ApprovalConfig::IMAGES)) {
|
||||||
|
$event->add_part($this->theme->get_image_admin_html($event->image));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event)
|
||||||
|
{
|
||||||
|
global $user, $config;
|
||||||
|
|
||||||
|
if ($user->can(Permissions::APPROVE_IMAGE)&& $config->get_bool(ApprovalConfig::IMAGES)) {
|
||||||
|
if(in_array("approved:no", $event->search_terms)) {
|
||||||
|
$event->add_action("bulk_approve_image", "Approve", "a");
|
||||||
|
} else {
|
||||||
|
$event->add_action("bulk_disapprove_image", "Disapprove");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onBulkAction(BulkActionEvent $event)
|
||||||
|
{
|
||||||
|
global $user;
|
||||||
|
|
||||||
|
switch ($event->action) {
|
||||||
|
case "bulk_approve_image":
|
||||||
|
if ($user->can(Permissions::APPROVE_IMAGE)) {
|
||||||
|
$total = 0;
|
||||||
|
foreach ($event->items as $image) {
|
||||||
|
self::approve_image($image->id);
|
||||||
|
$total++;
|
||||||
|
}
|
||||||
|
flash_message("Approved $total items");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "bulk_disapprove_image":
|
||||||
|
if ($user->can(Permissions::APPROVE_IMAGE)) {
|
||||||
|
$total = 0;
|
||||||
|
foreach ($event->items as $image) {
|
||||||
|
self::disapprove_image($image->id);
|
||||||
|
$total++;
|
||||||
|
}
|
||||||
|
flash_message("Disapproved $total items");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function install()
|
||||||
|
{
|
||||||
|
global $database, $config;
|
||||||
|
|
||||||
|
if ($config->get_int(ApprovalConfig::VERSION) < 1) {
|
||||||
|
$database->Execute($database->scoreql_to_sql(
|
||||||
|
"ALTER TABLE images ADD COLUMN approved SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N"
|
||||||
|
));
|
||||||
|
$database->Execute($database->scoreql_to_sql(
|
||||||
|
"ALTER TABLE images ADD COLUMN approved_by_id INTEGER NULL"
|
||||||
|
));
|
||||||
|
|
||||||
|
$database->Execute("CREATE INDEX images_approved_idx ON images(approved)");
|
||||||
|
$config->set_int(ApprovalConfig::VERSION, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
ext/approval/theme.php
Normal file
58
ext/approval/theme.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class ApprovalTheme extends Themelet
|
||||||
|
{
|
||||||
|
public function get_image_admin_html(Image $image)
|
||||||
|
{
|
||||||
|
if($image->approved===true) {
|
||||||
|
$html = "
|
||||||
|
".make_form(make_link('disapprove_image/'.$image->id), 'POST')."
|
||||||
|
<input type='hidden' name='image_id' value='$image->id'>
|
||||||
|
<input type='submit' value='Disapprove'>
|
||||||
|
</form>
|
||||||
|
";
|
||||||
|
} else {
|
||||||
|
$html = "
|
||||||
|
".make_form(make_link('approve_image/'.$image->id), 'POST')."
|
||||||
|
<input type='hidden' name='image_id' value='$image->id'>
|
||||||
|
<input type='submit' value='Approve'>
|
||||||
|
</form>
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function get_help_html()
|
||||||
|
{
|
||||||
|
return '<p>Search for images that are approved/not approved.</p>
|
||||||
|
<div class="command_example">
|
||||||
|
<pre>approved:yes</pre>
|
||||||
|
<p>Returns images that have been approved.</p>
|
||||||
|
</div>
|
||||||
|
<div class="command_example">
|
||||||
|
<pre>approved:no</pre>
|
||||||
|
<p>Returns images that have not been approved.</p>
|
||||||
|
</div>
|
||||||
|
';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function display_admin_block(SetupBuildingEvent $event)
|
||||||
|
{
|
||||||
|
$sb = new SetupBlock("Approval");
|
||||||
|
$sb->add_bool_option(ApprovalConfig::IMAGES, "Images: ");
|
||||||
|
$event->panel->add_block($sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function display_admin_form()
|
||||||
|
{
|
||||||
|
global $page;
|
||||||
|
|
||||||
|
$html = make_form(make_link("admin/approval"), "POST");
|
||||||
|
$html .= "<button name='approval_action' value='approve_all'>Approve All Images</button><br/>";
|
||||||
|
$html .= "<button name='approval_action' value='disapprove_all'>Disapprove All Images</button>";
|
||||||
|
$html .= "</form>\n";
|
||||||
|
$page->add_block(new Block("Approval", $html));
|
||||||
|
}
|
||||||
|
}
|
@ -33,22 +33,40 @@ class HelpPages extends Extension
|
|||||||
{
|
{
|
||||||
public const SEARCH = "search";
|
public const SEARCH = "search";
|
||||||
|
|
||||||
|
private $pages;
|
||||||
|
|
||||||
|
private function get_pages(): array
|
||||||
|
{
|
||||||
|
if($this->pages==null) {
|
||||||
|
$e = new HelpPageListBuildingEvent();
|
||||||
|
send_event($e);
|
||||||
|
$this->pages = $e->pages;
|
||||||
|
}
|
||||||
|
return $this->pages;
|
||||||
|
}
|
||||||
|
|
||||||
public function onPageRequest(PageRequestEvent $event)
|
public function onPageRequest(PageRequestEvent $event)
|
||||||
{
|
{
|
||||||
global $page;
|
global $page;
|
||||||
|
|
||||||
|
$pages = $this->get_pages();
|
||||||
|
|
||||||
if ($event->page_matches("help")) {
|
if ($event->page_matches("help")) {
|
||||||
$e = new HelpPageListBuildingEvent();
|
|
||||||
send_event($e);
|
|
||||||
$page->set_mode(PageMode::PAGE);
|
|
||||||
|
|
||||||
if ($event->count_args() == 0) {
|
if ($event->count_args() == 0) {
|
||||||
$this->theme->display_list_page($e->pages);
|
$name = array_key_first($pages);
|
||||||
|
$page->set_mode(PageMode::REDIRECT);
|
||||||
|
$page->set_redirect(make_link("help/".$name));
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
$page->set_mode(PageMode::PAGE);
|
||||||
$name = $event->get_arg(0);
|
$name = $event->get_arg(0);
|
||||||
$title = $name;
|
$title = $name;
|
||||||
if (array_key_exists($name, $e->pages)) {
|
if(array_key_exists($name, $pages)) {
|
||||||
$title = $e->pages[$name];
|
$title = $pages[$name];
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->theme->display_help_page($title);
|
$this->theme->display_help_page($title);
|
||||||
@ -77,6 +95,16 @@ class HelpPages extends Extension
|
|||||||
$event->add_nav_link("help", new Link('help'), "Help");
|
$event->add_nav_link("help", new Link('help'), "Help");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||||
|
{
|
||||||
|
if($event->parent=="help") {
|
||||||
|
$pages = $this->get_pages();
|
||||||
|
foreach ($pages as $key=>$value) {
|
||||||
|
$event->add_nav_link("help_".$key, new Link('help/'.$key),$value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
||||||
{
|
{
|
||||||
$event->add_link("Help", make_link("help"));
|
$event->add_link("Help", make_link("help"));
|
||||||
|
@ -341,7 +341,7 @@ class Ratings extends Extension
|
|||||||
$old = $_POST["rating_old"];
|
$old = $_POST["rating_old"];
|
||||||
$new = $_POST["rating_new"];
|
$new = $_POST["rating_new"];
|
||||||
|
|
||||||
if ($user->can("bulk_edit_image_rating")) {
|
if($user->can(Permissions::BULK_EDIT_IMAGE_RATING)) {
|
||||||
$database->execute("UPDATE images SET rating = :new WHERE rating = :old", ["new"=>$new, "old"=>$old ]);
|
$database->execute("UPDATE images SET rating = :new WHERE rating = :old", ["new"=>$new, "old"=>$old ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,7 +506,7 @@ class Ratings extends Extension
|
|||||||
private function can_rate(): bool
|
private function can_rate(): bool
|
||||||
{
|
{
|
||||||
global $user;
|
global $user;
|
||||||
if ($user->can("edit_image_rating")) {
|
if ($user->can(Permissions::EDIT_IMAGE_RATING)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -35,9 +35,6 @@ class DataUploadEvent extends Event
|
|||||||
assert(is_array($metadata["tags"]));
|
assert(is_array($metadata["tags"]));
|
||||||
assert(is_string($metadata["source"]) || is_null($metadata["source"]));
|
assert(is_string($metadata["source"]) || is_null($metadata["source"]));
|
||||||
|
|
||||||
// DB limits to 64 char filenames
|
|
||||||
$metadata['filename'] = substr($metadata['filename'], 0, 63);
|
|
||||||
|
|
||||||
$this->metadata = $metadata;
|
$this->metadata = $metadata;
|
||||||
|
|
||||||
$this->set_tmpname($tmpname);
|
$this->set_tmpname($tmpname);
|
||||||
|
@ -8,7 +8,7 @@ class CustomExtManagerTheme extends ExtManagerTheme
|
|||||||
parent::display_table($page, $extensions, $editable);
|
parent::display_table($page, $extensions, $editable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function display_doc(Page $page, ExtensionInfo $info)
|
public function display_doc(Page $page, ExtensionManagerInfo $info)
|
||||||
{
|
{
|
||||||
$page->disable_left();
|
$page->disable_left();
|
||||||
parent::display_doc($page, $info);
|
parent::display_doc($page, $info);
|
||||||
|
@ -51,8 +51,10 @@ class CustomViewImageTheme extends ViewImageTheme
|
|||||||
if ($image->rating == null || $image->rating == "?") {
|
if ($image->rating == null || $image->rating == "?") {
|
||||||
$image->rating = "?";
|
$image->rating = "?";
|
||||||
}
|
}
|
||||||
$h_rating = Ratings::rating_to_human($image->rating);
|
if (Extension::is_enabled(RatingsInfo::KEY)) {
|
||||||
$html .= "<br>Rating: $h_rating";
|
$h_rating = Ratings::rating_to_human($image->rating);
|
||||||
|
$html .= "<br>Rating: $h_rating";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $html;
|
return $html;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user