4
0
mirror of https://github.com/AzuraCast/AzuraCast.git synced 2024-06-13 20:56:36 +00:00

Move entity OpenAPI annotations to attributes.

This commit is contained in:
Buster "Silver Eagle" Neece 2021-12-19 12:50:37 -06:00
parent c943fc91ec
commit a2eb5d0471
No known key found for this signature in database
GPG Key ID: 9FC8B9E008872109
15 changed files with 1148 additions and 1062 deletions

View File

@ -10,8 +10,8 @@ use OpenApi\Annotations as OA;
use Stringable;
use Symfony\Component\Validator\Constraints as Assert;
/** @OA\Schema(type="object") */
#[
OA\Schema(type: 'object'),
ORM\Entity,
ORM\Table(name: 'custom_field'),
Attributes\Auditable
@ -21,17 +21,27 @@ class CustomField implements Stringable, IdentifiableEntityInterface
use Traits\HasAutoIncrementId;
use Traits\TruncateStrings;
/** @OA\Property() */
#[ORM\Column(length: 255)]
#[Assert\NotBlank]
#[
OA\Property,
ORM\Column(length: 255),
Assert\NotBlank
]
protected string $name;
/** @OA\Property(description="The programmatic name for the field. Can be auto-generated from the full name.") */
#[ORM\Column(length: 100, nullable: false)]
#[
OA\Property(
description: "The programmatic name for the field. Can be auto-generated from the full name."
),
ORM\Column(length: 100, nullable: false)
]
protected string $short_name;
/** @OA\Property(description="An ID3v2 field to automatically assign to this value, if it exists in the media file.") */
#[ORM\Column(length: 100, nullable: true)]
#[
OA\Property(
description: "An ID3v2 field to automatically assign to this value, if it exists in the media file."
),
ORM\Column(length: 100, nullable: true)
]
protected ?string $auto_assign = null;
public function getName(): string

View File

@ -10,8 +10,8 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use OpenApi\Annotations as OA;
/** @OA\Schema(type="object") */
#[
OA\Schema(type: "object"),
ORM\Entity,
ORM\Table(name: 'relays'),
ORM\HasLifecycleCallbacks
@ -21,27 +21,37 @@ class Relay implements IdentifiableEntityInterface
use Traits\HasAutoIncrementId;
use Traits\TruncateStrings;
/** @OA\Property(example="https://custom-url.example.com") */
#[ORM\Column(length: 255)]
#[
OA\Property(example: "https://custom-url.example.com"),
ORM\Column(length: 255)
]
protected string $base_url;
/** @OA\Property(example="Relay") */
#[ORM\Column(length: 100, nullable: true)]
#[
OA\Property(example: "Relay"),
ORM\Column(length: 100, nullable: true)
]
protected ?string $name = 'Relay';
/** @OA\Property(example=true) */
#[ORM\Column]
#[
OA\Property(example: true),
ORM\Column
]
protected bool $is_visible_on_public_pages = true;
#[ORM\Column(type: 'array', nullable: true)]
protected mixed $nowplaying;
/** @OA\Property(example=1609480800) */
#[ORM\Column]
#[
OA\Property(example: 1609480800),
ORM\Column
]
protected int $created_at;
/** @OA\Property(example=1609480800) */
#[ORM\Column]
#[
OA\Property(example: 1609480800),
ORM\Column
]
protected int $updated_at;
#[ORM\OneToMany(mappedBy: 'relay', targetEntity: StationRemote::class)]

View File

@ -13,8 +13,8 @@ use OpenApi\Annotations as OA;
use Stringable;
use Symfony\Component\Validator\Constraints as Assert;
/** @OA\Schema(type="object") */
#[
OA\Schema(type: "object"),
ORM\Entity,
ORM\Table(name: 'role'),
Attributes\Auditable
@ -24,16 +24,20 @@ class Role implements JsonSerializable, Stringable, IdentifiableEntityInterface
use Traits\HasAutoIncrementId;
use Traits\TruncateStrings;
/** @OA\Property(example="Super Administrator") */
#[ORM\Column(length: 100)]
#[Assert\NotBlank]
#[
OA\Property(example: "Super Administrator"),
ORM\Column(length: 100),
Assert\NotBlank
]
protected string $name;
#[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'roles')]
protected Collection $users;
/** @OA\Property(type="array", @OA\Items) */
#[ORM\OneToMany(mappedBy: 'role', targetEntity: RolePermission::class)]
#[
OA\Property(type: "array", items: new OA\Items()),
ORM\OneToMany(mappedBy: 'role', targetEntity: RolePermission::class)
]
protected Collection $permissions;
public function __construct()

File diff suppressed because it is too large Load Diff

View File

@ -13,33 +13,44 @@ use Symfony\Component\Validator\Constraints as Assert;
use const PASSWORD_ARGON2ID;
/** @OA\Schema(type="object") */
#[ORM\Entity, ORM\Table(name: 'sftp_user')]
#[ORM\UniqueConstraint(name: 'username_idx', columns: ['username'])]
#[UniqueEntity(fields: ['username'])]
#[Auditable]
#[
OA\Schema(type: "object"),
ORM\Entity,
ORM\Table(name: 'sftp_user'),
ORM\UniqueConstraint(name: 'username_idx', columns: ['username']),
UniqueEntity(fields: ['username']),
Auditable
]
class SftpUser implements IdentifiableEntityInterface
{
use Traits\HasAutoIncrementId;
#[ORM\ManyToOne(inversedBy: 'sftp_users')]
#[ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
#[
ORM\ManyToOne(inversedBy: 'sftp_users'),
ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')
]
protected Station $station;
/** @OA\Property() */
#[ORM\Column(length: 32)]
#[Assert\Length(min: 1, max: 32)]
#[Assert\NotBlank]
#[Assert\Regex(pattern: '/^[a-zA-Z0-9-_.~]+$/')]
#[
OA\Property,
ORM\Column(length: 32),
Assert\Length(min: 1, max: 32),
Assert\NotBlank,
Assert\Regex(pattern: '/^[a-zA-Z0-9-_.~]+$/')
]
protected string $username;
/** @OA\Property() */
#[ORM\Column(length: 255)]
#[Assert\NotBlank]
#[
OA\Property,
ORM\Column(length: 255),
Assert\NotBlank
]
protected string $password;
/** @OA\Property() */
#[ORM\Column(name: 'public_keys', type: 'text', nullable: true)]
#[
OA\Property,
ORM\Column(name: 'public_keys', type: 'text', nullable: true)
]
protected ?string $publicKeys = null;
public function __construct(Station $station)

View File

