MCPcopy Create free account
hub / github.com/error311/FileRise / opMoveFolder

Method opMoveFolder

src/FileRise/Domain/McpCoreOpsService.php:1278–1472  ·  view source on GitHub ↗

* @param array $payload * @return array */

(McpOpsContext $ctx, array $payload)

Source from the content-addressed store, hash-verified

1276 * @return array<string,mixed>
1277 */
1278 private static function opMoveFolder(McpOpsContext $ctx, array $payload): array
1279 {
1280 self::assertWritableAccount($ctx, false);
1281
1282 $source = self::normalizeFolder((string)($payload['source'] ?? ''));
1283 if ($source === '' || $source === 'root') {
1284 throw new RuntimeException('Invalid source folder.', 400);
1285 }
1286
1287 $destinationRaw = trim((string)($payload['destination'] ?? 'root'));
1288 $destination = self::normalizeFolder($destinationRaw === '' ? 'root' : $destinationRaw);
1289
1290 $mode = strtolower(trim((string)($payload['mode'] ?? 'move')));
1291 if ($mode !== '' && $mode !== 'move') {
1292 throw new RuntimeException('Unsupported mode for MCP folder move.', 400);
1293 }
1294
1295 $sourcePair = self::resolveSourcePair($payload);
1296 $sourceId = $sourcePair['sourceId'];
1297 $destSourceId = $sourcePair['destSourceId'];
1298 $crossSource = $sourcePair['crossSource'];
1299
1300 if ($crossSource && (!class_exists(SourceContext::class) || !SourceContext::sourcesEnabled())) {
1301 throw new RuntimeException('Cross-source operations require sources to be enabled.', 400);
1302 }
1303
1304 $srcNorm = trim($source, "/\\ ");
1305 $dstNorm = $destination === 'root' ? '' : trim($destination, "/\\ ");
1306 if (
1307 !$crossSource
1308 && $dstNorm !== ''
1309 && (strcasecmp($dstNorm, $srcNorm) === 0 || strpos($dstNorm . '/', $srcNorm . '/') === 0)
1310 ) {
1311 throw new RuntimeException('Destination cannot be the source or its descendant.', 400);
1312 }
1313
1314 $baseName = basename(str_replace('\\', '/', $srcNorm));
1315 if ($baseName === '' || !preg_match((string)REGEX_FOLDER_NAME, $baseName)) {
1316 throw new RuntimeException('Invalid source folder.', 400);
1317 }
1318 $target = $destination === 'root' ? $baseName : rtrim($destination, "/\\ ") . '/' . $baseName;
1319 $target = self::normalizeFolder($target);
1320
1321 $username = $ctx->username();
1322 $perms = $ctx->permissions();
1323
1324 if ($crossSource) {
1325 self::assertWritableAccount($ctx, true);
1326 if ($sourceId === '' || $destSourceId === '') {
1327 throw new RuntimeException('Cross-source move requires both source ids.', 400);
1328 }
1329
1330 self::withSourceContext(
1331 $ctx,
1332 ['sourceId' => $sourceId],
1333 true,
1334 function () use ($ctx, $source, $username, $perms): array {
1335 $canManageSource = ACL::canManage($username, $perms, $source)

Callers 1

dispatchMethod · 0.95

Calls 15

assertWritableAccountMethod · 0.95
normalizeFolderMethod · 0.95
resolveSourcePairMethod · 0.95
withSourceContextMethod · 0.95
assertFolderScopeMethod · 0.95
usernameMethod · 0.80
permissionsMethod · 0.80
canManageMethod · 0.80
canCreateMethod · 0.80
canMoveMethod · 0.80

Tested by

no test coverage detected