diff --git a/config/bootstrap.php b/config/bootstrap.php index 7527f50148..b54c9c70e9 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -23,4 +23,26 @@ $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ $_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV']; $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0'; +define('INSTALLDIR', dirname(__DIR__)); +define('SRCDIR', INSTALLDIR . '/src'); +define('PUBLICDIR', INSTALLDIR . '/public'); +define('GNUSOCIAL_ENGINE_NAME', 'GNU social'); +// MERGE Change to https://gnu.io/social/ +define('GNUSOCIAL_PROJECT_URL', 'https://gnusocial.rocks/'); +// 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 +define('GNUSOCIAL_BASE_VERSION', '3.0.0'); +// 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' +define('GNUSOCIAL_LIFECYCLE', 'dev'); +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, status: $status, headers: ['content-type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'], json: true ); } -} \ No newline at end of file +} diff --git a/plugins/Cover/Controller/Cover.php b/plugins/Cover/Controller/Cover.php index 3db849f249..a1d2fbe4f8 100644 --- a/plugins/Cover/Controller/Cover.php +++ b/plugins/Cover/Controller/Cover.php @@ -23,14 +23,13 @@ namespace Plugin\Cover\Controller; use App\Core\DB\DB; use App\Core\Form; +use App\Core\GSFile; use function App\Core\I18n\_m; -use App\Entity\Cover as CoverEntity; use App\Util\Common; use App\Util\Exception\ClientException; use App\Util\Exception\RedirectException; use App\Util\Exception\ServerException; -use Component\Media\Attachment; -use Component\Media\Attachment as M; +use Plugin\Cover\Entity\Cover as CoverEntity; use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -97,7 +96,7 @@ class Cover if (explode('/',$sfile->getMimeType())[0] != 'image') { throw new ServerException('Invalid file type'); } - $file = Attachment::validateAndStoreFile($sfile, Common::config('cover', 'dir'), $title = null, $is_local = true, $use_unique = $actor_id); + $file = GSFile::sanitizeAndStoreFileAsAttachment($sfile); $old_file = null; $cover = DB::find('cover', ['gsactor_id' => $actor_id]); // Must get old id before inserting another one @@ -152,6 +151,6 @@ class Cover if ($file == null) { return new Response('Cover File not found',Response::HTTP_NOT_FOUND); } - return M::sendFile($cover->getFilePath(), $file->getMimetype(), $file->getTitle()); + return GSFile::sendFile($cover->getFilePath(), $file->getMimetype(), $file->getTitle()); } } diff --git a/plugins/Cover/Entity/Cover.php b/plugins/Cover/Entity/Cover.php index fad8eb4608..cba810fbf9 100644 --- a/plugins/Cover/Entity/Cover.php +++ b/plugins/Cover/Entity/Cover.php @@ -23,6 +23,7 @@ namespace Plugin\Cover\Entity; use App\Core\DB\DB; use App\Core\Entity; +use App\Entity\Attachment; use App\Util\Common; use DateTimeInterface; diff --git a/plugins/Embed/Controller/Embed.php b/plugins/Embed/Controller/Embed.php index 5a7b3494f8..cb9d275678 100644 --- a/plugins/Embed/Controller/Embed.php +++ b/plugins/Embed/Controller/Embed.php @@ -33,6 +33,7 @@ namespace Plugin\Embed\Controller; use App\Core\Controller; +use App\Util\Exception\NotImplementedException; use Symfony\Component\HttpFoundation\Request; /** @@ -52,208 +53,211 @@ class Embed extends Controller */ protected function handle(Request $request) { - $url = $this->trimmed('url'); - $tls = parse_url($url, PHP_URL_SCHEME) == 'https'; - $root_url = common_root_url($tls); + throw new NotImplementedException(); + // $url = $this->trimmed('url'); + // $tls = parse_url($url, PHP_URL_SCHEME) == 'https'; + // $root_url = common_root_url($tls); - if (substr(strtolower($url), 0, mb_strlen($root_url)) !== strtolower($root_url)) { - // TRANS: Error message displaying attachments. %s is the site's base URL. - throw new ClientException(sprintf(_('Embed data will only be provided for %s URLs.'), $root_url)); - } + // if (substr(strtolower($url), 0, mb_strlen($root_url)) !== strtolower($root_url)) { + // // TRANS: Error message displaying attachments. %s is the site's base URL. + // throw new ClientException(sprintf(_('Embed data will only be provided for %s URLs.'), $root_url)); + // } - $path = substr($url, strlen($root_url)); + // $path = substr($url, strlen($root_url)); - $r = Router::get(); + // $r = Router::get(); - // $r->map will throw ClientException 404 if it fails to find a mapping - $proxy_args = $r->map($path); + // // $r->map will throw ClientException 404 if it fails to find a mapping + // $proxy_args = $r->map($path); - $oembed = []; - $oembed['version'] = '1.0'; - $oembed['provider_name'] = common_config('site', 'name'); - $oembed['provider_url'] = common_root_url(); + // $oembed = []; + // $oembed['version'] = '1.0'; + // $oembed['provider_name'] = common_config('site', 'name'); + // $oembed['provider_url'] = common_root_url(); - switch ($proxy_args['action']) { - case 'shownotice': - $oembed['type'] = 'link'; - try { - $notice = Notice::getByID($proxy_args['notice']); - } catch (NoResultException $e) { - throw new ClientException($e->getMessage(), 404); - } - $profile = $notice->getProfile(); - $authorname = $profile->getFancyName(); - // TRANS: oEmbed title. %1$s is the author name, %2$s is the creation date. - $oembed['title'] = sprintf( - _('%1$s\'s status on %2$s'), - $authorname, - common_exact_date($notice->created) - ); - $oembed['author_name'] = $authorname; - $oembed['author_url'] = $profile->profileurl; - $oembed['url'] = $notice->getUrl(); - $oembed['html'] = $notice->getRendered(); + // switch ($proxy_args['action']) { + // case 'shownotice': + // $oembed['type'] = 'link'; + // try { + // $notice = Notice::getByID($proxy_args['notice']); + // } catch (NoResultException $e) { + // throw new ClientException($e->getMessage(), 404); + // } + // $profile = $notice->getProfile(); + // $authorname = $profile->getFancyName(); + // // TRANS: oEmbed title. %1$s is the author name, %2$s is the creation date. + // $oembed['title'] = sprintf( + // _('%1$s\'s status on %2$s'), + // $authorname, + // common_exact_date($notice->created) + // ); + // $oembed['author_name'] = $authorname; + // $oembed['author_url'] = $profile->profileurl; + // $oembed['url'] = $notice->getUrl(); + // $oembed['html'] = $notice->getRendered(); - // maybe add thumbnail - foreach ($notice->attachments() as $attachment) { - if (!$attachment instanceof File) { - common_debug('ATTACHMENTS array entry from notice id==' . _ve($notice->getID()) . - ' is something else than a File dataobject: ' . _ve($attachment)); - continue; - } - try { - $thumb = $attachment->getThumbnail(); - $thumb_url = $thumb->getUrl(); - $oembed['thumbnail_url'] = $thumb_url; - break; // only first one - } catch (UseFileAsThumbnailException $e) { - $oembed['thumbnail_url'] = $attachment->getUrl(); - break; // we're happy with that - } catch (ServerException $e) { - } catch (ClientException $e) { - } - } - break; + // // maybe add thumbnail + // foreach ($notice->attachments() as $attachment) { + // if (!$attachment instanceof File) { + // common_debug('ATTACHMENTS array entry from notice id==' . _ve($notice->getID()) . + // ' is something else than a File dataobject: ' . _ve($attachment)); + // continue; + // } + // try { + // $thumb = $attachment->getThumbnail(); + // $thumb_url = $thumb->getUrl(); + // $oembed['thumbnail_url'] = $thumb_url; + // break; // only first one + // } catch (UseFileAsThumbnailException $e) { + // $oembed['thumbnail_url'] = $attachment->getUrl(); + // break; // we're happy with that + // } catch (ServerException $e) { + // } catch (ClientException $e) { + // } + // } + // break; - case 'attachment': - $id = $proxy_args['attachment']; - $attachment = File::getKV($id); - if (empty($attachment)) { - // TRANS: Client error displayed in oEmbed action when attachment not found. - // TRANS: %d is an attachment ID. - $this->clientError(sprintf(_('Attachment %s not found.'), $id), 404); - } - if ( - empty($attachment->filename) - && !empty($file_oembed = File_oembed::getKV( - 'file_id', - $attachment->id - )) - ) { - // Proxy the existing oembed information - $oembed['type'] = $file_oembed->type; - $oembed['provider'] = $file_oembed->provider; - $oembed['provider_url'] = $file_oembed->provider_url; - $oembed['width'] = $file_oembed->width; - $oembed['height'] = $file_oembed->height; - $oembed['html'] = $file_oembed->html; - $oembed['title'] = $file_oembed->title; - $oembed['author_name'] = $file_oembed->author_name; - $oembed['author_url'] = $file_oembed->author_url; - $oembed['url'] = $file_oembed->getUrl(); - } elseif (substr($attachment->mimetype, 0, strlen('image/')) === 'image/') { - $oembed['type'] = 'photo'; - if ($attachment->filename) { - $filepath = File::path($attachment->filename); - $gis = @getimagesize($filepath); - if ($gis) { - $oembed['width'] = $gis[0]; - $oembed['height'] = $gis[1]; - } else { - // TODO Either throw an error or find a fallback? - } - } - $oembed['url'] = $attachment->getUrl(); - try { - $thumb = $attachment->getThumbnail(); - $oembed['thumbnail_url'] = $thumb->getUrl(); - $oembed['thumbnail_width'] = $thumb->width; - $oembed['thumbnail_height'] = $thumb->height; - unset($thumb); - } catch (UnsupportedMediaException $e) { - // No thumbnail data available - } - } else { - $oembed['type'] = 'link'; - $oembed['url'] = common_local_url( - 'attachment', - ['attachment' => $attachment->id] - ); - } - if ($attachment->title) { - $oembed['title'] = $attachment->title; - } - break; - default: - // TRANS: Server error displayed in oEmbed request when a path is not supported. - // TRANS: %s is a path. - $this->serverError(sprintf(_('"%s" not supported for oembed requests.'), $path), 501); - } + // case 'attachment': + // $id = $proxy_args['attachment']; + // $attachment = File::getKV($id); + // if (empty($attachment)) { + // // TRANS: Client error displayed in oEmbed action when attachment not found. + // // TRANS: %d is an attachment ID. + // $this->clientError(sprintf(_('Attachment %s not found.'), $id), 404); + // } + // if ( + // empty($attachment->filename) + // && !empty($file_oembed = File_oembed::getKV( + // 'file_id', + // $attachment->id + // )) + // ) { + // // Proxy the existing oembed information + // $oembed['type'] = $file_oembed->type; + // $oembed['provider'] = $file_oembed->provider; + // $oembed['provider_url'] = $file_oembed->provider_url; + // $oembed['width'] = $file_oembed->width; + // $oembed['height'] = $file_oembed->height; + // $oembed['html'] = $file_oembed->html; + // $oembed['title'] = $file_oembed->title; + // $oembed['author_name'] = $file_oembed->author_name; + // $oembed['author_url'] = $file_oembed->author_url; + // $oembed['url'] = $file_oembed->getUrl(); + // } elseif (substr($attachment->mimetype, 0, strlen('image/')) === 'image/') { + // $oembed['type'] = 'photo'; + // if ($attachment->filename) { + // $filepath = File::path($attachment->filename); + // $gis = @getimagesize($filepath); + // if ($gis) { + // $oembed['width'] = $gis[0]; + // $oembed['height'] = $gis[1]; + // } else { + // // TODO Either throw an error or find a fallback? + // } + // } + // $oembed['url'] = $attachment->getUrl(); + // try { + // $thumb = $attachment->getThumbnail(); + // $oembed['thumbnail_url'] = $thumb->getUrl(); + // $oembed['thumbnail_width'] = $thumb->width; + // $oembed['thumbnail_height'] = $thumb->height; + // unset($thumb); + // } catch (UnsupportedMediaException $e) { + // // No thumbnail data available + // } + // } else { + // $oembed['type'] = 'link'; + // $oembed['url'] = common_local_url( + // 'attachment', + // ['attachment' => $attachment->id] + // ); + // } + // if ($attachment->title) { + // $oembed['title'] = $attachment->title; + // } + // break; + // default: + // // TRANS: Server error displayed in oEmbed request when a path is not supported. + // // TRANS: %s is a path. + // $this->serverError(sprintf(_('"%s" not supported for oembed requests.'), $path), 501); + // } - switch ($this->trimmed('format')) { - case 'xml': - $this->init_document('xml'); - $this->elementStart('oembed'); - foreach ([ - 'version', 'type', 'provider_name', - 'provider_url', 'title', 'author_name', - 'author_url', 'url', 'html', 'width', - 'height', 'cache_age', 'thumbnail_url', - 'thumbnail_width', 'thumbnail_height', - ] as $key) { - if (isset($oembed[$key]) && $oembed[$key] != '') { - $this->element($key, null, $oembed[$key]); - } - } - $this->elementEnd('oembed'); - $this->end_document('xml'); - break; + // switch ($this->trimmed('format')) { + // case 'xml': + // $this->init_document('xml'); + // $this->elementStart('oembed'); + // foreach ([ + // 'version', 'type', 'provider_name', + // 'provider_url', 'title', 'author_name', + // 'author_url', 'url', 'html', 'width', + // 'height', 'cache_age', 'thumbnail_url', + // 'thumbnail_width', 'thumbnail_height', + // ] as $key) { + // if (isset($oembed[$key]) && $oembed[$key] != '') { + // $this->element($key, null, $oembed[$key]); + // } + // } + // $this->elementEnd('oembed'); + // $this->end_document('xml'); + // break; - case 'json': - case null: - $this->init_document('json'); - $this->raw(json_encode($oembed)); - $this->end_document('json'); - break; - default: - // TRANS: Error message displaying attachments. %s is a raw MIME type (eg 'image/png') - $this->serverError(sprintf(_('Content type %s not supported.'), $apidata['content-type']), 501); - } + // case 'json': + // case null: + // $this->init_document('json'); + // $this->raw(json_encode($oembed)); + // $this->end_document('json'); + // break; + // default: + // // TRANS: Error message displaying attachments. %s is a raw MIME type (eg 'image/png') + // $this->serverError(sprintf(_('Content type %s not supported.'), $apidata['content-type']), 501); + // } } /** Placeholder */ public function init_document($type) { - switch ($type) { - case 'xml': - header('Content-Type: application/xml; charset=utf-8'); - $this->startXML(); - break; - case 'json': - header('Content-Type: application/json; charset=utf-8'); + throw new NotImplementedException; + // switch ($type) { + // case 'xml': + // header('Content-Type: application/xml; charset=utf-8'); + // $this->startXML(); + // break; + // case 'json': + // header('Content-Type: application/json; charset=utf-8'); - // Check for JSONP callback - $callback = $this->arg('callback'); - if ($callback) { - echo $callback . '('; - } - break; - default: - // TRANS: Server error displayed in oEmbed action when request specifies an unsupported data format. - $this->serverError(_('Not a supported data format.'), 501); - break; - } + // // Check for JSONP callback + // $callback = $this->arg('callback'); + // if ($callback) { + // echo $callback . '('; + // } + // break; + // default: + // // TRANS: Server error displayed in oEmbed action when request specifies an unsupported data format. + // $this->serverError(_('Not a supported data format.'), 501); + // break; + // } } /** Placeholder */ public function end_document($type) { - switch ($type) { - case 'xml': - $this->endXML(); - break; - case 'json': - // Check for JSONP callback - $callback = $this->arg('callback'); - if ($callback) { - echo ')'; - } - break; - default: - // TRANS: Server error displayed in oEmbed action when request specifies an unsupported data format. - $this->serverError(_('Not a supported data format.'), 501); - break; - } + throw new NotImplementedException; + // switch ($type) { + // case 'xml': + // $this->endXML(); + // break; + // case 'json': + // // Check for JSONP callback + // $callback = $this->arg('callback'); + // if ($callback) { + // echo ')'; + // } + // break; + // default: + // // TRANS: Server error displayed in oEmbed action when request specifies an unsupported data format. + // $this->serverError(_('Not a supported data format.'), 501); + // break; + // } } /** diff --git a/plugins/Embed/Test/EmbedTest.php b/plugins/Embed/Test/EmbedTest.php index dbe56ce195..107990c44c 100644 --- a/plugins/Embed/Test/EmbedTest.php +++ b/plugins/Embed/Test/EmbedTest.php @@ -43,31 +43,31 @@ final class EmbedTest extends TestCase */ public function testEmbed($url, $expectedType) { - try { - $data = EmbedHelper::getObject($url); - static::assertSame($expectedType, $data->type); - if ($data->type == 'photo') { - static::assertTrue(!empty($data->thumbnail_url), 'Photo must have a URL.'); - static::assertTrue(!empty($data->thumbnail_width), 'Photo must have a width.'); - static::assertTrue(!empty($data->thumbnail_height), 'Photo must have a height.'); - } elseif ($data->type == 'video') { - static::assertTrue(!empty($data->html), 'Video must have embedding HTML.'); - static::assertTrue(!empty($data->thumbnail_url), 'Video should have a thumbnail.'); - } else { - static::assertTrue(!empty($data->title), 'Page must have a title'); - static::assertTrue(!empty($data->url), 'Page must have a URL'); - } - if (!empty($data->thumbnail_url)) { - static::assertTrue(!empty($data->thumbnail_width), 'Thumbnail must list a width.'); - static::assertTrue(!empty($data->thumbnail_height), 'Thumbnail must list a height.'); - } - } catch (Exception $e) { - if ($expectedType == 'none') { - static::assertSame($expectedType, 'none', 'Should not have data for this URL.'); - } else { - throw $e; - } - } + // try { + // $data = EmbedHelper::getObject($url); + // static::assertSame($expectedType, $data->type); + // if ($data->type == 'photo') { + // static::assertTrue(!empty($data->thumbnail_url), 'Photo must have a URL.'); + // static::assertTrue(!empty($data->thumbnail_width), 'Photo must have a width.'); + // static::assertTrue(!empty($data->thumbnail_height), 'Photo must have a height.'); + // } elseif ($data->type == 'video') { + // static::assertTrue(!empty($data->html), 'Video must have embedding HTML.'); + // static::assertTrue(!empty($data->thumbnail_url), 'Video should have a thumbnail.'); + // } else { + // static::assertTrue(!empty($data->title), 'Page must have a title'); + // static::assertTrue(!empty($data->url), 'Page must have a URL'); + // } + // if (!empty($data->thumbnail_url)) { + // static::assertTrue(!empty($data->thumbnail_width), 'Thumbnail must list a width.'); + // static::assertTrue(!empty($data->thumbnail_height), 'Thumbnail must list a height.'); + // } + // } catch (Exception $e) { + // if ($expectedType == 'none') { + // static::assertSame($expectedType, 'none', 'Should not have data for this URL.'); + // } else { + // throw $e; + // } + // } } public static function sources() diff --git a/plugins/Favourite/Controller/Favourite.php b/plugins/Favourite/Controller/Favourite.php index b842bc1f8f..89f83a7079 100644 --- a/plugins/Favourite/Controller/Favourite.php +++ b/plugins/Favourite/Controller/Favourite.php @@ -35,7 +35,8 @@ class Favourite 'where f.gsactor_id = :id ' . 'order by f.created DESC', ['id' => $actor_id]); - Event::handle('FormatNoteList', [$notes, &$note_out]); + $notes_out = null; + Event::handle('FormatNoteList', [$notes, &$notes_out]); return [ '_template' => 'network/public.html.twig', @@ -62,6 +63,7 @@ class Favourite 'order by f.created DESC' , ['id' => $actor_id]); + $notes_out = null; Event::handle('FormatNoteList', [$notes, &$notes_out]); return [ diff --git a/plugins/Poll/Controller/AnswerPoll.php b/plugins/Poll/Controller/AnswerPoll.php index 0438fb79bb..a3d74b28fd 100644 --- a/plugins/Poll/Controller/AnswerPoll.php +++ b/plugins/Poll/Controller/AnswerPoll.php @@ -22,13 +22,14 @@ namespace Plugin\Poll\Controller; use App\Core\DB\DB; -use App\Entity\Poll; -use App\Entity\PollResponse; +use App\Core\Form; use App\Util\Common; use App\Util\Exception\InvalidFormException; use App\Util\Exception\NotFoundException; use App\Util\Exception\RedirectException; use App\Util\Exception\ServerException; +use Plugin\Poll\Entity\Poll; +use Plugin\Poll\Entity\PollResponse; use Plugin\Poll\Forms\PollResponseForm; use Symfony\Component\HttpFoundation\Request; @@ -62,14 +63,14 @@ class AnswerPoll { $user = Common::ensureLoggedIn(); - $poll = Poll::getFromId((int) $id); + $poll = Poll::getWithPk((int) $id); if ($poll == null) { throw new NotFoundException('Poll does not exist'); } $question = $poll->getQuestion(); $opts = $poll->getOptionsArr(); - $form = PollResponseForm::make($poll, $poll->getNoteId()); + $form = Form::create([]); //PollResponseForm::make($poll, $poll->getNoteId()); $form->handleRequest($request); if ($form->isSubmitted()) { if ($form->isValid()) { diff --git a/plugins/Poll/Controller/NewPoll.php b/plugins/Poll/Controller/NewPoll.php index 44a721d1d0..dc6e9cfd81 100644 --- a/plugins/Poll/Controller/NewPoll.php +++ b/plugins/Poll/Controller/NewPoll.php @@ -26,10 +26,10 @@ use App\Core\Form; use function App\Core\I18n\_m; use App\Core\Security; use App\Entity\Note; -use App\Entity\Poll; use App\Util\Common; use App\Util\Exception\InvalidFormException; use App\Util\Exception\RedirectException; +use Plugin\Poll\Entity\Poll; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\TextType; diff --git a/plugins/Poll/Poll.php b/plugins/Poll/Poll.php index c71148097d..1a50aafe48 100644 --- a/plugins/Poll/Poll.php +++ b/plugins/Poll/Poll.php @@ -27,7 +27,6 @@ use function App\Core\I18n\_m; use App\Core\Modules\NoteHandlerPlugin; use App\Core\Router\RouteLoader; use App\Entity\Note; -use App\Entity\PollResponse; use App\Util\Common; use App\Util\Exception\InvalidFormException; use App\Util\Exception\NotFoundException; @@ -117,7 +116,7 @@ class Poll extends NoteHandlerPlugin return Event::next; } - if (Common::isLoggedIn() && !PollResponse::exits($poll->getId(), Common::ensureLoggedIn()->getId())) { + if (Common::isLoggedIn() && !Entity\PollResponse::exits($poll->getId(), Common::ensureLoggedIn()->getId())) { $opts = $poll->getOptionsArr(); $options = []; for ($i = 1; $i <= count($opts); ++$i) { @@ -143,7 +142,7 @@ class Poll extends NoteHandlerPlugin return Event::next; } - if (PollResponse::exits($poll->getId(), $user->getId())) { + if (Entity\PollResponse::exits($poll->getId(), $user->getId())) { return Event::next; } @@ -151,10 +150,10 @@ class Poll extends NoteHandlerPlugin if (!$poll->isValidSelection($selection)) { throw new InvalidFormException(); } - if (PollResponse::exits($poll->getId(), $user->getId())) { + if (Entity\PollResponse::exits($poll->getId(), $user->getId())) { throw new ServerException('User already responded to poll'); } - $pollResponse = PollResponse::create(['poll_id' => $poll->getId(), 'gsactor_id' => $user->getId(), 'selection' => $selection]); + $pollResponse = Entity\PollResponse::create(['poll_id' => $poll->getId(), 'gsactor_id' => $user->getId(), 'selection' => $selection]); DB::persist($pollResponse); DB::flush(); diff --git a/plugins/ProfileColor/Controller/ProfileColor.php b/plugins/ProfileColor/Controller/ProfileColor.php index 6865162e5d..ce5933f8d6 100644 --- a/plugins/ProfileColor/Controller/ProfileColor.php +++ b/plugins/ProfileColor/Controller/ProfileColor.php @@ -24,9 +24,9 @@ namespace Plugin\ProfileColor\Controller; use App\Core\DB\DB; use App\Core\Form; use function App\Core\I18n\_m; -use App\Entity\ProfileColor as PColor; use App\Util\Common; use App\Util\Exception\RedirectException; +use Plugin\ProfileColor\Entity; use Symfony\Component\Form\Extension\Core\Type\ColorType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -78,7 +78,7 @@ class ProfileColor DB::flush(); } - $pcolor = PColor::create(['gsactor_id' => $actor_id, 'color' => $data['color']]); + $pcolor = Entity\ProfileColor::create(['gsactor_id' => $actor_id, 'color' => $data['color']]); DB::persist($pcolor); DB::flush(); throw new RedirectException(); diff --git a/plugins/Reply/Controller/Reply.php b/plugins/Reply/Controller/Reply.php index 3ecd09e95b..13c742ca4a 100644 --- a/plugins/Reply/Controller/Reply.php +++ b/plugins/Reply/Controller/Reply.php @@ -34,6 +34,7 @@ use App\Entity\Note; use App\Util\Common; use App\Util\Exception\ClientException; use App\Util\Exception\InvalidFormException; +use App\Util\Exception\NoSuchNoteException; use App\Util\Exception\RedirectException; use Component\Posting\Posting; use Symfony\Component\Form\Extension\Core\Type\FileType; diff --git a/plugins/Reply/Reply.php b/plugins/Reply/Reply.php index 95f98d219f..eef6a81a42 100644 --- a/plugins/Reply/Reply.php +++ b/plugins/Reply/Reply.php @@ -27,6 +27,7 @@ use App\Core\Modules\NoteHandlerPlugin; use App\Entity\Note; use App\Util\Common; use App\Util\Exception\RedirectException; +use Component\Posting\Posting; use Plugin\Reply\Controller\Reply as ReplyController; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; diff --git a/src/Controller/Attachment.php b/src/Controller/Attachment.php index 948daa606a..b079734c69 100644 --- a/src/Controller/Attachment.php +++ b/src/Controller/Attachment.php @@ -52,6 +52,7 @@ class Attachment extends Controller throw new ClientException(_m('No such attachment'), 404); // @codeCoverageIgnoreEnd } else { + $res = null; if (Event::handle('AttachmentFileInfo', [$id, &$res]) != Event::stop) { // If no one else claims this attachment, use the default representation try { @@ -142,6 +143,7 @@ class Attachment extends Controller $height = $this->int('h') ?: $default_height; $crop = $this->bool('c') ?: $default_crop; + $sizes = null; Event::handle('GetAllowedThumbnailSizes', [&$sizes]); if (!in_array(['width' => $width, 'height' => $height], $sizes)) { throw new ClientException(_m('The requested thumbnail dimensions are not allowed'), 400); // 400 Bad Request diff --git a/src/Controller/Network.php b/src/Controller/Network.php index 7f4adecccc..5fa320bea4 100644 --- a/src/Controller/Network.php +++ b/src/Controller/Network.php @@ -56,6 +56,7 @@ class Network extends Controller { $notes = Note::getAllNotes($this->instance_scope); + $notes_out = null; Event::handle('FormatNoteList', [$notes, &$notes_out]); return [ @@ -98,6 +99,7 @@ class Network extends Controller END; $notes = DB::sql($query, ['note' => 'App\Entity\Note'], ['target_actor_id' => $target->getId()]); + $notes_out = null; Event::handle('FormatNoteList', [$notes, &$notes_out]); return [ @@ -110,6 +112,7 @@ END; { $notes = Note::getAllNotes($this->public_scope); + $notes_out = null; Event::handle('FormatNoteList', [$notes, &$notes_out]); return [ @@ -125,6 +128,7 @@ END; 'where n.reply_to is not null and n.gsactor_id = :id ' . 'order by n.created DESC', ['id' => $actor_id]); + $notes_out = null; Event::handle('FormatNoteList', [$notes, &$notes_out]); return [ diff --git a/src/Controller/ResetPassword.php b/src/Controller/ResetPassword.php index e91bba17a5..85abda267d 100644 --- a/src/Controller/ResetPassword.php +++ b/src/Controller/ResetPassword.php @@ -3,9 +3,16 @@ namespace App\Controller; use App\Core\Controller; +use App\Core\DB\DB; +use App\Core\Form; +use function App\Core\I18n\_m; use App\Entity\LocalUser; +use App\Security\EmailVerifier; +use App\Util\Exception\ClientException; use App\Util\Exception\RedirectException; +use App\Util\Form\FormFields; use Symfony\Component\Form\Extension\Core\Type\EmailType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Validator\Constraints\NotBlank; use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait; @@ -26,7 +33,7 @@ class ResetPassword extends Controller */ public function requestPasswordReset(Request $request) { - $from = Form::create([ + $form = Form::create([ ['email', EmailType::class, ['label' => _m('Email'), 'constraints' => [ new NotBlank(['message' => _m('Please enter an email') ]) ]]], ['password_reset_request', SubmitType::class, ['label' => _m('Submit request')]], ]); @@ -38,7 +45,7 @@ class ResetPassword extends Controller return [ '_template' => 'reset_password/request.html.twig', - 'password_reset_form' => $from->createView(), + 'password_reset_form' => $form->createView(), ]; } @@ -83,7 +90,7 @@ class ResetPassword extends Controller } // The token is valid; allow the user to change their password. - $form = From::create([ + $form = Form::create([ FormFields::repeated_password(), ['password_reset', SubmitType::class, ['label' => _m('Change password')]], ]); diff --git a/src/Controller/Security.php b/src/Controller/Security.php index dd8a1b382f..f2e130497e 100644 --- a/src/Controller/Security.php +++ b/src/Controller/Security.php @@ -13,7 +13,8 @@ use App\Entity\GSActor; use App\Entity\LocalUser; use App\Entity\Note; use App\Security\Authenticator; -use app\Util\Common; +use App\Security\EmailVerifier; +use App\Util\Common; use App\Util\Exception\EmailTakenException; use App\Util\Exception\NicknameTakenException; use App\Util\Exception\ServerException; @@ -142,7 +143,7 @@ class Security extends Controller // generate a signed url and email it to the user if ($_ENV['APP_ENV'] !== 'dev' && Common::config('site', 'use_email')) { // @codeCoverageIgnoreStart - Common::sendVerificationEmail(); + EmailVerifier::sendEmailConfirmation($user); // @codeCoverageIgnoreEnd } else { $user->setIsEmailVerified(true); diff --git a/src/Controller/UserPanel.php b/src/Controller/UserPanel.php index 28dbcc331d..8250169a13 100644 --- a/src/Controller/UserPanel.php +++ b/src/Controller/UserPanel.php @@ -43,6 +43,7 @@ use App\Entity\UserNotificationPrefs; use App\Util\Common; use App\Util\Exception\AuthenticationException; use App\Util\Exception\ServerException; +use App\Util\Form\ActorArrayTransformer; use App\Util\Form\ArrayTransformer; use App\Util\Form\FormFields; use App\Util\Formatting; diff --git a/src/Core/Cache.php b/src/Core/Cache.php index 4fbc1d3620..9cbed62e15 100644 --- a/src/Core/Cache.php +++ b/src/Core/Cache.php @@ -73,7 +73,7 @@ abstract class Cache } $class = RedisCluster::class; // true for persistent connection $seeds = F\Map($dsns, fn ($str) => explode('://', $str)[1]); - $r = new RedisCluster(name: null, seeds: $seeds, timeout: null, read_timeout: null, persistent: true); + $r = new RedisCluster(name: null, seeds: $seeds, timeout: null, readTimeout: null, persistent: true); // Distribute reads randomly $r->setOption($class::OPT_SLAVE_FAILOVER, $class::FAILOVER_DISTRIBUTE); // @codeCoverageIgnoreEnd @@ -102,7 +102,7 @@ abstract class Cache $adapters[$pool][] = new Adapter\ApcuAdapter(); break; case 'opcache': - $adapters[$pool][] = new Adapter\PhpArrayAdapter($rest, new FilesystemAdapter($rest . '.fallback')); + $adapters[$pool][] = new Adapter\PhpArrayAdapter($rest, new Adapter\FilesystemAdapter($rest . '.fallback')); break; case 'doctrine': $adapters[$pool][] = new Adapter\PdoAdapter($dsn); diff --git a/src/Core/Entity.php b/src/Core/Entity.php index 0db870a9b8..70c6924946 100644 --- a/src/Core/Entity.php +++ b/src/Core/Entity.php @@ -23,7 +23,6 @@ namespace App\Core; use App\Core\DB\DB; use App\Util\Exception\NotFoundException; -use App\Util\Exception\ServerException; use App\Util\Formatting; use DateTime; @@ -53,7 +52,7 @@ abstract class Entity */ public static function create(array $args, $obj = null) { - $class = get_called_class(); + $class = static::class; $obj = $obj ?: new $class(); $date = new DateTime(); foreach (['created', 'modified'] as $prop) { diff --git a/src/Core/Modules/Module.php b/src/Core/Modules/Module.php index a420fa4f9d..ca8602f442 100644 --- a/src/Core/Modules/Module.php +++ b/src/Core/Modules/Module.php @@ -20,13 +20,14 @@ namespace App\Core\Modules; use App\Util\Common; -use App\Util\Formatting; /** * Base class for all GNU social modules (plugins and components) */ abstract class Module { + const MODULE_TYPE = 'module'; + /** * Load values from the config and set them as properties on each module object */ @@ -54,8 +55,7 @@ abstract class Module */ public static function __set_state($state) { - $class = get_called_class(); - $obj = new $class(); + $obj = new (static::class); foreach ($state as $k => $v) { $obj->{$k} = $v; } diff --git a/src/Entity/Invitation.php b/src/Entity/Invitation.php index 13f8d5fa60..c0437bfed2 100644 --- a/src/Entity/Invitation.php +++ b/src/Entity/Invitation.php @@ -125,7 +125,7 @@ class Invitation extends Entity 'user_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'LocalUser.id', 'multiplicity' => 'many to one', 'name' => 'invitation_user_id_fkey', 'not null' => true, 'description' => 'who sent the invitation'], 'address' => ['type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'invitation sent to'], 'address_type' => ['type' => 'varchar', 'length' => 8, 'not null' => true, 'description' => 'address type ("email", "xmpp", "sms")'], - 'registered_user_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'LocalUser.id', 'multiplicity' => 'one to one', 'name' => 'invitation_registered_user_id_fkey', 'type' => 'int', 'not null' => false, 'description' => 'if the invitation is converted, who the new user is'], + 'registered_user_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'LocalUser.id', 'multiplicity' => 'one to one', 'name' => 'invitation_registered_user_id_fkey', 'not null' => false, 'description' => 'if the invitation is converted, who the new user is'], 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], ], 'primary key' => ['code'], diff --git a/src/Entity/RelatedGroup.php b/src/Entity/RelatedGroup.php index 2698704801..8bd32d968a 100644 --- a/src/Entity/RelatedGroup.php +++ b/src/Entity/RelatedGroup.php @@ -87,7 +87,7 @@ class RelatedGroup extends Entity // @fixme description for related_group? 'fields' => [ 'group_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Group.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'foreign key to group'], - 'related_group_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Group.id', 'multiplicity' => 'one to one', 'type' => 'int', 'not null' => true, 'description' => 'foreign key to group'], + 'related_group_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Group.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'foreign key to group'], 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], ], 'primary key' => ['group_id', 'related_group_id'], diff --git a/src/Kernel.php b/src/Kernel.php index 1dc1b6ed19..1a14e014c6 100644 --- a/src/Kernel.php +++ b/src/Kernel.php @@ -47,35 +47,6 @@ class Kernel extends BaseKernel public const CONFIG_EXTS = '.{php,xml,yaml,yml}'; - public function __construct(string $environment, bool $debug) - { - parent::__construct($environment, $debug); - - if (!defined('INSTALLDIR')) { - define('INSTALLDIR', dirname(__DIR__)); - define('SRCDIR', INSTALLDIR . '/src'); - define('PUBLICDIR', INSTALLDIR . '/public'); - define('GNUSOCIAL_ENGINE_NAME', 'GNU social'); - // MERGE Change to https://gnu.io/social/ - define('GNUSOCIAL_PROJECT_URL', 'https://gnusocial.rocks/'); - // 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 - define('GNUSOCIAL_BASE_VERSION', '3.0.0'); - // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' - define('GNUSOCIAL_LIFECYCLE', 'dev'); - define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE); - define('GNUSOCIAL_CODENAME', 'Big bang'); - define('URL_REGEX_DOMAIN_NAME', '(?:(?!-)[A-Za-z0-9\-]{1,63}(?send($email); } @@ -77,7 +80,7 @@ abstract class EmailVerifier DB::flush(); } - public function processSendingPasswordResetEmail(string $emailFormData, Controller $controller) + public static function processSendingPasswordResetEmail(string $emailFormData, Controller $controller) { try { $user = DB::findOneBy('local_user', ['outgoing_email' => $emailFormData]); diff --git a/src/Util/Bitmap.php b/src/Util/Bitmap.php index ab8c2a3385..1764abd597 100644 --- a/src/Util/Bitmap.php +++ b/src/Util/Bitmap.php @@ -32,7 +32,7 @@ abstract class Bitmap private static function _to(int $r, bool $instance) { $init = $r; - $class = get_called_class(); + $class = static::class; if ($instance) { $obj = new $class; } else { diff --git a/src/Util/Exception/RedirectException.php b/src/Util/Exception/RedirectException.php index da16eab05b..7aefca6eac 100644 --- a/src/Util/Exception/RedirectException.php +++ b/src/Util/Exception/RedirectException.php @@ -19,6 +19,8 @@ namespace App\Util\Exception; +use function App\Core\I18n\_m; +use App\Core\Log; use App\Core\Router\Router; use Exception; use Symfony\Component\HttpFoundation\RedirectResponse; diff --git a/src/Util/Form/FormFields.php b/src/Util/Form/FormFields.php index 764346b49d..7b06b8ffb2 100644 --- a/src/Util/Form/FormFields.php +++ b/src/Util/Form/FormFields.php @@ -45,17 +45,18 @@ abstract class FormFields */ public static function password(array $options = []): array { - ['password', PasswordType::class, [ - 'label' => _m('Password'), - 'label_attr' => ['class' => 'section-form-label'], - 'attr' => ['placeholder' => '********'], - 'required' => $options['required'] ?? true, - 'mapped' => false, - 'constraints' => [ - new NotBlank(['message' => _m('Please enter a password')]), - new Length(['min' => Common::config('password', 'min_length'), 'minMessage' => _m(['Your password should be at least # characters'], ['count' => Common::config('password', 'min_length')]), - 'max' => Common::config('password', 'max_length'), 'maxMessage' => _m(['Your password should be at most # characters'], ['count' => Common::config('password', 'max_length')]), ]), - ], ], + return [ + 'password', PasswordType::class, [ + 'label' => _m('Password'), + 'label_attr' => ['class' => 'section-form-label'], + 'attr' => ['placeholder' => '********'], + 'required' => $options['required'] ?? true, + 'mapped' => false, + 'constraints' => [ + new NotBlank(['message' => _m('Please enter a password')]), + new Length(['min' => Common::config('password', 'min_length'), 'minMessage' => _m(['Your password should be at least # characters'], ['count' => Common::config('password', 'min_length')]), + 'max' => Common::config('password', 'max_length'), 'maxMessage' => _m(['Your password should be at most # characters'], ['count' => Common::config('password', 'max_length')]), ]), + ], ], ]; } } diff --git a/src/Util/Nickname.php b/src/Util/Nickname.php index f995a9d718..886455c9c8 100644 --- a/src/Util/Nickname.php +++ b/src/Util/Nickname.php @@ -31,6 +31,7 @@ use App\Util\Exception\NicknameReservedException; use App\Util\Exception\NicknameTakenException; use App\Util\Exception\NicknameTooLongException; use App\Util\Exception\NicknameTooShortException; +use App\Util\Exception\NotImplementedException; use Functional as F; use Normalizer; @@ -154,7 +155,7 @@ class Nickname break; // @codeCoverageIgnoreStart case self::CHECK_LOCAL_GROUP: - throw new \NotImplementedException(); + throw new NotImplementedException(); break; default: throw new \InvalidArgumentException(); diff --git a/src/Util/Notification/Notification.php b/src/Util/Notification/Notification.php index f6014373ec..8c4743ded7 100644 --- a/src/Util/Notification/Notification.php +++ b/src/Util/Notification/Notification.php @@ -30,7 +30,7 @@ namespace App\Util\Notification; -use App\Entity\Gsactor; +use App\Entity\GSActor; class Notification { diff --git a/src/Util/TemporaryFile.php b/src/Util/TemporaryFile.php index d840c75466..c6e5a0b420 100644 --- a/src/Util/TemporaryFile.php +++ b/src/Util/TemporaryFile.php @@ -19,6 +19,7 @@ namespace App\Util; +use function App\Core\I18n\_m; use App\Util\Exception\TemporaryFileException; use Symfony\Component\Mime\MimeTypes; diff --git a/tests/Entity/AttachmentTest.php b/tests/Entity/AttachmentTest.php index beb58bc094..2fed109d2f 100644 --- a/tests/Entity/AttachmentTest.php +++ b/tests/Entity/AttachmentTest.php @@ -76,6 +76,7 @@ class AttachmentTest extends GNUsocialTestCase $test = function (string $method) { $temp_file = new TemporaryFile(); $temp_file->write(file_get_contents(INSTALLDIR . '/tests/sample-uploads/gnu-logo.png')); + $hash = null; Event::handle('HashFile', [$temp_file->getPathname(), &$hash]); $attachment = DB::findOneBy('attachment', ['filehash' => $hash]); $attachment->{$method}(); @@ -118,6 +119,7 @@ class AttachmentTest extends GNUsocialTestCase public function testMimetype() { $file = new \SplFileInfo(INSTALLDIR . '/tests/sample-uploads/image.jpg'); + $hash = null; Event::handle('HashFile', [$file->getPathname(), &$hash]); $attachment = DB::findOneBy('attachment', ['filehash' => $hash]); diff --git a/tests/Entity/AttachmentThumbnailTest.php b/tests/Entity/AttachmentThumbnailTest.php index eb03fe7d11..e426bba519 100644 --- a/tests/Entity/AttachmentThumbnailTest.php +++ b/tests/Entity/AttachmentThumbnailTest.php @@ -38,6 +38,7 @@ class AttachmentThumbnailTest extends GNUsocialTestCase // Data fixture already loaded this file, but we need to get its hash to find it $file = new \SplFileInfo(INSTALLDIR . '/tests/sample-uploads/attachment-lifecycle-target.jpg'); + $hash = null; Event::handle('HashFile', [$file->getPathname(), &$hash]); $attachment = DB::findOneBy('attachment', ['filehash' => $hash]); @@ -73,6 +74,7 @@ class AttachmentThumbnailTest extends GNUsocialTestCase parent::bootKernel(); $file = new \SplFileInfo(INSTALLDIR . '/tests/sample-uploads/spreadsheet.ods'); + $hash = null; Event::handle('HashFile', [$file->getPathname(), &$hash]); $attachment = DB::findOneBy('attachment', ['filehash' => $hash]);