@ -8,9 +8,12 @@ use App\Entity\Interfaces\IdentifiableEntityInterface;
use App\Entity\Interfaces\SongInterface;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity, ORM\Table(name: 'song_history')]
#[ORM\Index(columns: ['timestamp_start'], name: 'idx_timestamp_start')]
#[ORM\Index(columns: ['timestamp_end'], name: 'idx_timestamp_end')]
#[
ORM\Entity,
ORM\Table(name: 'song_history'),
ORM\Index(columns: ['timestamp_start'], name: 'idx_timestamp_start'),
ORM\Index(columns: ['timestamp_end'], name: 'idx_timestamp_end')
]
class SongHistory implements SongInterface, IdentifiableEntityInterface
{
use Traits\HasAutoIncrementId;

View File

@ -26,8 +26,8 @@ use Stringable;
use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Constraints as Assert;
/** @OA\Schema(type="object", schema="Station") */
#[
OA\Schema(type: "object", schema: "Station"),
ORM\Entity,
ORM\Table(name: 'station'),
ORM\Index(columns: ['short_name'], name: 'idx_short_name'),
@ -44,275 +44,308 @@ class Station implements Stringable, IdentifiableEntityInterface
// Taxonomical groups for permission-based serialization.
public const GROUP_AUTOMATION = 'automation';
/**
* @OA\Property(
* description="The full display name of the station.",
* example="AzuraTest Radio"
* )
*/
#[ORM\Column(length: 100, nullable: false)]
#[Assert\NotBlank]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(description: "The full display name of the station.", example: "AzuraTest Radio"),
ORM\Column(length: 100, nullable: false),
Assert\NotBlank,
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected string $name = '';
/**
* @OA\Property(
* description="The URL-friendly name for the station, typically auto-generated from the full station name.",
* example="azuratest_radio"
* )
*/
#[ORM\Column(length: 100, nullable: false)]
#[Assert\NotBlank]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "The URL-friendly name for the station, typically auto-generated from the full station name.",
example: "azuratest_radio"
),
ORM\Column(length: 100, nullable: false),
Assert\NotBlank,
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected string $short_name = '';
/**
* @OA\Property(
* description="If set to 'false', prevents the station from broadcasting but leaves it in the database.",
* example=true
* )
*/
#[ORM\Column]
#[Serializer\Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "If set to 'false', prevents the station from broadcasting but leaves it in the database.",
example: true
),
ORM\Column,
Serializer\Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])
]
protected bool $is_enabled = true;
/**
* @OA\Property(
* description="The frontend adapter (icecast,shoutcast,remote,etc)",
* example="icecast"
* )
*/
#[ORM\Column(length: 100, nullable: true)]
#[Assert\Choice(choices: [Adapters::FRONTEND_ICECAST, Adapters::FRONTEND_REMOTE, Adapters::FRONTEND_SHOUTCAST])]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "The frontend adapter (icecast,shoutcast,remote,etc)",
example: "icecast"
),
ORM\Column(length: 100, nullable: true),
Assert\Choice(choices: [Adapters::FRONTEND_ICECAST, Adapters::FRONTEND_REMOTE, Adapters::FRONTEND_SHOUTCAST]),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $frontend_type = Adapters::FRONTEND_ICECAST;
/**
* @OA\Property(
* type="array",
* description="An array containing station-specific frontend configuration",
* @OA\Items()
* )
*/
#[ORM\Column(type: 'json', nullable: true)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
type: "array",
description: "An array containing station-specific frontend configuration",
items: new OA\Items()
),
ORM\Column(type: 'json', nullable: true),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?array $frontend_config = null;
/**
* @OA\Property(
* description="The backend adapter (liquidsoap,etc)",
* example="liquidsoap"
* )
*/
#[ORM\Column(length: 100, nullable: true)]
#[Assert\Choice(choices: [Adapters::BACKEND_LIQUIDSOAP, Adapters::BACKEND_NONE])]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "The backend adapter (liquidsoap,etc)",
example: "liquidsoap"
),
ORM\Column(length: 100, nullable: true),
Assert\Choice(choices: [Adapters::BACKEND_LIQUIDSOAP, Adapters::BACKEND_NONE]),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $backend_type = Adapters::BACKEND_LIQUIDSOAP;
/**
* @OA\Property(
* type="array",
* description="An array containing station-specific backend configuration",
* @OA\Items()
* )
*/
#[ORM\Column(type: 'json', nullable: true)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
type: "array",
description: "An array containing station-specific backend configuration",
items: new OA\Items()
),
ORM\Column(type: 'json', nullable: true),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?array $backend_config = null;
#[ORM\Column(length: 150, nullable: true)]
#[Attributes\AuditIgnore]
#[
ORM\Column(length: 150, nullable: true),
Attributes\AuditIgnore
]
protected ?string $adapter_api_key = null;
/** @OA\Property(example="A sample radio station.") */
#[ORM\Column(type: 'text', nullable: true)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: "A sample radio station."),
ORM\Column(type: 'text', nullable: true),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $description = null;
/** @OA\Property(example="https://demo.azuracast.com/") */
#[ORM\Column(length: 255, nullable: true)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: "https://demo.azuracast.com/"),
ORM\Column(length: 255, nullable: true),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $url = null;
/** @OA\Property(example="Various") */
#[ORM\Column(length: 150, nullable: true)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: "Various"),
ORM\Column(length: 150, nullable: true),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $genre = null;
/** @OA\Property(example="/var/azuracast/stations/azuratest_radio") */
#[ORM\Column(length: 255, nullable: true)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: "/var/azuracast/stations/azuratest_radio"),
ORM\Column(length: 255, nullable: true),
Serializer\Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $radio_base_dir = null;
#[ORM\Column(type: 'array', nullable: true)]
#[Attributes\AuditIgnore]
#[
ORM\Column(type: 'array', nullable: true),
Attributes\AuditIgnore
]
protected mixed $nowplaying;
#[ORM\Column(nullable: true)]
#[Attributes\AuditIgnore]
#[
ORM\Column(nullable: true),
Attributes\AuditIgnore
]
protected ?int $nowplaying_timestamp = null;
/** @OA\Property(type="array", @OA\Items()) */
#[ORM\Column(type: 'json', nullable: true)]
#[Serializer\Groups([self::GROUP_AUTOMATION, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(type: "array", items: new OA\Items()),
ORM\Column(type: 'json', nullable: true),
Serializer\Groups([self::GROUP_AUTOMATION, EntityGroupsInterface::GROUP_ALL])
]
protected ?array $automation_settings = null;
#[ORM\Column(nullable: true)]
#[Attributes\AuditIgnore]
#[Serializer\Groups([self::GROUP_AUTOMATION, EntityGroupsInterface::GROUP_ALL])]
#[
ORM\Column(nullable: true),
Attributes\AuditIgnore,
Serializer\Groups([self::GROUP_AUTOMATION, EntityGroupsInterface::GROUP_ALL])
]
protected ?int $automation_timestamp = 0;
/**
* @OA\Property(
* description="Whether listeners can request songs to play on this station.",
* example=true
* )
*/
#[ORM\Column]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "Whether listeners can request songs to play on this station.",
example: true
),
ORM\Column,
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected bool $enable_requests = false;
/** @OA\Property(example=5) */
#[ORM\Column(nullable: true)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: 5),
ORM\Column(nullable: true),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?int $request_delay = 5;
/** @OA\Property(example=15) */
#[ORM\Column(nullable: true)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: 15),
ORM\Column(nullable: true),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?int $request_threshold = 15;
/** @OA\Property(example=0) */
#[ORM\Column(nullable: true, options: ['default' => 0])]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: 0),
ORM\Column(nullable: true, options: ['default' => 0]),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?int $disconnect_deactivate_streamer = 0;
/**
* @OA\Property(
* description="Whether streamers are allowed to broadcast to this station at all.",
* example=false
* )
*/
#[ORM\Column]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "Whether streamers are allowed to broadcast to this station at all.",
example: false
),
ORM\Column,
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected bool $enable_streamers = false;
/**
* @OA\Property(
* description="Whether a streamer is currently active on the station.",
* example=false
* )
*/
#[ORM\Column]
#[Attributes\AuditIgnore]
#[
OA\Property(
description: "Whether a streamer is currently active on the station.",
example: false
),
ORM\Column,
Attributes\AuditIgnore
]
protected bool $is_streamer_live = false;
/**
* @OA\Property(
* description="Whether this station is visible as a public page and in a now-playing API response.",
* example=true
* )
*/
#[ORM\Column]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "Whether this station is visible as a public page and in a now-playing API response.",
example: true
),
ORM\Column,
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected bool $enable_public_page = true;
/**
* @OA\Property(
* description="Whether this station has a public 'on-demand' streaming and download page.",
* example=true
* )
*/
#[ORM\Column]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "Whether this station has a public 'on-demand' streaming and download page.",
example: true
),
ORM\Column,
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected bool $enable_on_demand = false;
/**
* @OA\Property(
* description="Whether the 'on-demand' page offers download capability.",
* example=true
* )
*/
#[ORM\Column]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "Whether the 'on-demand' page offers download capability.",
example: true
),
ORM\Column,
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected bool $enable_on_demand_download = true;
#[ORM\Column]
#[Attributes\AuditIgnore]
#[
ORM\Column,
Attributes\AuditIgnore
]
protected bool $needs_restart = false;
#[ORM\Column]
#[Attributes\AuditIgnore]
#[
ORM\Column,
Attributes\AuditIgnore
]
protected bool $has_started = false;
/**
* @OA\Property(
* description="The number of 'last played' history items to show for a station in API responses.",
* example=5
* )
*/
#[ORM\Column(type: 'smallint')]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "The number of 'last played' history items to show for a station in API responses.",
example: 5
),
ORM\Column(type: 'smallint'),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected int $api_history_items = 5;
/**
* @OA\Property(
* description="The time zone that station operations should take place in.",
* example="UTC"
* )
*/
#[ORM\Column(length: 100, nullable: true)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "The time zone that station operations should take place in.",
example: "UTC"
),
ORM\Column(length: 100, nullable: true),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $timezone = 'UTC';
/**
* @OA\Property(
* description="The station-specific default album artwork URL.",
* example="https://example.com/image.jpg"
* )
*/
#[ORM\Column(length: 255, nullable: true)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(
description: "The station-specific default album artwork URL.",
example: "https://example.com/image.jpg"
),
ORM\Column(length: 255, nullable: true),
Serializer\Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $default_album_art_url = null;
#[ORM\OneToMany(mappedBy: 'station', targetEntity: SongHistory::class)]
#[ORM\OrderBy(['timestamp_start' => 'desc'])]
#[
ORM\OneToMany(mappedBy: 'station', targetEntity: SongHistory::class),
ORM\OrderBy(['timestamp_start' => 'desc'])
]
protected Collection $history;
#[ORM\ManyToOne]
#[ORM\JoinColumn(
name: 'media_storage_location_id',
referencedColumnName: 'id',
nullable: true,
onDelete: 'SET NULL'
)]
#[DeepNormalize(true)]
#[Serializer\MaxDepth(1)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[
ORM\ManyToOne,
ORM\JoinColumn(
name: 'media_storage_location_id',
referencedColumnName: 'id',
nullable: true,
onDelete: 'SET NULL'
),
DeepNormalize(true),
Serializer\MaxDepth(1),
Serializer\Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])
]
protected ?StorageLocation $media_storage_location = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(
name: 'recordings_storage_location_id',
referencedColumnName: 'id',
nullable: true,
onDelete: 'SET NULL'
)]
#[DeepNormalize(true)]
#[Serializer\MaxDepth(1)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[
ORM\ManyToOne,
ORM\JoinColumn(
name: 'recordings_storage_location_id',
referencedColumnName: 'id',
nullable: true,
onDelete: 'SET NULL'
),
DeepNormalize(true),
Serializer\MaxDepth(1),
Serializer\Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])
]
protected ?StorageLocation $recordings_storage_location = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(
name: 'podcasts_storage_location_id',
referencedColumnName: 'id',
nullable: true,
onDelete: 'SET NULL'
)]
#[DeepNormalize(true)]
#[Serializer\MaxDepth(1)]
#[Serializer\Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[
ORM\ManyToOne,
ORM\JoinColumn(
name: 'podcasts_storage_location_id',
referencedColumnName: 'id',
nullable: true,
onDelete: 'SET NULL'
),
DeepNormalize(true),
Serializer\MaxDepth(1),
Serializer\Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])
]
protected ?StorageLocation $podcasts_storage_location = null;
#[ORM\OneToMany(mappedBy: 'station', targetEntity: StationStreamer::class)]
@ -321,15 +354,19 @@ class Station implements Stringable, IdentifiableEntityInterface
#[ORM\Column(nullable: true)]
protected ?int $current_streamer_id = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(name: 'current_streamer_id', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')]
#[
ORM\ManyToOne,
ORM\JoinColumn(name: 'current_streamer_id', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')
]
protected ?StationStreamer $current_streamer = null;
#[ORM\OneToMany(mappedBy: 'station', targetEntity: RolePermission::class)]
protected Collection $permissions;
#[ORM\OneToMany(mappedBy: 'station', targetEntity: StationPlaylist::class)]
#[ORM\OrderBy(['type' => 'ASC', 'weight' => 'DESC'])]
#[
ORM\OneToMany(mappedBy: 'station', targetEntity: StationPlaylist::class),
ORM\OrderBy(['type' => 'ASC', 'weight' => 'DESC'])
]
protected Collection $playlists;
#[ORM\OneToMany(mappedBy: 'station', targetEntity: StationMount::class)]

View File

@ -20,8 +20,8 @@ use OpenApi\Annotations as OA;
use RuntimeException;
use Symfony\Component\Serializer\Annotation as Serializer;
/** @OA\Schema(type="object") */
#[
OA\Schema(type: "object"),
ORM\Entity,
ORM\Table(name: 'station_media'),
ORM\Index(columns: ['title', 'artist', 'album'], name: 'search_idx'),
@ -38,161 +38,165 @@ class StationMedia implements SongInterface, ProcessableMediaInterface, PathAwar
public const DIR_ALBUM_ART = '.albumart';
public const DIR_WAVEFORMS = '.waveforms';
/**
* @OA\Property(
* description="A unique identifier associated with this record.",
* example="69b536afc7ebbf16457b8645"
* )
*/
#[ORM\Column(length: 25, nullable: true)]
#[
OA\Property(
description: "A unique identifier associated with this record.",
example: "69b536afc7ebbf16457b8645"
),
ORM\Column(length: 25, nullable: true)
]
protected ?string $unique_id = null;
#[ORM\Column(nullable: false)]
protected int $storage_location_id;
#[ORM\ManyToOne(inversedBy: 'media')]
#[ORM\JoinColumn(name: 'storage_location_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
#[
ORM\ManyToOne(inversedBy: 'media'),
ORM\JoinColumn(name: 'storage_location_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')
]
protected StorageLocation $storage_location;
/**
* @OA\Property(
* description="The name of the media file's album.",
* example="Test Album"
* )
*/
#[ORM\Column(length: 200, nullable: true)]
#[
OA\Property(
description: "The name of the media file's album.",
example: "Test Album"
),
ORM\Column(length: 200, nullable: true)
]
protected ?string $album = null;
/**
* @OA\Property(
* description="The genre of the media file.",
* example="Rock"
* )
*/
#[ORM\Column(length: 30, nullable: true)]
#[
OA\Property(
description: "The genre of the media file.",
example: "Rock"
),
ORM\Column(length: 30, nullable: true)
]
protected ?string $genre = null;
/**
* @OA\Property(
* description="Full lyrics of the track, if available.",
* example="...Never gonna give you up..."
* )
*/
#[ORM\Column(type: 'text', nullable: true)]
#[
OA\Property(
description: "Full lyrics of the track, if available.",
example: "...Never gonna give you up..."
),
ORM\Column(type: 'text', nullable: true)
]
protected ?string $lyrics = null;
/**
* @OA\Property(
* description="The track ISRC (International Standard Recording Code), used for licensing purposes.",
* example="GBARL0600786"
* )
*/
#[ORM\Column(length: 15, nullable: true)]
#[
OA\Property(
description: "The track ISRC (International Standard Recording Code), used for licensing purposes.",
example: "GBARL0600786"
),
ORM\Column(length: 15, nullable: true)
]
protected ?string $isrc = null;
/**
* @OA\Property(
* description="The song duration in seconds.",
* example=240.00
* )
*/
#[ORM\Column(type: 'decimal', precision: 7, scale: 2, nullable: true)]
#[
OA\Property(
description: "The song duration in seconds.",
example: 240.00
),
ORM\Column(type: 'decimal', precision: 7, scale: 2, nullable: true)
]
protected ?float $length = 0.00;
/**
* @OA\Property(
* description="The formatted song duration (in mm:ss format)",
* example="4:00"
* )
*/
#[ORM\Column(length: 10, nullable: true)]
#[
OA\Property(
description: "The formatted song duration (in mm:ss format)",
example: "4:00"
),
ORM\Column(length: 10, nullable: true)
]
protected ?string $length_text = '0:00';
/**
* @OA\Property(
* description="The relative path of the media file.",
* example="test.mp3"
* )
*/
#[ORM\Column(length: 500)]
#[
OA\Property(
description: "The relative path of the media file.",
example: "test.mp3"
),
ORM\Column(length: 500)
]
protected string $path;
/**
* @OA\Property(
* description="The UNIX timestamp when the database was last modified.",
* example=1609480800
* )
*/
#[ORM\Column(nullable: true)]
#[
OA\Property(
description: "The UNIX timestamp when the database was last modified.",
example: 1609480800
),
ORM\Column(nullable: true)
]
protected ?int $mtime = 0;
/**
* @OA\Property(
* description="The amount of amplification (in dB) to be applied to the radio source (liq_amplify)",
* example=-14.00
* )
*/
#[ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)]
#[
OA\Property(
description: "The amount of amplification (in dB) to be applied to the radio source (liq_amplify)",
example: -14.00
),
ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)
]
protected ?float $amplify = null;
/**
* @OA\Property(
* description="The length of time (in seconds) before the next song starts in the fade (liq_start_next)",
* example=2.00
* )
*/
#[ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)]
#[
OA\Property(
description: "The length of time (in seconds) before the next song starts in the fade (liq_start_next)",
example: 2.00
),
ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)
]
protected ?float $fade_overlap = null;
/**
* @OA\Property(
* description="The length of time (in seconds) to fade in the next track (liq_fade_in)",
* example=3.00
* )
*/
#[ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)]
#[
OA\Property(
description: "The length of time (in seconds) to fade in the next track (liq_fade_in)",
example: 3.00
),
ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)
]
protected ?float $fade_in = null;
/**
* @OA\Property(
* description="The length of time (in seconds) to fade out the previous track (liq_fade_out)",
* example=3.00
* )
*/
#[ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)]
#[
OA\Property(
description: "The length of time (in seconds) to fade out the previous track (liq_fade_out)",
example: 3.00
),
ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)
]
protected ?float $fade_out = null;
/**
* @OA\Property(
* description="The length of time (in seconds) from the start of the track to start playing (liq_cue_in)",
* example=30.00
* )
*/
#[ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)]
#[
OA\Property(
description: "The length of time (in seconds) from the start of the track to start playing (liq_cue_in)",
example: 30.00
),
ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)
]
protected ?float $cue_in = null;
/**
* @OA\Property(
* description="The length of time (in seconds) from the CUE-IN of the track to stop playing (liq_cue_out)",
* example=30.00
* )
*/
#[ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)]
#[
OA\Property(
description: "The length of time (in seconds) from the CUE-IN of the track to stop playing (liq_cue_out)",
example: 30.00
),
ORM\Column(type: 'decimal', precision: 6, scale: 1, nullable: true)
]
protected ?float $cue_out = null;
/**
* @OA\Property(
* description="The latest time (UNIX timestamp) when album art was updated.",
* example=1609480800
* )
*/
#[ORM\Column]
#[
OA\Property(
description: "The latest time (UNIX timestamp) when album art was updated.",
example: 1609480800
),
ORM\Column
]
protected int $art_updated_at = 0;
/** @OA\Property(type="array", @OA\Items()) */
#[ORM\OneToMany(mappedBy: 'media', targetEntity: StationPlaylistMedia::class)]
#[DeepNormalize(true)]
#[Serializer\MaxDepth(1)]
#[
OA\Property(type: "array", items: new OA\Items()),
ORM\OneToMany(mappedBy: 'media', targetEntity: StationPlaylistMedia::class),
DeepNormalize(true),
Serializer\MaxDepth(1)
]
protected Collection $playlists;
#[ORM\OneToMany(mappedBy: 'media', targetEntity: StationMediaCustomField::class)]

View File

@ -13,8 +13,8 @@ use Psr\Http\Message\UriInterface;
use Stringable;
use Symfony\Component\Validator\Constraints as Assert;
/** @OA\Schema(type="object") */
#[
OA\Schema(type: "object"),
ORM\Entity,
ORM\Table(name: 'station_mounts'),
Attributes\Auditable
@ -32,88 +32,118 @@ class StationMount implements
#[ORM\Column(nullable: false)]
protected int $station_id;
#[ORM\ManyToOne(inversedBy: 'mounts')]
#[ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
#[
ORM\ManyToOne(inversedBy: 'mounts'),
ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')
]
protected Station $station;
/** @OA\Property(example="/radio.mp3") */
#[ORM\Column(length: 100)]
#[Assert\NotBlank]
#[
OA\Property(example: "/radio.mp3"),
ORM\Column(length: 100),
Assert\NotBlank
]
protected string $name = '';
/** @OA\Property(example="128kbps MP3") */
#[ORM\Column(length: 255, nullable: true)]
#[
OA\Property(example: "128kbps MP3"),
ORM\Column(length: 255, nullable: true)
]
protected ?string $display_name = null;
/** @OA\Property(example=true) */
#[ORM\Column]
#[
OA\Property(example: true),
ORM\Column
]
protected bool $is_visible_on_public_pages = true;
/** @OA\Property(example=false) */
#[ORM\Column]
#[
OA\Property(example: false),
ORM\Column
]
protected bool $is_default = false;
/** @OA\Property(example=false) */
#[ORM\Column]
#[
OA\Property(example: false),
ORM\Column
]
protected bool $is_public = false;
/** @OA\Property(example="/error.mp3") */
#[ORM\Column(length: 100, nullable: true)]
#[
OA\Property(example: "/error.mp3"),
ORM\Column(length: 100, nullable: true)
]
protected ?string $fallback_mount = null;
/** @OA\Property(example="https://radio.example.com:8000/radio.mp3") */
#[ORM\Column(length: 255, nullable: true)]
#[
OA\Property(example: "https://radio.example.com:8000/radio.mp3"),
ORM\Column(length: 255, nullable: true)
]
protected ?string $relay_url = null;
/** @OA\Property(example="") */
#[ORM\Column(length: 255, nullable: true)]
#[
OA\Property(example: ""),
ORM\Column(length: 255, nullable: true)
]
protected ?string $authhash = null;
/** @OA\Property(example=43200) */
#[ORM\Column(type: 'integer', nullable: false)]
#[
OA\Property(example: 43200),
ORM\Column(type: 'integer', nullable: false)
]
protected int $max_listener_duration = 0;
/** @OA\Property(example=true) */
#[ORM\Column]
#[
OA\Property(example: true),
ORM\Column
]
protected bool $enable_autodj = true;
/** @OA\Property(example="mp3") */
#[ORM\Column(length: 10, nullable: true)]
#[
OA\Property(example: "mp3"),
ORM\Column(length: 10, nullable: true)
]
protected ?string $autodj_format = 'mp3';
/** @OA\Property(example=128) */
#[ORM\Column(type: 'smallint', nullable: true)]
#[
OA\Property(example: 128),
ORM\Column(type: 'smallint', nullable: true)
]
protected ?int $autodj_bitrate = 128;
/** @OA\Property(example="https://custom-listen-url.example.com/stream.mp3") */
#[ORM\Column(length: 255, nullable: true)]
#[
OA\Property(example: "https://custom-listen-url.example.com/stream.mp3"),
ORM\Column(length: 255, nullable: true)
]
protected ?string $custom_listen_url = null;
#[ORM\Column(length: 255, nullable: true)]
protected ?string $intro_path = null;
/** @OA\Property(type="array", @OA\Items()) */
#[ORM\Column(type: 'text', nullable: true)]
#[
OA\Property(type: "array", items: new OA\Items()),
ORM\Column(type: 'text', nullable: true)
]
protected ?string $frontend_config = null;
/**
* @OA\Property(
* description="The most recent number of unique listeners.",
* example=10
* )
*/
#[ORM\Column]
#[Attributes\AuditIgnore]
#[
OA\Property(
description: "The most recent number of unique listeners.",
example: 10
),
ORM\Column,
Attributes\AuditIgnore
]
protected int $listeners_unique = 0;
/**
* @OA\Property(
* description="The most recent number of total (non-unique) listeners.",
* example=12
* )
*/
#[ORM\Column]
#[Attributes\AuditIgnore]
#[
OA\Property(
description: "The most recent number of total (non-unique) listeners.",
example: 12
),
ORM\Column,
Attributes\AuditIgnore
]
protected int $listeners_total = 0;
public function __construct(Station $station)

