fix: final review wave — public routes, inbox 419, url schemes, deep_link, tests

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCrwHHnGCB5XH968Nxokqw
This commit is contained in:
nikita.hohlov
2026-09-04 09:09:07 -03:00
parent dd714a4be1
commit cbb43714ae
20 changed files with 123 additions and 20 deletions

View File

@@ -31,8 +31,8 @@ class ChannelsController extends Controller
$data = $request->validate([
'type' => ['required', 'in:webhook'],
'config' => ['required', 'array'],
'config.deliver_url' => ['required', 'url'],
'config.presence_url' => ['required', 'url'],
'config.deliver_url' => ['required', 'url:http,https'],
'config.presence_url' => ['required', 'url:http,https'],
], ['type.in' => 'Через API добавляется только webhook; Telegram подключается через /start.']);
$channel = $user->channels()->create([

View File

@@ -10,9 +10,11 @@ use App\Ingest\EventUpserter;
use App\Models\Event;
use App\Models\Source;
use App\Models\User;
use Carbon\CarbonImmutable;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
class EventsController extends Controller
{
@@ -22,11 +24,14 @@ class EventsController extends Controller
{
/** @var User $user */
$user = $request->attributes->get('user');
$request->validate([
'state' => ['sometimes', Rule::in(array_map(fn ($s) => $s->value, EventState::cases()))],
]);
$states = $request->query('state')
? [$request->query('state')]
: EventState::nonTerminalValues();
$events = $user->events()->whereIn('state', $states)->orderBy('due_date')->orderBy('due_instant')->get();
$events = $user->events()->with('source')->whereIn('state', $states)->orderBy('due_date')->orderBy('due_instant')->get();
return response()->json(['events' => $events->map(fn (Event $e) => ApiPresenter::present($e) + ['source' => $e->source->name])->values()]);
}
@@ -66,7 +71,7 @@ class EventsController extends Controller
'source_ref' => 'manual:'.Str::ulid(),
'topic' => '',
'due_at' => $dueAt,
'fire_at' => \Carbon\CarbonImmutable::createFromFormat('Y-m-d', $data['due_date'])->subDays(30)->format('Y-m-d'),
'fire_at' => CarbonImmutable::createFromFormat('Y-m-d', $data['due_date'])->subDays(30)->format('Y-m-d'),
'after_due' => 'keep',
'payload' => array_filter([
'title' => $data['title'],

View File

@@ -10,7 +10,7 @@ use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Cache;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
use Illuminate\Validation\ValidationException;
class ProfileController extends Controller
{
@@ -33,7 +33,7 @@ class ProfileController extends Controller
$start = $data['quiet_start'] ?? substr($user->quiet_start, 0, 5);
$end = $data['quiet_end'] ?? substr($user->quiet_end, 0, 5);
if ($end >= $start) {
throw \Illuminate\Validation\ValidationException::withMessages([
throw ValidationException::withMessages([
'quiet_end' => 'Тихие часы должны переходить через полночь: quiet_end раньше quiet_start',
]);
}
@@ -64,7 +64,7 @@ class ProfileController extends Controller
'tz' => $user->tz,
'quiet_start' => substr($user->quiet_start, 0, 5),
'quiet_end' => substr($user->quiet_end, 0, 5),
'badge' => $user->events()->whereIn('state', [EventState::Today->value, EventState::Overdue->value])->count(),
'badge' => $user->events()->whereIn('state', EventState::badgeValues())->count(),
];
}
}