signupChannels() ->orderByDesc('id') ->get() ->map(fn (SignupChannel $channel) => $this->toSummary($channel, $competition)) ->values(); return response()->json([ 'data' => $channels, ]); } public function store(StoreSignupChannelRequest $request, Competition $competition): JsonResponse { /** @var SignupChannel $channel */ $channel = $competition->signupChannels()->create( $this->normalizePayload($request->validated(), true) ); return response()->json($this->toDetail($channel, $competition), 201); } public function show(Competition $competition, SignupChannel $signupChannel): JsonResponse { $this->assertChannelBelongs($competition, $signupChannel); $this->ensureEncryptionKeyPair($signupChannel); return response()->json($this->toDetail($signupChannel, $competition)); } public function update( UpdateSignupChannelRequest $request, Competition $competition, SignupChannel $signupChannel ): JsonResponse { $this->assertChannelBelongs($competition, $signupChannel); $signupChannel->fill($this->normalizePayload($request->validated())); $signupChannel->ensureEncryptionKeyPair(); $signupChannel->save(); return response()->json($this->toDetail($signupChannel, $competition)); } public function destroy(Competition $competition, SignupChannel $signupChannel): Response { $this->assertChannelBelongs($competition, $signupChannel); $signupChannel->delete(); return response()->noContent(); } /** * @return array */ private function toSummary(SignupChannel $channel, Competition $competition): array { return [ 'id' => $channel->id, 'competition_id' => $channel->competition_id, 'competition_name' => $competition->name, 'channel_code' => $channel->channel_code, 'channel_name' => $channel->channel_name, 'status' => $channel->status, 'encryption_algorithm' => $channel->encryption_algorithm ?: ChannelEntryEncryption::ALGORITHM, 'entry_encryption_enabled' => (bool) $channel->entry_encryption_enabled, 'success_callback_url' => $channel->success_callback_url, 'remark' => $channel->remark, 'created_at' => $channel->created_at?->toIso8601String(), 'updated_at' => $channel->updated_at?->toIso8601String(), ]; } /** * @return array */ private function toDetail(SignupChannel $channel, Competition $competition): array { $row = $this->toSummary($channel, $competition); $row['shared_secret'] = $channel->shared_secret; $row['encryption_public_key'] = $channel->encryption_public_key; return $row; } private function assertChannelBelongs(Competition $competition, SignupChannel $channel): void { if ((int) $channel->competition_id !== (int) $competition->id) { abort(404); } } private function ensureEncryptionKeyPair(SignupChannel $channel): void { $channel->ensureEncryptionKeyPair(); if ($channel->isDirty()) { $channel->save(); } } /** * @param array $payload * @return array */ private function normalizePayload(array $payload, bool $isCreate = false): array { if ($isCreate || array_key_exists('success_callback_url', $payload)) { $payload['success_callback_url'] = trim((string) ($payload['success_callback_url'] ?? '')); } return $payload; } }