View File

@ -13,8 +13,8 @@ use Stringable;
use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Constraints as Assert;
/** @OA\Schema(type="object") */
#[
OA\Schema(type: "object"),
ORM\Entity,
ORM\Table(name: 'station_playlists'),
ORM\HasLifecycleCallbacks,
@ -55,132 +55,169 @@ class StationPlaylist implements
#[ORM\Column(nullable: false)]
protected int $station_id;
#[ORM\ManyToOne(inversedBy: 'playlists')]
#[ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
#[
ORM\ManyToOne(inversedBy: 'playlists'),
ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')
]
protected Station $station;
/** @OA\Property(example="Test Playlist") */
#[ORM\Column(length: 200)]
#[Assert\NotBlank]
#[
OA\Property(example: "Test Playlist"),
ORM\Column(length: 200),
Assert\NotBlank
]
protected string $name;
/** @OA\Property(example="default") */
#[ORM\Column(length: 50)]
#[Assert\Choice(choices: [
self::TYPE_DEFAULT,
self::TYPE_ONCE_PER_X_SONGS,
self::TYPE_ONCE_PER_X_MINUTES,
self::TYPE_ONCE_PER_HOUR,
self::TYPE_ADVANCED,
])]
#[
OA\Property(example: "default"),
ORM\Column(length: 50),
Assert\Choice(choices: [
self::TYPE_DEFAULT,
self::TYPE_ONCE_PER_X_SONGS,
self::TYPE_ONCE_PER_X_MINUTES,
self::TYPE_ONCE_PER_HOUR,
self::TYPE_ADVANCED,
])
]
protected string $type = self::TYPE_DEFAULT;
/** @OA\Property(example="songs") */
#[ORM\Column(length: 50)]
#[Assert\Choice(choices: [self::SOURCE_SONGS, self::SOURCE_REMOTE_URL])]
#[
OA\Property(example: "songs"),
ORM\Column(length: 50),
Assert\Choice(choices: [self::SOURCE_SONGS, self::SOURCE_REMOTE_URL])
]
protected string $source = self::SOURCE_SONGS;
/** @OA\Property(example="shuffle") */
#[ORM\Column(name: 'playback_order', length: 50)]
#[Assert\Choice(choices: [self::ORDER_RANDOM, self::ORDER_SHUFFLE, self::ORDER_SEQUENTIAL])]
#[
OA\Property(example: "shuffle"),
ORM\Column(name: 'playback_order', length: 50),
Assert\Choice(choices: [self::ORDER_RANDOM, self::ORDER_SHUFFLE, self::ORDER_SEQUENTIAL])
]
protected string $order = self::ORDER_SHUFFLE;
/** @OA\Property(example="https://remote-url.example.com/stream.mp3") */
#[ORM\Column(length: 255, nullable: true)]
#[
OA\Property(example: "https://remote-url.example.com/stream.mp3"),
ORM\Column(length: 255, nullable: true)
]
protected ?string $remote_url = null;
/** @OA\Property(example="stream") */
#[ORM\Column(length: 25, nullable: true)]
#[Assert\Choice(choices: [self::REMOTE_TYPE_STREAM, self::REMOTE_TYPE_PLAYLIST])]
#[
OA\Property(example: "stream"),
ORM\Column(length: 25, nullable: true),
Assert\Choice(choices: [self::REMOTE_TYPE_STREAM, self::REMOTE_TYPE_PLAYLIST])
]
protected ?string $remote_type = self::REMOTE_TYPE_STREAM;
/**
* @OA\Property(
* description="The total time (in seconds) that Liquidsoap should buffer remote URL streams.",
* example=0
* )
*/
#[ORM\Column(name: 'remote_timeout', type: 'smallint')]
#[
OA\Property(
description: "The total time (in seconds) that Liquidsoap should buffer remote URL streams.",
example: 0
),
ORM\Column(name: 'remote_timeout', type: 'smallint')
]
protected int $remote_buffer = 0;
/** @OA\Property(example=true) */
#[ORM\Column]
#[
OA\Property(example: true),
ORM\Column
]
protected bool $is_enabled = true;
/**
* @OA\Property(
* description="If yes, do not send jingle metadata to AutoDJ or trigger web hooks.",
* example=false
* )
*/
#[ORM\Column]
#[
OA\Property(
description: "If yes, do not send jingle metadata to AutoDJ or trigger web hooks.",
example: false
),
ORM\Column
]
protected bool $is_jingle = false;
/** @OA\Property(example=5) */
#[ORM\Column(type: 'smallint')]
#[
OA\Property(example: 5),
ORM\Column(type: 'smallint')
]
protected int $play_per_songs = 0;
/** @OA\Property(example=120) */
#[ORM\Column(type: 'smallint')]
#[
OA\Property(example: 120),
ORM\Column(type: 'smallint')
]
protected int $play_per_minutes = 0;
/** @OA\Property(example=15) */
#[ORM\Column(type: 'smallint')]
#[
OA\Property(example: 15),
ORM\Column(type: 'smallint')
]
protected int $play_per_hour_minute = 0;
/** @OA\Property(example=3) */
#[ORM\Column(type: 'smallint')]
#[
OA\Property(example: 3),
ORM\Column(type: 'smallint')
]
protected int $weight = self::DEFAULT_WEIGHT;
/** @OA\Property(example=true) */
#[ORM\Column]
#[
OA\Property(example: true),
ORM\Column
]
protected bool $include_in_requests = true;
/**
* @OA\Property(
* description="Whether this playlist's media is included in 'on demand' download/streaming if enabled.",
* example=true
* )
*/
#[ORM\Column]
#[
OA\Property(
description: "Whether this playlist's media is included in 'on demand' download/streaming if enabled.",
example: true
),
ORM\Column
]
protected bool $include_in_on_demand = false;
/** @OA\Property(example=false) */
#[ORM\Column]
#[
OA\Property(example: false),
ORM\Column
]
protected bool $include_in_automation = false;
/** @OA\Property(example="interrupt,loop_once,single_track,merge") */
#[ORM\Column(length: 255, nullable: true)]
#[
OA\Property(example: "interrupt,loop_once,single_track,merge"),
ORM\Column(length: 255, nullable: true)
]
protected ?string $backend_options = '';
/** @OA\Property(example=true) */
#[ORM\Column]
#[
OA\Property(example: true),
ORM\Column
]
protected bool $avoid_duplicates = true;
#[ORM\Column]
#[Attributes\AuditIgnore]
#[
ORM\Column,
Attributes\AuditIgnore
]
protected int $played_at = 0;
#[ORM\Column]
#[Attributes\AuditIgnore]
#[
ORM\Column,
Attributes\AuditIgnore
]
protected int $queue_reset_at = 0;
#[ORM\OneToMany(mappedBy: 'playlist', targetEntity: StationPlaylistMedia::class, fetch: 'EXTRA_LAZY')]
#[ORM\OrderBy(['weight' => 'ASC'])]
#[
ORM\OneToMany(mappedBy: 'playlist', targetEntity: StationPlaylistMedia::class, fetch: 'EXTRA_LAZY'),
ORM\OrderBy(['weight' => 'ASC'])
]
protected Collection $media_items;
#[ORM\OneToMany(mappedBy: 'playlist', targetEntity: StationPlaylistFolder::class, fetch: 'EXTRA_LAZY')]
#[
ORM\OneToMany(mappedBy: 'playlist', targetEntity: StationPlaylistFolder::class, fetch: 'EXTRA_LAZY')
]
protected Collection $folders;
/**
* @OA\Property(
* type="array",
* @OA\Items()
* )
*/
#[ORM\OneToMany(mappedBy: 'playlist', targetEntity: StationSchedule::class, fetch: 'EXTRA_LAZY')]
#[DeepNormalize(true)]
#[Serializer\MaxDepth(1)]
#[
OA\Property(type: "array", items: new OA\Items()),
ORM\OneToMany(mappedBy: 'playlist', targetEntity: StationSchedule::class, fetch: 'EXTRA_LAZY'),
DeepNormalize(true),
Serializer\MaxDepth(1)
]
protected Collection $schedule_items;
public function __construct(Station $station)

