Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ts Portal Laravel Package

miraheze/ts-portal

A Laravel/PHP package from Miraheze for the TS Portal. It provides the portal’s PHP components and integration points, making it easy to add TS Portal functionality to a Laravel application via Composer.

View on GitHub
Deep Wiki
Context7

Getting Started

TSPortal is Miraheze's Laravel-based Trust & Safety portal — the app behind wiki requests, reports, and appeals. Treat it as a standard Laravel app first, and a MediaWiki-integrated app second.

Minimal bootstrap:

  1. composer install, copy .env.example to .env, php artisan key:generate.
  2. Point DB_* at MySQL/MariaDB (the schema uses standard Eloquent migrations; SQLite is fine for tests only).
  3. Register a MediaWiki OAuth consumer and fill in the Socialite credentials — you cannot exercise most of the app without a working login.
  4. php artisan migrate, then php artisan serve (or Sail/Valet).
  5. Run php artisan test before touching anything. This release bumps PHPUnit, Mockery, and the framework, so get a green baseline first.

Where to look first:

  • routes/web.php and routes/api.php — the API surface is small and is where the security-relevant writekey logic lives.
  • app/Http/Controllers — the request/report/appeal flows.
  • app/Models + database/migrations — the domain is mostly a handful of core models plus status/pivot tables.
  • config/ and .env.example — OAuth, queue, mail, and API settings.

First real use case: log in via OAuth as a test user, submit a report or wiki request through the UI, and watch it flow through the staff queue. That single path exercises auth, authorization policies, form validation, notifications, and the API — which is exactly the surface area v37 touched.

Implementation Patterns

OAuth identity as the user source of truth. Users come from MediaWiki via laravel/socialite. Don't build local password auth or duplicate profile fields; read the identity from the Socialite user object and store the stable central ID. When you add a feature, ask "does this need a local user row, or can it read from the OAuth payload?" — the latter is almost always right.

Age/eligibility gating is a policy concern, not a form field. v37 fixed an underage check (GHSA-4835-jf76-3g69). Model this as an explicit, single-source eligibility check used by every entry point (registration, appeal submission, report creation), not an inline if in one controller. If you add a new submission path, route it through the same check.

Writekey-protected API calls. The API validates a writekey; since v37 this uses hash_equals for constant-time comparison. Consume it by sending the key in the configured header from your client, and on the server side keep validation in middleware rather than per-controller. Never store or log the raw key, and never add a second comparison path — reuse the existing one.

Form Requests + Policies. Validation lives in Form Requests, authorization in Policies/Gates. This is the idiomatic Laravel shape and it's what makes the flows testable. When adding a new action on a request/report, add the policy method alongside it rather than checking roles in the controller.

Queue the slow stuff. Anything that talks to the MediaWiki API (creating wikis, posting talk-page notices, syncing statuses) belongs in a queued job. Local development should use QUEUE_CONNECTION=sync; production needs a real worker. Watch for jobs that swallow exceptions — a failed on-wiki notification should surface, not disappear.

WithoutTimestamps over public $timestamps = false. This release migrated models to the attribute form. Follow that convention for new pivot/log models; it keeps timestamp intent visible at the class declaration and is the direction the framework is going.

Testing. Feature tests with RefreshDatabase for flows, Http::fake() for MediaWiki/Guzzle calls, and Mockery for collaborators. Given the Guzzle major bump, mock at the Laravel HTTP client layer rather than the Guzzle handler layer — it survives dependency upgrades.

Gotchas and Tips

  • Guzzle 7 → 8 is a major bump. Laravel's Http facade wraps Guzzle, so most call sites are insulated — but custom handlers, middleware stacks, Client::create() calls, and anything touching PSR-7 request/response internals may break. Grep for GuzzleHttp\ before deploying and exercise the MediaWiki API integration end-to-end.
  • The two security fixes are the reason to upgrade. Timing-safe hash_equals for the writekey and the corrected underage check are both regressions that a naive refactor could reintroduce. If you have local modifications in those areas, rebase them onto the v37 code rather than re-applying your version.
  • Add regression tests for both advisories. A feature test asserting that a wrong writekey is rejected, and a unit/feature test asserting the eligibility check rejects underage submissions, will keep the fixes from silently regressing.
  • Laravel 13.x point upgrade. 13.2 → 13.36 is minor, but read the changelog for deprecations. Run composer update -W locally first rather than a bare composer update, and commit the lock file.
  • Timestamps behavior change. Removing timestamp handling from models also removes the updated_at-based sorting some admin views may rely on. If a listing looks unsorted or a latest() scope misbehaves, check whether that model was moved to the attribute.
  • Config caching bites after env edits. php artisan config:clear and queue:restart after changing OAuth or API settings — stale cached config is the most common "my change did nothing" cause here, especially with queue workers.
  • OAuth on localhost. Callback URLs must match exactly what's registered on-wiki. Use a tunnel rather than editing the consumer repeatedly.
  • Socialite 5.26 → 5.31 is minor but touches driver internals; re-verify the MediaWiki provider config keys after upgrading.
  • Debugging levers: php artisan tinker against a local DB, Log::debug around the MediaWiki client, and Http::fake()/Http::preventStrayRequests() in tests. Enable APP_DEBUG locally only — these flows handle user reports and personal data, so production error pages must stay generic.
  • Extension points: new submission types should reuse the existing request/report models with a type discriminator rather than new tables, and new staff actions belong in policies plus a queued job, not in controller closures.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource