2021-12-14 18:32:47 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
2009-07-28 10:20:50 +00:00
|
|
|
|
2023-01-10 22:44:09 +00:00
|
|
|
namespace Shimmie2;
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
class FavoriteSetEvent extends Event
|
|
|
|
{
|
2021-03-14 23:43:50 +00:00
|
|
|
public int $image_id;
|
|
|
|
public User $user;
|
|
|
|
public bool $do_set;
|
2019-05-28 16:59:38 +00:00
|
|
|
|
|
|
|
public function __construct(int $image_id, User $user, bool $do_set)
|
|
|
|
{
|
2020-01-26 13:19:35 +00:00
|
|
|
parent::__construct();
|
2019-05-28 16:59:38 +00:00
|
|
|
assert(is_int($image_id));
|
|
|
|
assert(is_bool($do_set));
|
|
|
|
|
|
|
|
$this->image_id = $image_id;
|
|
|
|
$this->user = $user;
|
|
|
|
$this->do_set = $do_set;
|
|
|
|
}
|
2009-07-28 10:20:50 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
class Favorites extends Extension
|
|
|
|
{
|
2020-01-26 13:19:35 +00:00
|
|
|
/** @var FavoritesTheme */
|
2023-06-27 14:56:49 +00:00
|
|
|
protected Themelet $theme;
|
2020-01-26 13:19:35 +00:00
|
|
|
|
2024-01-15 18:01:48 +00:00
|
|
|
public function onInitExt(InitExtEvent $event): void
|
|
|
|
{
|
|
|
|
Image::$prop_types["favorites"] = ImagePropType::INT;
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $database, $user;
|
|
|
|
if (!$user->is_anonymous()) {
|
|
|
|
$user_id = $user->id;
|
|
|
|
$image_id = $event->image->id;
|
|
|
|
|
|
|
|
$is_favorited = $database->get_one(
|
|
|
|
"SELECT COUNT(*) AS ct FROM user_favorites WHERE user_id = :user_id AND image_id = :image_id",
|
2023-11-11 21:49:12 +00:00
|
|
|
["user_id" => $user_id, "image_id" => $image_id]
|
2019-05-28 16:59:38 +00:00
|
|
|
) > 0;
|
2019-08-07 19:53:59 +00:00
|
|
|
|
2024-08-31 16:05:18 +00:00
|
|
|
if ($is_favorited) {
|
2024-02-10 18:35:55 +00:00
|
|
|
$event->add_button("Un-Favorite", "favourite/remove/{$event->image->id}");
|
|
|
|
} else {
|
|
|
|
$event->add_button("Favorite", "favourite/add/{$event->image->id}");
|
|
|
|
}
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onDisplayingImage(DisplayingImageEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
$people = $this->list_persons_who_have_favorited($event->image);
|
|
|
|
if (count($people) > 0) {
|
|
|
|
$this->theme->display_people($people);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onPageRequest(PageRequestEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $page, $user;
|
2024-02-10 18:35:55 +00:00
|
|
|
if ($user->is_anonymous()) {
|
|
|
|
return;
|
|
|
|
} // FIXME: proper permissions
|
|
|
|
|
2024-02-11 11:34:09 +00:00
|
|
|
if ($event->page_matches("favourite/add/{image_id}", method: "POST")) {
|
|
|
|
$image_id = $event->get_iarg('image_id');
|
2024-02-10 18:35:55 +00:00
|
|
|
send_event(new FavoriteSetEvent($image_id, $user, true));
|
|
|
|
$page->set_mode(PageMode::REDIRECT);
|
|
|
|
$page->set_redirect(make_link("post/view/$image_id"));
|
|
|
|
}
|
2024-02-11 11:34:09 +00:00
|
|
|
if ($event->page_matches("favourite/remove/{image_id}", method: "POST")) {
|
|
|
|
$image_id = $event->get_iarg('image_id');
|
2024-02-10 18:35:55 +00:00
|
|
|
send_event(new FavoriteSetEvent($image_id, $user, false));
|
2019-06-19 01:58:28 +00:00
|
|
|
$page->set_mode(PageMode::REDIRECT);
|
2019-05-28 16:59:38 +00:00
|
|
|
$page->set_redirect(make_link("post/view/$image_id"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onUserPageBuilding(UserPageBuildingEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2023-12-14 16:33:21 +00:00
|
|
|
$i_favorites_count = Search::count_images(["favorited_by={$event->display_user->name}"]);
|
2024-02-20 00:22:25 +00:00
|
|
|
$i_days_old = ((time() - \Safe\strtotime($event->display_user->join_date)) / 86400) + 1;
|
2019-05-28 16:59:38 +00:00
|
|
|
$h_favorites_rate = sprintf("%.1f", ($i_favorites_count / $i_days_old));
|
2023-08-18 12:38:55 +00:00
|
|
|
$favorites_link = search_link(["favorited_by={$event->display_user->name}"]);
|
2024-03-28 12:42:39 +00:00
|
|
|
$event->add_part("<a href='$favorites_link'>Posts favorited</a>: $i_favorites_count, $h_favorites_rate per day");
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onImageInfoSet(ImageInfoSetEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $user;
|
2024-02-20 21:28:14 +00:00
|
|
|
$action = $event->get_param("favorite_action");
|
2019-05-28 16:59:38 +00:00
|
|
|
if (
|
2020-02-08 00:24:13 +00:00
|
|
|
$user->can(Permissions::EDIT_FAVOURITES) &&
|
2024-02-20 21:28:14 +00:00
|
|
|
!is_null($action) &&
|
|
|
|
($action == "set" || $action == "unset")
|
2019-05-28 16:59:38 +00:00
|
|
|
) {
|
2024-02-20 21:28:14 +00:00
|
|
|
send_event(new FavoriteSetEvent($event->image->id, $user, $action == "set"));
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onFavoriteSet(FavoriteSetEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $user;
|
|
|
|
$this->add_vote($event->image_id, $user->id, $event->do_set);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: this should be handled by the foreign key. Check that it
|
|
|
|
// is, and then remove this
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onImageDeletion(ImageDeletionEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $database;
|
2023-11-11 21:49:12 +00:00
|
|
|
$database->execute("DELETE FROM user_favorites WHERE image_id=:image_id", ["image_id" => $event->image->id]);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onParseLinkTemplate(ParseLinkTemplateEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2024-01-15 17:12:36 +00:00
|
|
|
$event->replace('$favorites', (string)$event->image['favorites']);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $user;
|
|
|
|
|
|
|
|
$username = url_escape($user->name);
|
2023-08-18 12:38:55 +00:00
|
|
|
$event->add_link("My Favorites", search_link(["favorited_by=$username"]), 20);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onSearchTermParse(SearchTermParseEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2020-01-26 16:38:26 +00:00
|
|
|
if (is_null($event->term)) {
|
|
|
|
return;
|
|
|
|
}
|
2020-01-26 13:19:35 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
$matches = [];
|
|
|
|
if (preg_match("/^favorites([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/i", $event->term, $matches)) {
|
|
|
|
$cmp = ltrim($matches[1], ":") ?: "=";
|
|
|
|
$favorites = $matches[2];
|
|
|
|
$event->add_querylet(new Querylet("images.id IN (SELECT id FROM images WHERE favorites $cmp $favorites)"));
|
|
|
|
} elseif (preg_match("/^favorited_by[=|:](.*)$/i", $event->term, $matches)) {
|
2019-11-11 16:31:14 +00:00
|
|
|
$user_id = User::name_to_id($matches[1]);
|
2019-05-28 16:59:38 +00:00
|
|
|
$event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM user_favorites WHERE user_id = $user_id)"));
|
|
|
|
} elseif (preg_match("/^favorited_by_userno[=|:](\d+)$/i", $event->term, $matches)) {
|
|
|
|
$user_id = int_escape($matches[1]);
|
|
|
|
$event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM user_favorites WHERE user_id = $user_id)"));
|
2022-03-25 17:17:22 +00:00
|
|
|
} elseif (preg_match("/^order[=|:](favorites)(?:_(desc|asc))?$/i", $event->term, $matches)) {
|
|
|
|
$default_order_for_column = "DESC";
|
|
|
|
$sort = isset($matches[2]) ? strtoupper($matches[2]) : $default_order_for_column;
|
|
|
|
$event->order = "images.favorites $sort";
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onHelpPageBuilding(HelpPageBuildingEvent $event): void
|
2019-08-02 20:05:49 +00:00
|
|
|
{
|
2023-11-11 21:49:12 +00:00
|
|
|
if ($event->key === HelpPages::SEARCH) {
|
2022-10-28 00:45:35 +00:00
|
|
|
$event->add_block(new Block("Favorites", $this->theme->get_help_html()));
|
2019-08-02 20:05:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
2019-08-02 19:54:48 +00:00
|
|
|
{
|
|
|
|
global $user;
|
2023-11-11 21:49:12 +00:00
|
|
|
if ($event->parent == "posts") {
|
2019-08-02 19:54:48 +00:00
|
|
|
$event->add_nav_link("posts_favorites", new Link("post/list/favorited_by={$user->name}/1"), "My Favorites");
|
|
|
|
}
|
|
|
|
|
2023-11-11 21:49:12 +00:00
|
|
|
if ($event->parent === "user") {
|
2019-08-02 19:54:48 +00:00
|
|
|
if ($user->can(Permissions::MANAGE_ADMINTOOLS)) {
|
|
|
|
$username = url_escape($user->name);
|
|
|
|
$event->add_nav_link("favorites", new Link("post/list/favorited_by=$username/1"), "My Favorites");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-28 16:59:38 +00:00
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event): void
|
2019-10-10 15:34:37 +00:00
|
|
|
{
|
|
|
|
global $user;
|
|
|
|
|
|
|
|
if (!$user->is_anonymous()) {
|
|
|
|
$event->add_action("bulk_favorite", "Favorite");
|
|
|
|
$event->add_action("bulk_unfavorite", "Un-Favorite");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onBulkAction(BulkActionEvent $event): void
|
2019-10-10 15:34:37 +00:00
|
|
|
{
|
2019-12-15 19:47:18 +00:00
|
|
|
global $page, $user;
|
2019-10-10 15:34:37 +00:00
|
|
|
|
|
|
|
switch ($event->action) {
|
|
|
|
case "bulk_favorite":
|
|
|
|
if (!$user->is_anonymous()) {
|
|
|
|
$total = 0;
|
|
|
|
foreach ($event->items as $image) {
|
|
|
|
send_event(new FavoriteSetEvent($image->id, $user, true));
|
|
|
|
$total++;
|
|
|
|
}
|
2019-12-15 19:47:18 +00:00
|
|
|
$page->flash("Added $total items to favorites");
|
2019-10-10 15:34:37 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "bulk_unfavorite":
|
|
|
|
if (!$user->is_anonymous()) {
|
|
|
|
$total = 0;
|
|
|
|
foreach ($event->items as $image) {
|
|
|
|
send_event(new FavoriteSetEvent($image->id, $user, false));
|
|
|
|
$total++;
|
|
|
|
}
|
2019-12-15 19:47:18 +00:00
|
|
|
$page->flash("Removed $total items from favorites");
|
2019-10-10 15:34:37 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:52:35 +00:00
|
|
|
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2019-11-03 17:19:37 +00:00
|
|
|
global $database;
|
2019-05-28 16:59:38 +00:00
|
|
|
|
2019-11-03 19:49:52 +00:00
|
|
|
if ($this->get_version("ext_favorites_version") < 1) {
|
2020-10-25 21:34:52 +00:00
|
|
|
$database->execute("ALTER TABLE images ADD COLUMN favorites INTEGER NOT NULL DEFAULT 0");
|
|
|
|
$database->execute("CREATE INDEX images__favorites ON images(favorites)");
|
2019-05-28 16:59:38 +00:00
|
|
|
$database->create_table("user_favorites", "
|
2009-07-28 10:20:50 +00:00
|
|
|
image_id INTEGER NOT NULL,
|
|
|
|
user_id INTEGER NOT NULL,
|
2019-11-03 19:25:51 +00:00
|
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
2009-07-28 10:20:50 +00:00
|
|
|
UNIQUE(image_id, user_id),
|
2012-03-11 01:52:25 +00:00
|
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
|
|
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE
|
2014-03-02 18:50:46 +00:00
|
|
|
");
|
2019-05-28 16:59:38 +00:00
|
|
|
$database->execute("CREATE INDEX user_favorites_image_id_idx ON user_favorites(image_id)", []);
|
2019-11-03 19:49:52 +00:00
|
|
|
$this->set_version("ext_favorites_version", 2);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
2019-11-03 19:49:52 +00:00
|
|
|
if ($this->get_version("ext_favorites_version") < 2) {
|
2019-05-28 16:59:38 +00:00
|
|
|
log_info("favorites", "Cleaning user favourites");
|
2020-10-25 21:34:52 +00:00
|
|
|
$database->execute("DELETE FROM user_favorites WHERE user_id NOT IN (SELECT id FROM users)");
|
|
|
|
$database->execute("DELETE FROM user_favorites WHERE image_id NOT IN (SELECT id FROM images)");
|
2019-05-28 16:59:38 +00:00
|
|
|
|
|
|
|
log_info("favorites", "Adding foreign keys to user favourites");
|
2020-10-25 21:34:52 +00:00
|
|
|
$database->execute("ALTER TABLE user_favorites ADD FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;");
|
|
|
|
$database->execute("ALTER TABLE user_favorites ADD FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE;");
|
2019-11-03 19:49:52 +00:00
|
|
|
$this->set_version("ext_favorites_version", 2);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-20 14:10:59 +00:00
|
|
|
private function add_vote(int $image_id, int $user_id, bool $do_set): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $database;
|
|
|
|
if ($do_set) {
|
2023-11-11 21:49:12 +00:00
|
|
|
if (!$database->get_row("select 1 from user_favorites where image_id=:image_id and user_id=:user_id", ["image_id" => $image_id, "user_id" => $user_id])) {
|
2020-10-25 21:34:52 +00:00
|
|
|
$database->execute(
|
2019-10-10 15:34:37 +00:00
|
|
|
"INSERT INTO user_favorites(image_id, user_id, created_at) VALUES(:image_id, :user_id, NOW())",
|
2023-11-11 21:49:12 +00:00
|
|
|
["image_id" => $image_id, "user_id" => $user_id]
|
2019-10-10 15:34:37 +00:00
|
|
|
);
|
|
|
|
}
|
2019-05-28 16:59:38 +00:00
|
|
|
} else {
|
2020-10-25 21:34:52 +00:00
|
|
|
$database->execute(
|
2019-05-28 16:59:38 +00:00
|
|
|
"DELETE FROM user_favorites WHERE image_id = :image_id AND user_id = :user_id",
|
2023-11-11 21:49:12 +00:00
|
|
|
["image_id" => $image_id, "user_id" => $user_id]
|
2019-05-28 16:59:38 +00:00
|
|
|
);
|
|
|
|
}
|
2020-10-25 21:34:52 +00:00
|
|
|
$database->execute(
|
2019-05-28 16:59:38 +00:00
|
|
|
"UPDATE images SET favorites=(SELECT COUNT(*) FROM user_favorites WHERE image_id=:image_id) WHERE id=:user_id",
|
2023-11-11 21:49:12 +00:00
|
|
|
["image_id" => $image_id, "user_id" => $user_id]
|
2019-05-28 16:59:38 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2024-01-06 21:28:06 +00:00
|
|
|
* @return string[]
|
2019-05-28 16:59:38 +00:00
|
|
|
*/
|
|
|
|
private function list_persons_who_have_favorited(Image $image): array
|
|
|
|
{
|
|
|
|
global $database;
|
|
|
|
|
|
|
|
return $database->get_col(
|
|
|
|
"SELECT name FROM users WHERE id IN (SELECT user_id FROM user_favorites WHERE image_id = :image_id) ORDER BY name",
|
2023-11-11 21:49:12 +00:00
|
|
|
["image_id" => $image->id]
|
2019-05-28 16:59:38 +00:00
|
|
|
);
|
|
|
|
}
|
2009-07-28 10:20:50 +00:00
|
|
|
}
|