View File

@ -12,8 +12,8 @@ use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
use OpenApi\Annotations as OA;
/** @OA\Schema(type="object") */
#[
OA\Schema(type: "object"),
ORM\Entity,
ORM\Table(name: 'station_schedules'),
Attributes\Auditable
@ -22,20 +22,28 @@ class StationSchedule implements IdentifiableEntityInterface
{
use Traits\HasAutoIncrementId;
#[ORM\ManyToOne(inversedBy: 'schedule_items')]
#[ORM\JoinColumn(name: 'playlist_id', referencedColumnName: 'id', nullable: true, onDelete: 'CASCADE')]
#[
ORM\ManyToOne(inversedBy: 'schedule_items'),
ORM\JoinColumn(name: 'playlist_id', referencedColumnName: 'id', nullable: true, onDelete: 'CASCADE')
]
protected ?StationPlaylist $playlist = null;
#[ORM\ManyToOne(inversedBy: 'schedule_items')]
#[ORM\JoinColumn(name: 'streamer_id', referencedColumnName: 'id', nullable: true, onDelete: 'CASCADE')]
#[
ORM\ManyToOne(inversedBy: 'schedule_items'),
ORM\JoinColumn(name: 'streamer_id', referencedColumnName: 'id', nullable: true, onDelete: 'CASCADE')
]
protected ?StationStreamer $streamer = null;
/** @OA\Property(example=900) */
#[ORM\Column(type: 'smallint')]
#[
OA\Property(example: 900),
ORM\Column(type: 'smallint')
]
protected int $start_time = 0;
/** @OA\Property(example=2200) */
#[ORM\Column(type: 'smallint')]
#[
OA\Property(example: 2200),
ORM\Column(type: 'smallint')
]
protected int $end_time = 0;
#[ORM\Column(length: 10, nullable: true)]
@ -44,17 +52,19 @@ class StationSchedule implements IdentifiableEntityInterface
#[ORM\Column(length: 10, nullable: true)]
protected ?string $end_date = null;
/**
* @OA\Property(
* description="Array of ISO-8601 days (1 for Monday, 7 for Sunday)",
* example="0,1,2,3"
* )
*/
#[ORM\Column(length: 50, nullable: true)]
#[
OA\Property(
description: "Array of ISO-8601 days (1 for Monday, 7 for Sunday)",
example: "0,1,2,3"
),
ORM\Column(length: 50, nullable: true)
]
protected ?string $days = null;
/** @OA\Property(example=false) */
#[ORM\Column]
#[
OA\Property(example: false),
ORM\Column
]
protected bool $loop_once = false;
public function __construct(StationPlaylist|StationStreamer $relation)

