* @param array $payload * @return array */
(McpOpsContext $ctx, array $payload)
| 766 | * @return array<string,mixed> |
| 767 | */ |
| 768 | private static function opCreateFile(McpOpsContext $ctx, array $payload): array |
| 769 | { |
| 770 | return self::withSourceContext($ctx, $payload, true, function () use ($ctx, $payload): array { |
| 771 | self::assertWritableAccount($ctx, false); |
| 772 | |
| 773 | $folder = self::normalizeFolder((string)($payload['folder'] ?? 'root')); |
| 774 | $fileName = self::normalizeFileName( |
| 775 | (string)($payload['name'] ?? ($payload['file'] ?? ($payload['filename'] ?? ''))) |
| 776 | ); |
| 777 | |
| 778 | $username = $ctx->username(); |
| 779 | $perms = $ctx->permissions(); |
| 780 | |
| 781 | $canCreate = ACL::canCreate($username, $perms, $folder) |
| 782 | || ACL::ownsFolderOrAncestor($username, $perms, $folder); |
| 783 | if (!$canCreate) { |
| 784 | throw new RuntimeException('Forbidden: no create permission.', 403); |
| 785 | } |
| 786 | |
| 787 | self::assertFolderScope($ctx, $folder, 'create'); |
| 788 | |
| 789 | $result = FileModel::createFile($folder, $fileName, $username); |
| 790 | if (!is_array($result)) { |
| 791 | throw new RuntimeException('Failed to create file.', 500); |
| 792 | } |
| 793 | if (empty($result['success'])) { |
| 794 | $status = (int)($result['code'] ?? 400); |
| 795 | if ($status < 400 || $status > 599) { |
| 796 | $status = 400; |
| 797 | } |
| 798 | throw new RuntimeException((string)($result['error'] ?? 'Failed to create file.'), $status); |
| 799 | } |
| 800 | |
| 801 | return [ |
| 802 | 'ok' => true, |
| 803 | 'folder' => $folder, |
| 804 | 'file' => $fileName, |
| 805 | 'result' => $result, |
| 806 | ]; |
| 807 | }); |
| 808 | } |
| 809 | |
| 810 | /** |
| 811 | * @param array<string,mixed> $payload |
no test coverage detected