mirror of
https://github.com/projectsend/projectsend.git
synced 2026-09-17 00:55:07 +00:00
479dc61d2d
Logo and watermark belonged in the private package for one reason: that is where they were written. Nothing about them needs a hosted platform, and an installation wanting its own mark on the pages it serves is the ordinary case rather than the exotic one. They are core's now, and every installation has them. Hiding "Powered by ProjectSend" did not come. That is what a hosted customer pays for, and its gate is not a capability key but the absence of the code: cloud-modules keeps the listener, so an installation without that package holds the column and has nothing able to read it. Flipping an edition variable buys nothing, which was true before and stays true. Core renders the switch where Capability::AttributionHide is held and has no route that can save it -- there is a test asserting exactly that, which fails the day white-labelling quietly becomes free. The migrations move with their original filenames on purpose. A Cloud tenant already ran them under those names, so Laravel skips them there and the table and its data are untouched; a fresh install or a community one runs them from here for the first time. What got better on the way rather than merely moving: The watermark listeners take core's real RenderingImage and ResolvingImageRendering instead of duck-typed `object` payloads, and the tests construct the genuine events rather than anonymous stand-ins that imitated their shape. The package had to do it that way -- it builds with no host present -- so three PHPStan ignore entries existed to describe what the type system could not see. They are gone. ModuleBoundaryTest asserted "branding is cloud-only, and the suite runs as community", which was never what it was testing. It now reads the capability off the route and subtracts it, so the invariant holds for whichever module is installed. The 43 branding strings arrived in all sixteen locales from the package's own catalogues rather than being retranslated, and the package's are pruned to the one string it still uses. A hosted plan without branding subtracts branding.customize and attribution.hide from the instance's environment. The row is never deleted by that: a downgrade is usually an expired card rather than a decision, and wiping somebody's artwork over a billing event is a loss they would find weeks later with no way to know what it used to be. Hiding reverses; deleting does not.
90 lines
2.8 KiB
PHP
90 lines
2.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Modules\Platform\Branding\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use App\Modules\Platform\Branding\Watermark\WatermarkPosition;
|
|
|
|
/**
|
|
* A single-row settings table — see the migration's comment for why no
|
|
* tenant/owner column is needed.
|
|
*
|
|
* @property int $id
|
|
* @property string|null $logo_path
|
|
* @property bool $watermark_enabled
|
|
* @property string|null $watermark_path
|
|
* @property WatermarkPosition $watermark_position
|
|
* @property int $watermark_size
|
|
* @property int $watermark_opacity
|
|
* @property bool $hide_attribution
|
|
* @property \Illuminate\Support\Carbon|null $created_at
|
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
|
*/
|
|
class BrandingSetting extends Model
|
|
{
|
|
protected $table = 'branding_settings';
|
|
|
|
protected $guarded = [];
|
|
|
|
protected $casts = [
|
|
'watermark_enabled' => 'boolean',
|
|
'watermark_position' => WatermarkPosition::class,
|
|
'watermark_size' => 'integer',
|
|
'watermark_opacity' => 'integer',
|
|
'hide_attribution' => 'boolean',
|
|
];
|
|
|
|
/**
|
|
* Mirrors the migration's column defaults, so an unsaved instance
|
|
* answers the same as a freshly created row would. That is what lets
|
|
* the settings screen render `new BrandingSetting` on an install that
|
|
* has never touched branding, instead of either creating a row on a
|
|
* GET or restating these numbers a second time in the controller.
|
|
*/
|
|
protected $attributes = [
|
|
'watermark_enabled' => false,
|
|
'watermark_position' => 'bottom-right',
|
|
'watermark_size' => 30,
|
|
'watermark_opacity' => 60,
|
|
'hide_attribution' => false,
|
|
];
|
|
|
|
public static function current(): self
|
|
{
|
|
return static::query()->firstOrCreate([]);
|
|
}
|
|
|
|
public function logoUrl(): ?string
|
|
{
|
|
return $this->logo_path === null ? null : Storage::disk('public')->url($this->logo_path);
|
|
}
|
|
|
|
public function watermarkUrl(): ?string
|
|
{
|
|
return $this->watermark_path === null ? null : Storage::disk('public')->url($this->watermark_path);
|
|
}
|
|
|
|
/**
|
|
* The artwork to stamp on a thumbnail being rendered right now, or
|
|
* null when this installation is not watermarking.
|
|
*
|
|
* Phrased as "which image, if any" rather than as a boolean because
|
|
* the toggle alone is not enough to act on: removing the image
|
|
* leaves the toggle standing, and a row restored from a backup can
|
|
* carry an `enabled` that its file no longer backs. Answering both
|
|
* halves at once means a caller cannot check one and use the other.
|
|
*/
|
|
public function activeWatermarkPath(): ?string
|
|
{
|
|
return $this->watermark_enabled ? $this->watermark_path : null;
|
|
}
|
|
|
|
public function watermarksThumbnails(): bool
|
|
{
|
|
return $this->activeWatermarkPath() !== null;
|
|
}
|
|
}
|