parent
43a04c2918
commit
15818964b7
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PublicSourceChannel;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class PublicSourceChannelController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$channels = PublicSourceChannel::query()
|
||||
->orderByDesc('id')
|
||||
->get()
|
||||
->map(fn (PublicSourceChannel $channel) => $this->toRow($channel, $request))
|
||||
->values();
|
||||
|
||||
return response()->json(['data' => $channels]);
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'source_code' => [
|
||||
'required',
|
||||
'string',
|
||||
'min:2',
|
||||
'max:64',
|
||||
'regex:/^[A-Za-z0-9_-]{2,64}$/',
|
||||
Rule::unique('public_source_channels', 'source_code'),
|
||||
],
|
||||
'source_name' => ['required', 'string', 'min:1', 'max:100'],
|
||||
'status' => ['sometimes', Rule::in(PublicSourceChannel::STATUSES)],
|
||||
]);
|
||||
|
||||
$channel = PublicSourceChannel::query()->create([
|
||||
'source_code' => trim($data['source_code']),
|
||||
'source_name' => trim($data['source_name']),
|
||||
'status' => $data['status'] ?? PublicSourceChannel::STATUS_ENABLED,
|
||||
]);
|
||||
|
||||
return response()->json($this->toRow($channel, $request), 201);
|
||||
}
|
||||
|
||||
public function show(Request $request, PublicSourceChannel $publicSourceChannel): JsonResponse
|
||||
{
|
||||
return response()->json($this->toRow($publicSourceChannel, $request));
|
||||
}
|
||||
|
||||
public function update(Request $request, PublicSourceChannel $publicSourceChannel): JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'source_code' => [
|
||||
'sometimes',
|
||||
'string',
|
||||
'min:2',
|
||||
'max:64',
|
||||
'regex:/^[A-Za-z0-9_-]{2,64}$/',
|
||||
Rule::unique('public_source_channels', 'source_code')->ignore($publicSourceChannel->id),
|
||||
],
|
||||
'source_name' => ['sometimes', 'string', 'min:1', 'max:100'],
|
||||
'status' => ['sometimes', Rule::in(PublicSourceChannel::STATUSES)],
|
||||
]);
|
||||
|
||||
if (array_key_exists('source_code', $data)) {
|
||||
$publicSourceChannel->source_code = trim($data['source_code']);
|
||||
}
|
||||
if (array_key_exists('source_name', $data)) {
|
||||
$publicSourceChannel->source_name = trim($data['source_name']);
|
||||
}
|
||||
if (array_key_exists('status', $data)) {
|
||||
$publicSourceChannel->status = $data['status'];
|
||||
}
|
||||
$publicSourceChannel->save();
|
||||
|
||||
return response()->json($this->toRow($publicSourceChannel, $request));
|
||||
}
|
||||
|
||||
public function destroy(PublicSourceChannel $publicSourceChannel): Response
|
||||
{
|
||||
$publicSourceChannel->status = PublicSourceChannel::STATUS_DISABLED;
|
||||
$publicSourceChannel->save();
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function toRow(PublicSourceChannel $channel, Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $channel->id,
|
||||
'source_code' => $channel->source_code,
|
||||
'source_name' => $channel->source_name,
|
||||
'status' => $channel->status,
|
||||
'entry_url' => $this->entryUrl($channel, $request),
|
||||
'created_at' => $channel->created_at?->toIso8601String(),
|
||||
'updated_at' => $channel->updated_at?->toIso8601String(),
|
||||
];
|
||||
}
|
||||
|
||||
private function entryUrl(PublicSourceChannel $channel, Request $request): string
|
||||
{
|
||||
$base = trim((string) config('public_source.frontend_url'));
|
||||
if ($base === '') {
|
||||
$base = $request->getSchemeAndHttpHost();
|
||||
}
|
||||
|
||||
return rtrim($base, '/').'/?src='.rawurlencode($channel->source_code);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PublicSourceChannel;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PublicSourceChannelController extends Controller
|
||||
{
|
||||
public function resolve(Request $request): JsonResponse
|
||||
{
|
||||
$sourceCode = trim((string) $request->query('source_code', ''));
|
||||
if (! preg_match('/^[A-Za-z0-9_-]{2,64}$/', $sourceCode)) {
|
||||
return response()->json(['valid' => false]);
|
||||
}
|
||||
|
||||
$channel = PublicSourceChannel::query()
|
||||
->where('source_code', $sourceCode)
|
||||
->where('status', PublicSourceChannel::STATUS_ENABLED)
|
||||
->first();
|
||||
|
||||
if ($channel === null) {
|
||||
return response()->json(['valid' => false]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'valid' => true,
|
||||
'source_code' => $channel->source_code,
|
||||
'source_name' => $channel->source_name,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class PublicSourceChannel extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
public const STATUS_ENABLED = 'enabled';
|
||||
|
||||
public const STATUS_DISABLED = 'disabled';
|
||||
|
||||
public const STATUSES = [
|
||||
self::STATUS_ENABLED,
|
||||
self::STATUS_DISABLED,
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'source_code',
|
||||
'source_name',
|
||||
'status',
|
||||
];
|
||||
|
||||
public function users(): HasMany
|
||||
{
|
||||
return $this->hasMany(User::class, 'public_source_channel_id');
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_ENABLED;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'frontend_url' => env('PUBLIC_FRONTEND_URL'),
|
||||
];
|
||||
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
use App\Models\PublicSourceChannel;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('public_source_channels', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('source_code', 64)->unique();
|
||||
$table->string('source_name', 100);
|
||||
$table->string('status')->default(PublicSourceChannel::STATUS_ENABLED);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('public_source_channels');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->foreignId('public_source_channel_id')
|
||||
->nullable()
|
||||
->after('last_channel_entered_at')
|
||||
->constrained('public_source_channels')
|
||||
->nullOnDelete();
|
||||
$table->string('public_source_code', 64)->nullable()->after('public_source_channel_id');
|
||||
$table->timestamp('public_source_attributed_at')->nullable()->after('public_source_code');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropForeign(['public_source_channel_id']);
|
||||
$table->dropColumn([
|
||||
'public_source_channel_id',
|
||||
'public_source_code',
|
||||
'public_source_attributed_at',
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
Loading…
Reference in new issue