View File

@ -16,12 +16,11 @@ use Symfony\Component\Validator\Constraints as Assert;
use const PASSWORD_ARGON2ID;
/**
* Station streamers (DJ accounts) allowed to broadcast to a station.
*
* @OA\Schema(type="object")
*/
#[
OA\Schema(
description: 'Station streamers (DJ accounts) allowed to broadcast to a station.',
type: "object"
),
ORM\Entity,
ORM\Table(name: 'station_streamers'),
ORM\UniqueConstraint(name: 'username_unique_idx', columns: ['station_id', 'streamer_username']),
@ -40,51 +39,64 @@ class StationStreamer implements
#[ORM\Column(nullable: false)]
protected int $station_id;
#[ORM\ManyToOne(inversedBy: 'streamers')]
#[ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
#[
ORM\ManyToOne(inversedBy: 'streamers'),
ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')
]
protected Station $station;
/** @OA\Property(example="dj_test") */
#[ORM\Column(length: 50)]
#[Assert\NotBlank]
#[
OA\Property(example: "dj_test"),
ORM\Column(length: 50),
Assert\NotBlank
]
protected string $streamer_username;
/** @OA\Property(example="") */
#[ORM\Column(length: 255)]
#[Assert\NotBlank]
#[Attributes\AuditIgnore]
#[
OA\Property(example: ""),
ORM\Column(length: 255),
Assert\NotBlank,
Attributes\AuditIgnore
]
protected string $streamer_password;
/** @OA\Property(example="Test DJ") */
#[ORM\Column(length: 255, nullable: true)]
#[
OA\Property(example: "Test DJ"),
ORM\Column(length: 255, nullable: true)
]
protected ?string $display_name = null;
/** @OA\Property(example="This is a test DJ account.") */
#[ORM\Column(type: 'text', nullable: true)]
#[
OA\Property(example: "This is a test DJ account."),
ORM\Column(type: 'text', nullable: true)
]
protected ?string $comments = null;
/** @OA\Property(example=true) */
#[ORM\Column]
#[
OA\Property(example: true),
ORM\Column
]
protected bool $is_active = true;
/** @OA\Property(example=false) */
#[ORM\Column]
#[
OA\Property(example: false),
ORM\Column
]
protected bool $enforce_schedule = false;
/** @OA\Property(example=1609480800) */
#[ORM\Column(nullable: true)]
#[Attributes\AuditIgnore]
#[
OA\Property(example: 1609480800),
ORM\Column(nullable: true),
Attributes\AuditIgnore
]
protected ?int $reactivate_at = null;
/**
* @OA\Property(
* type="array",
* @OA\Items()
* )
*/
#[ORM\OneToMany(mappedBy: 'streamer', targetEntity: StationSchedule::class)]
#[DeepNormalize(true)]
#[Serializer\MaxDepth(1)]
#[
OA\Property(type: "array", items: new OA\Items()),
ORM\OneToMany(mappedBy: 'streamer', targetEntity: StationSchedule::class),
DeepNormalize(true),
Serializer\MaxDepth(1)
]
protected Collection $schedule_items;
public function __construct(Station $station)

View File

@ -10,12 +10,11 @@ use Carbon\CarbonImmutable;
use Doctrine\ORM\Mapping as ORM;
use OpenApi\Annotations as OA;
/**
* Each individual broadcast associated with a streamer.
*
* @OA\Schema(type="object")
*/
#[
OA\Schema(
description: 'Each individual broadcast associated with a streamer.',
type: "object"
),
ORM\Entity,
ORM\Table(name: 'station_streamer_broadcasts')
]
@ -26,12 +25,16 @@ class StationStreamerBroadcast implements IdentifiableEntityInterface
public const PATH_PREFIX = 'stream';
#[ORM\ManyToOne(inversedBy: 'streamer_broadcasts')]
#[ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
#[
ORM\ManyToOne(inversedBy: 'streamer_broadcasts'),
ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')
]
protected Station $station;
#[ORM\ManyToOne(inversedBy: 'broadcasts')]
#[ORM\JoinColumn(name: 'streamer_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
#[
ORM\ManyToOne(inversedBy: 'broadcasts'),
ORM\JoinColumn(name: 'streamer_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')
]
protected StationStreamer $streamer;
#[ORM\Column(name: 'timestamp_start')]

