diff --git a/components/Avatar/Controller/Avatar.php b/components/Avatar/Controller/Avatar.php index 0c0175ea81..3dfbebe418 100644 --- a/components/Avatar/Controller/Avatar.php +++ b/components/Avatar/Controller/Avatar.php @@ -86,6 +86,7 @@ class Avatar extends Controller $form->addError(new FormError(_m('No avatar set, so cannot delete'))); } } else { + $attachment = null; if (isset($data['hidden'])) { // Cropped client side $matches = []; @@ -95,26 +96,25 @@ class Avatar extends Controller $data_user = base64_decode($data_user); $tempfile = new TemporaryFile(['prefix' => 'gs-avatar']); $tempfile->write($data_user); + $attachment = GSFile::sanitizeAndStoreFileAsAttachment($tempfile); } else { Log::info('Avatar upload got an invalid encoding, something\'s fishy and/or wrong'); } } } elseif (isset($data['avatar'])) { // Cropping failed (e.g. disabled js), use file as uploaded - $file = $data['avatar']; + $file = $data['avatar']; + $attachment = GSFile::sanitizeAndStoreFileAsAttachment($file); } else { throw new ClientException('Invalid form'); } - $attachment = GSFile::sanitizeAndStoreFileAsAttachment( - $file - ); // Delete current avatar if there's one $avatar = DB::find('avatar', ['gsactor_id' => $gsactor_id]); $avatar?->delete(); DB::persist($attachment); // Can only get new id after inserting DB::flush(); - DB::persist(AvatarEntity::create(['gsactor_id' => $gsactor_id, 'attachment_id' => $attachment->getId(), 'filename' => $file->getClientOriginalName()])); + DB::persist(AvatarEntity::create(['gsactor_id' => $gsactor_id, 'attachment_id' => $attachment->getId()])); DB::flush(); Event::handle('AvatarUpdate', [$user->getId()]); } diff --git a/config/bootstrap.php b/config/bootstrap.php index b54c9c70e9..b7dfbf07a9 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -29,6 +29,7 @@ define('PUBLICDIR', INSTALLDIR . '/public'); define('GNUSOCIAL_ENGINE_NAME', 'GNU social'); // MERGE Change to https://gnu.io/social/ define('GNUSOCIAL_PROJECT_URL', 'https://gnusocial.rocks/'); +define('GNUSOCIAL_ENGINE_URL', GNUSOCIAL_PROJECT_URL); // MERGE Change to https://git.gnu.io/gnu/gnu-social define('GNUSOCIAL_REPOSITORY_URL', 'https://code.undefinedhackers.net/GNUsocial/gnu-social'); // Current base version, major.minor.patch @@ -39,6 +40,8 @@ define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE); define('GNUSOCIAL_CODENAME', 'Big bang'); define('URL_REGEX_DOMAIN_NAME', '(?:(?!-)[A-Za-z0-9\-]{1,63}(?toJson() : null, diff --git a/plugins/ActivityStreamsTwo/Util/Type/AbstractObject.php b/plugins/ActivityStreamsTwo/Util/Type/AbstractObject.php index c2cca91b87..c808ef5f7a 100644 --- a/plugins/ActivityStreamsTwo/Util/Type/AbstractObject.php +++ b/plugins/ActivityStreamsTwo/Util/Type/AbstractObject.php @@ -31,6 +31,8 @@ abstract class AbstractObject */ private array $_props = []; + protected string $type = 'AbstractObject'; + /** * Standard setter method * - Perform content validation if a validator exists diff --git a/plugins/Favourite/Favourite.php b/plugins/Favourite/Favourite.php index 520f94e5eb..28eb6e2bb2 100644 --- a/plugins/Favourite/Favourite.php +++ b/plugins/Favourite/Favourite.php @@ -77,28 +77,32 @@ class Favourite extends NoteHandlerPlugin // Form handler $ret = self::noteActionHandle( - $request, $form_fav, $note, "favourite-{$note->getId()}", /** - * Called from form handler - * - * @param $note Note to be favourited - * @param $data Form input - * - * @throws RedirectException Always thrown in order to prevent accidental form re-submit from browser - */ function ($note, $data) use ($opts, $request) { - $favourite_note = DB::find('favourite', $opts); - if ($data["favourite-{$note->getId()}"] === '0' && $favourite_note === null) { - DB::persist(Entity\Favourite::create($opts)); - DB::flush(); - } else if ($data["favourite-{$note->getId()}"] === '1' && $favourite_note !== null) { - DB::remove($favourite_note); - DB::flush(); - } + $request, $form_fav, $note, "favourite-{$note->getId()}", + /** + * Called from form handler + * + * @param $note Note to be favourited + * @param $data Form input + * + * @throws RedirectException Always thrown in order to prevent accidental form re-submit from browser + */ + function ($note, $data) use ($opts) { + $favourite_note = DB::find('favourite', $opts); + if ($data["favourite-{$note->getId()}"] === '0' && $favourite_note === null) { + DB::persist(Entity\Favourite::create($opts)); + DB::flush(); + } else { + if ($data["favourite-{$note->getId()}"] === '1' && $favourite_note !== null) { + DB::remove($favourite_note); + DB::flush(); + } + } - // Prevent accidental refreshes from resubmitting the form - throw new RedirectException(); + // Prevent accidental refreshes from resubmitting the form + throw new RedirectException(); - return Event::stop; - }); + return Event::stop; + }); if ($ret !== null) { return $ret; diff --git a/plugins/Repeat/Repeat.php b/plugins/Repeat/Repeat.php index 0514839592..d04bb73608 100644 --- a/plugins/Repeat/Repeat.php +++ b/plugins/Repeat/Repeat.php @@ -61,7 +61,7 @@ class Repeat extends NoteHandlerPlugin // Handle form $ret = self::noteActionHandle( - $request, $form_repeat, $note, "repeat-{$note->getId()}", function ($note, $data, $user) use ($opts) { + $request, $form_repeat, $note, "repeat-{$note->getId()}", function ($note, $data, $user) { if ($data["repeat-{$note->getId()}"] === '0') { DB::persist(Note::create([ 'gsactor_id' => $user->getId(), diff --git a/src/Controller/AdminPanel.php b/src/Controller/AdminPanel.php index ee9d4d83cb..50284794cd 100644 --- a/src/Controller/AdminPanel.php +++ b/src/Controller/AdminPanel.php @@ -79,6 +79,7 @@ class AdminPanel extends Controller // @codeCoverageIgnoreEnd } + $value = null; foreach ([ 'int' => FILTER_VALIDATE_INT, 'bool' => FILTER_VALIDATE_BOOL, diff --git a/src/Controller/Note.php b/src/Controller/Note.php index 6e3709fd2e..b075b8afc3 100644 --- a/src/Controller/Note.php +++ b/src/Controller/Note.php @@ -47,11 +47,6 @@ class Note extends Controller */ public function note_show(Request $request, int $id) { - return $this->note($id, function ($note) use ($id) { - return [ - '_template' => 'note/view.html.twig', - 'note' => $note, - ]; - }); + return $this->note($id, fn ($note) => ['_template' => 'note/view.html.twig', 'note' => $note]); } } diff --git a/src/Core/Cache.php b/src/Core/Cache.php index 9cbed62e15..b3bc86c20c 100644 --- a/src/Core/Cache.php +++ b/src/Core/Cache.php @@ -199,7 +199,7 @@ abstract class Cache ->lTrim($key, -$max_count ?? 0, -1) ->exec(); } else { - self::set($key, $value, $pool, $beta); + self::set($key, $value, $pool); } } @@ -223,7 +223,7 @@ abstract class Cache $count = count($res); $res = array_slice($res, $count - $max_count, $count); // Trim the older values } - self::set($key, $res, $pool, $beta); + self::set($key, $res, $pool); } } diff --git a/src/Core/Controller.php b/src/Core/Controller.php index 874b446d52..41b0c9c28d 100644 --- a/src/Core/Controller.php +++ b/src/Core/Controller.php @@ -46,6 +46,11 @@ use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\ViewEvent; use Symfony\Component\HttpKernel\KernelEvents; +/** + * @method int int(string $param) + * @method bool bool(string $param) + * @method string string(string $param) + */ class Controller extends AbstractController implements EventSubscriberInterface { private array $vars = []; diff --git a/src/Core/DB/DB.php b/src/Core/DB/DB.php index 06bf2458d2..a781e13022 100644 --- a/src/Core/DB/DB.php +++ b/src/Core/DB/DB.php @@ -42,7 +42,10 @@ use Doctrine\ORM\Query; use Doctrine\ORM\Query\ResultSetMappingBuilder; use Functional as F; -abstract class DB +/** + * @mixin EntityManagerInterface + */ +class DB { private static ?EntityManagerInterface $em; public static function setManager($m): void diff --git a/src/Core/HTTPClient.php b/src/Core/HTTPClient.php index ef14bbdf2a..869d9b4ade 100644 --- a/src/Core/HTTPClient.php +++ b/src/Core/HTTPClient.php @@ -20,13 +20,25 @@ namespace App\Core; use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; /** * @codeCoverageIgnore + * @mixin HttpClientInterface + * + * @method static ResponseInterface head(string $url, array $options = []) + * @method static ResponseInterface get(string $url, array $options = []) + * @method static ResponseInterface post(string $url, array $options = []) + * @method static ResponseInterface put(string $url, array $options = []) + * @method static ResponseInterface delete(string $url, array $options = []) + * @method static ResponseInterface connect(string $url, array $options = []) + * @method static ResponseInterface options(string $url, array $options = []) + * @method static ResponseInterface trace(string $url, array $options = []) + * @method static ResponseInterface patch(string $url, array $options = []) */ abstract class HTTPClient { - private static ?Httpclientinterface $client; + private static ?HttpClientInterface $client; public static function setClient(HttpClientInterface $client) { self::$client = $client; diff --git a/src/Core/I18n/I18n.php b/src/Core/I18n/I18n.php index 14b88def3f..68ad66be3f 100644 --- a/src/Core/I18n/I18n.php +++ b/src/Core/I18n/I18n.php @@ -316,7 +316,7 @@ function _m(...$args): string // Get the file where this function was called from, reducing the // memory and performance impact by not returning the arguments, // and only 2 frames (this and previous) - $domain = I18n::_mdomain(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[0]['file'], 2); + $domain = I18n::_mdomain(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[0]['file']); switch (count($args)) { case 1: // Empty parameters, simple message diff --git a/src/Core/Log.php b/src/Core/Log.php index 4012acff04..633a976d11 100644 --- a/src/Core/Log.php +++ b/src/Core/Log.php @@ -34,6 +34,9 @@ namespace App\Core; use App\Util\Exception\ServerException; use Psr\Log\LoggerInterface; +/** + * @mixin LoggerInterface + */ abstract class Log { private static ?LoggerInterface $logger; diff --git a/src/Core/ModuleManager.php b/src/Core/ModuleManager.php index 1ac66401e3..496c2b46fa 100644 --- a/src/Core/ModuleManager.php +++ b/src/Core/ModuleManager.php @@ -46,13 +46,6 @@ use Symfony\Component\DependencyInjection\Reference; class ModuleManager { - public function __construct() - { - if (!defined('CACHE_FILE')) { - define('CACHE_FILE', INSTALLDIR . '/var/cache/module_manager.php'); - } - } - protected static $loader; /** @codeCoverageIgnore */ public static function setLoader($l) @@ -128,7 +121,7 @@ class ModuleManager $module_manager->preRegisterEvents(); - file_put_contents(CACHE_FILE, "append(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(INSTALLDIR . '/components', FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS))); $rdi->append(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(INSTALLDIR . '/plugins', FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS))); - $time = file_exists(CACHE_FILE) ? filemtime(CACHE_FILE) : 0; + $time = file_exists(MODULE_CACHE_FILE) ? filemtime(MODULE_CACHE_FILE) : 0; if ($_ENV['APP_ENV'] === 'test' || F\some($rdi, function ($e) use ($time) { return $e->getMTime() > $time; })) { Log::info('Rebuilding plugin cache at runtime. This means we can\'t update DB definitions'); @@ -166,7 +159,7 @@ class ModuleManager } } - $obj = require CACHE_FILE; + $obj = require MODULE_CACHE_FILE; foreach ($obj->modules as $module) { $module->loadConfig(); diff --git a/src/Core/Router/Router.php b/src/Core/Router/Router.php index 9276e94ea4..0576924c7b 100644 --- a/src/Core/Router/Router.php +++ b/src/Core/Router/Router.php @@ -31,8 +31,11 @@ namespace App\Core\Router; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Component\Routing\Router as SRouter; +use Symfony\Component\Routing\Router as SymfonyRouter; +/** + * @mixin SymfonyRouter + */ abstract class Router { /** @@ -58,7 +61,7 @@ abstract class Router */ const NETWORK_PATH = UrlGeneratorInterface::NETWORK_PATH; - public static ?SRouter $router = null; + public static ?SymfonyRouter $router = null; public static ?UrlGeneratorInterface $url_gen = null; public static function setServices($rtr, $gen): void diff --git a/src/Core/Security.php b/src/Core/Security.php index 1f79ded213..ad1cf9ce40 100644 --- a/src/Core/Security.php +++ b/src/Core/Security.php @@ -31,17 +31,19 @@ namespace App\Core; use HtmlSanitizer\SanitizerInterface; -use Symfony\Component\Security\Core\Security as SSecurity; +use Symfony\Component\Security\Core\Security as SymfonySecurity; /** * Forwards method calls to either Symfony\Component\Security\Core\Security or * HtmlSanitizer\SanitizerInterface, calling the first existing method, in that order * * @codeCoverageIgnore + * @mixin SymfonySecurity + * @mixin SanitizerInterface */ abstract class Security { - private static ?SSecurity $security; + private static ?SymfonySecurity $security; private static ?SanitizerInterface $sanitizer; public static function setHelper($sec, $san): void diff --git a/src/Util/Bitmap.php b/src/Util/Bitmap.php index 1764abd597..3cf2523b7f 100644 --- a/src/Util/Bitmap.php +++ b/src/Util/Bitmap.php @@ -33,6 +33,8 @@ abstract class Bitmap { $init = $r; $class = static::class; + $obj = null; + $vals = null; if ($instance) { $obj = new $class; } else { diff --git a/tests/Entity/AttachmentTest.php b/tests/Entity/AttachmentTest.php index 2fed109d2f..af28c0d2cf 100644 --- a/tests/Entity/AttachmentTest.php +++ b/tests/Entity/AttachmentTest.php @@ -50,7 +50,8 @@ class AttachmentTest extends GNUsocialTestCase static::assertTrue($attachment->deleteStorage()); static::assertFalse(file_exists($path)); static::assertNull($attachment->getPath()); - DB::flush($attachment); + DB::persist($attachment); + DB::flush(); // Setup the second attachment, re-adding the backed store $file = new TemporaryFile();