aboutsummaryrefslogblamecommitdiffhomepage
path: root/application/front/controller/admin/ShaareManageController.php
blob: 7ceb8d8a3584e046c94c51c6999e39a5974bf3dc (plain) (tree)









































































































































































































                                                                                                                   
<?php

declare(strict_types=1);

namespace Shaarli\Front\Controller\Admin;

use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
use Slim\Http\Request;
use Slim\Http\Response;

/**
 * Class PostBookmarkController
 *
 * Slim controller used to handle Shaarli create or edit bookmarks.
 */
class ShaareManageController extends ShaarliAdminController
{
    /**
     * GET /admin/shaare/delete - Delete one or multiple bookmarks (depending on `id` query parameter).
     */
    public function deleteBookmark(Request $request, Response $response): Response
    {
        $this->checkToken($request);

        $ids = escape(trim($request->getParam('id') ?? ''));
        if (empty($ids) || strpos($ids, ' ') !== false) {
            // multiple, space-separated ids provided
            $ids = array_values(array_filter(preg_split('/\s+/', $ids), 'ctype_digit'));
        } else {
            $ids = [$ids];
        }

        // assert at least one id is given
        if (0 === count($ids)) {
            $this->saveErrorMessage(t('Invalid bookmark ID provided.'));

            return $this->redirectFromReferer($request, $response, [], ['delete-shaare']);
        }

        $formatter = $this->container->formatterFactory->getFormatter('raw');
        $count = 0;
        foreach ($ids as $id) {
            try {
                $bookmark = $this->container->bookmarkService->get((int) $id);
            } catch (BookmarkNotFoundException $e) {
                $this->saveErrorMessage(sprintf(
                    t('Bookmark with identifier %s could not be found.'),
                    $id
                ));

                continue;
            }

            $data = $formatter->format($bookmark);
            $this->executePageHooks('delete_link', $data);
            $this->container->bookmarkService->remove($bookmark, false);
            ++ $count;
        }

        if ($count > 0) {
            $this->container->bookmarkService->save();
        }

        // If we are called from the bookmarklet, we must close the popup:
        if ($request->getParam('source') === 'bookmarklet') {
            return $response->write('<script>self.close();</script>');
        }

        // Don't redirect to where we were previously because the datastore has changed.
        return $this->redirect($response, '/');
    }

    /**
     * GET /admin/shaare/visibility
     *
     * Change visibility (public/private) of one or multiple bookmarks (depending on `id` query parameter).
     */
    public function changeVisibility(Request $request, Response $response): Response
    {
        $this->checkToken($request);

        $ids = trim(escape($request->getParam('id') ?? ''));
        if (empty($ids) || strpos($ids, ' ') !== false) {
            // multiple, space-separated ids provided
            $ids = array_values(array_filter(preg_split('/\s+/', $ids), 'ctype_digit'));
        } else {
            // only a single id provided
            $ids = [$ids];
        }

        // assert at least one id is given
        if (0 === count($ids)) {
            $this->saveErrorMessage(t('Invalid bookmark ID provided.'));

            return $this->redirectFromReferer($request, $response, [], ['change_visibility']);
        }

        // assert that the visibility is valid
        $visibility = $request->getParam('newVisibility');
        if (null === $visibility || false === in_array($visibility, ['public', 'private'], true)) {
            $this->saveErrorMessage(t('Invalid visibility provided.'));

            return $this->redirectFromReferer($request, $response, [], ['change_visibility']);
        } else {
            $isPrivate = $visibility === 'private';
        }

        $formatter = $this->container->formatterFactory->getFormatter('raw');
        $count = 0;

        foreach ($ids as $id) {
            try {
                $bookmark = $this->container->bookmarkService->get((int) $id);
            } catch (BookmarkNotFoundException $e) {
                $this->saveErrorMessage(sprintf(
                    t('Bookmark with identifier %s could not be found.'),
                    $id
                ));

                continue;
            }

            $bookmark->setPrivate($isPrivate);

            // To preserve backward compatibility with 3rd parties, plugins still use arrays
            $data = $formatter->format($bookmark);
            $this->executePageHooks('save_link', $data);
            $bookmark->fromArray($data);

            $this->container->bookmarkService->set($bookmark, false);
            ++$count;
        }

        if ($count > 0) {
            $this->container->bookmarkService->save();
        }

        return $this->redirectFromReferer($request, $response, ['/visibility'], ['change_visibility']);
    }

    /**
     * GET /admin/shaare/{id}/pin - Pin or unpin a bookmark.
     */
    public function pinBookmark(Request $request, Response $response, array $args): Response
    {
        $this->checkToken($request);

        $id = $args['id'] ?? '';
        try {
            if (false === ctype_digit($id)) {
                throw new BookmarkNotFoundException();
            }
            $bookmark = $this->container->bookmarkService->get((int) $id);  // Read database
        } catch (BookmarkNotFoundException $e) {
            $this->saveErrorMessage(sprintf(
                t('Bookmark with identifier %s could not be found.'),
                $id
            ));

            return $this->redirectFromReferer($request, $response, ['/pin'], ['pin']);
        }

        $formatter = $this->container->formatterFactory->getFormatter('raw');

        $bookmark->setSticky(!$bookmark->isSticky());

        // To preserve backward compatibility with 3rd parties, plugins still use arrays
        $data = $formatter->format($bookmark);
        $this->executePageHooks('save_link', $data);
        $bookmark->fromArray($data);

        $this->container->bookmarkService->set($bookmark);

        return $this->redirectFromReferer($request, $response, ['/pin'], ['pin']);
    }

    /**
     * GET /admin/shaare/private/{hash} - Attach a private key to given bookmark, then redirect to the sharing URL.
     */
    public function sharePrivate(Request $request, Response $response, array $args): Response
    {
        $this->checkToken($request);

        $hash = $args['hash'] ?? '';
        $bookmark = $this->container->bookmarkService->findByHash($hash);

        if ($bookmark->isPrivate() !== true) {
            return $this->redirect($response, '/shaare/' . $hash);
        }

        if (empty($bookmark->getAdditionalContentEntry('private_key'))) {
            $privateKey = bin2hex(random_bytes(16));
            $bookmark->addAdditionalContentEntry('private_key', $privateKey);
            $this->container->bookmarkService->set($bookmark);
        }

        return $this->redirect(
            $response,
            '/shaare/' . $hash . '?key=' . $bookmark->getAdditionalContentEntry('private_key')
        );
    }
}