View File

@ -9,10 +9,8 @@ use OpenApi\Annotations as OA;
use Stringable;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @OA\Schema(type="object")
*/
#[
OA\Schema(type: "object"),
ORM\Entity,
ORM\Table(name: 'station_webhooks', options: ['charset' => 'utf8mb4', 'collate' => 'utf8mb4_unicode_ci']),
Attributes\Auditable
@ -39,62 +37,66 @@ class StationWebhook implements
#[ORM\Column(nullable: false)]
protected int $station_id;
#[ORM\ManyToOne(inversedBy: 'webhooks')]
#[ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
#[
ORM\ManyToOne(inversedBy: 'webhooks'),
ORM\JoinColumn(name: 'station_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')
]
protected Station $station;
/**
* @OA\Property(
* description="The nickname of the webhook connector.",
* example="Twitter Post"
* )
*/
#[ORM\Column(length: 100, nullable: true)]
#[
OA\Property(
description: "The nickname of the webhook connector.",
example: "Twitter Post"
),
ORM\Column(length: 100, nullable: true)
]
protected ?string $name = null;
/**
* @OA\Property(
* description="The type of webhook connector to use.",
* example="twitter"
* )
*/
#[ORM\Column(length: 100)]
#[Assert\NotBlank]
#[
OA\Property(
description: "The type of webhook connector to use.",
example: "twitter"
),
ORM\Column(length: 100),
Assert\NotBlank
]
protected string $type;
/** @OA\Property(example=true) */
#[ORM\Column]
#[
OA\Property(example: true),
ORM\Column
]
protected bool $is_enabled = true;
/**
* @OA\Property(
* type="array",
* description="List of events that should trigger the webhook notification.",
* @OA\Items()
* )
*/
#[ORM\Column(type: 'json', nullable: true)]
#[
OA\Property(
type: "array",
description: "List of events that should trigger the webhook notification.",
items: new OA\Items()
),
ORM\Column(type: 'json', nullable: true)
]
protected ?array $triggers = null;
/**
* @OA\Property(
* type="array",
* description="Detailed webhook configuration (if applicable)",
* @OA\Items()
* )
*/
#[ORM\Column(type: 'json', nullable: true)]
#[
OA\Property(
type: "array",
description: "Detailed webhook configuration (if applicable)",
items: new OA\Items()
),
ORM\Column(type: 'json', nullable: true)
]
protected ?array $config = null;
/**
* @OA\Property(
* type="array",
* description="Internal details used by the webhook to preserve state.",
* @OA\Items()
* )
*/
#[ORM\Column(type: 'json', nullable: true)]
#[Attributes\AuditIgnore]
#[
OA\Property(
type: "array",
description: "Internal details used by the webhook to preserve state.",
items: new OA\Items()
),
ORM\Column(type: 'json', nullable: true),
Attributes\AuditIgnore
]
protected ?array $metadata = null;
public function __construct(Station $station, string $type)

View File

@ -22,8 +22,8 @@ use Symfony\Component\Validator\Constraints as Assert;
use const PASSWORD_BCRYPT;
/** @OA\Schema(type="object") */
#[
OA\Schema(type: "object"),
ORM\Entity,
ORM\Table(name: 'users'),
ORM\HasLifecycleCallbacks,
@ -36,73 +36,90 @@ class User implements Stringable, IdentifiableEntityInterface
use Traits\HasAutoIncrementId;
use Traits\TruncateStrings;
/** @OA\Property(example="demo@azuracast.com") */
#[ORM\Column(length: 100, nullable: false)]
#[Assert\NotBlank]
#[Assert\Email]
#[Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: "demo@azuracast.com"),
ORM\Column(length: 100, nullable: false),
Assert\NotBlank,
Assert\Email,
Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected string $email;
#[ORM\Column(length: 255, nullable: false)]
#[Attributes\AuditIgnore]
#[
ORM\Column(length: 255, nullable: false),
Attributes\AuditIgnore
]
protected string $auth_password = '';
/** @OA\Property(example="") */
#[Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: ""),
Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $new_password = null;
/** @OA\Property(example="Demo Account") */
#[ORM\Column(length: 100, nullable: true)]
#[Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: "Demo Account"),
ORM\Column(length: 100, nullable: true),
Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $name = null;
/** @OA\Property(example="en_US") */
#[ORM\Column(length: 25, nullable: true)]
#[Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: "en_US"),
ORM\Column(length: 25, nullable: true),
Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $locale = null;
/** @OA\Property(example="dark") */
#[ORM\Column(length: 25, nullable: true)]
#[Attributes\AuditIgnore]
#[Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: "dark"),
ORM\Column(length: 25, nullable: true),
Attributes\AuditIgnore,
Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $theme = null;
/** @OA\Property(example="A1B2C3D4") */
#[ORM\Column(length: 255, nullable: true)]
#[Attributes\AuditIgnore]
#[Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: "A1B2C3D4"),
ORM\Column(length: 255, nullable: true),
Attributes\AuditIgnore,
Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])
]
protected ?string $two_factor_secret = null;
/** @OA\Property(example=1609480800) */
#[ORM\Column]
#[Attributes\AuditIgnore]
#[Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: 1609480800),
ORM\Column,
Attributes\AuditIgnore,
Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])
]
protected int $created_at;
/** @OA\Property(example=1609480800) */
#[ORM\Column]
#[Attributes\AuditIgnore]
#[Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[
OA\Property(example: 1609480800),
ORM\Column,
Attributes\AuditIgnore,
Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])
]
protected int $updated_at;
/**
* @OA\Property(
* type="array",
* @OA\Items()
* )
*/
#[ORM\ManyToMany(targetEntity: Role::class, inversedBy: 'users', fetch: 'EAGER')]
#[ORM\JoinTable(name: 'user_has_role')]
#[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
#[ORM\InverseJoinColumn(name: 'role_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
#[Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[DeepNormalize(true)]
#[Serializer\MaxDepth(1)]
#[
OA\Property(type: "array", items: new OA\Items()),
ORM\ManyToMany(targetEntity: Role::class, inversedBy: 'users', fetch: 'EAGER'),
ORM\JoinTable(name: 'user_has_role'),
ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', onDelete: 'CASCADE'),
ORM\InverseJoinColumn(name: 'role_id', referencedColumnName: 'id', onDelete: 'CASCADE'),
Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL]),
DeepNormalize(true),
Serializer\MaxDepth(1)
]
protected Collection $roles;
#[ORM\OneToMany(mappedBy: 'user', targetEntity: ApiKey::class)]
#[Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
#[DeepNormalize(true)]
#[
ORM\OneToMany(mappedBy: 'user', targetEntity: ApiKey::class),
Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL]),
DeepNormalize(true)
]
protected Collection $api_keys;
public function __construct()