@@ -525,6 +525,10 @@ public function handleRequest(
525525 if ($ check_permission === true ) {
526526 if (false === Session::checkServicePermission ($ verb , $ service , $ resource , Session::getRequestor (),
527527 $ throw_exception )) {
528+ // For schema requests, try to get filtered results
529+ if ($ verb === Verbs::GET && $ resource === '_schema ' ) {
530+ return $ this ->getFilteredSchemaResponse ($ service , $ query );
531+ }
528532 return new ServiceResponse ([]);
529533 }
530534 }
@@ -547,6 +551,141 @@ public function handleRequest(
547551 return $ this ->getService ($ service )->handleRequest ($ request , $ resource );
548552 }
549553
554+ /**
555+ * Get filtered schema response based on user permissions
556+ *
557+ * @param string $service Service name
558+ * @param array $query Query parameters
559+ * @return ServiceResponse Filtered schema response
560+ */
561+ private function getFilteredSchemaResponse ($ service , $ query )
562+ {
563+ try {
564+ $ serviceInstance = $ this ->getService ($ service );
565+
566+ // Create a request with as_list parameter
567+ $ request = new ServiceRequest ();
568+ $ request ->setMethod (Verbs::GET );
569+ $ request ->setParameters (array_merge ($ query , ['as_list ' => true ]));
570+
571+ // Handle the request without permission checks
572+ $ response = $ serviceInstance ->handleRequest ($ request , '_schema ' );
573+
574+ // Filter the response based on user permissions
575+ $ content = $ response ->getContent ();
576+ $ allowedComponents = Session::getAllowedComponentsForGet ($ service );
577+
578+ if (!empty ($ allowedComponents ) && !in_array ('* ' , $ allowedComponents )) {
579+ $ content = $ this ->filterSchemaContent ($ content , $ allowedComponents );
580+ $ response ->setContent ($ content );
581+ }
582+
583+ return $ response ;
584+
585+ } catch (\Exception $ e ) {
586+ return new ServiceResponse ([], 'application/json ' , 500 );
587+ }
588+ }
589+
590+ /**
591+ * Filter schema content based on allowed components
592+ *
593+ * @param mixed $content Schema content to filter
594+ * @param array $allowedComponents Array of allowed component patterns
595+ * @return mixed Filtered content
596+ */
597+ private function filterSchemaContent ($ content , $ allowedComponents )
598+ {
599+ // Handle different content structures
600+ if (is_array ($ content )) {
601+ // Check if content is wrapped in resources wrapper
602+ $ wrapper = config ('df.resources_wrapper ' , 'resource ' );
603+ if (isset ($ content [$ wrapper ]) && is_array ($ content [$ wrapper ])) {
604+ $ resources = $ content [$ wrapper ];
605+ $ filteredResources = $ this ->filterResourcesByAccess ($ resources , $ allowedComponents );
606+ $ content [$ wrapper ] = $ filteredResources ;
607+ return $ content ;
608+ } else {
609+ return $ this ->filterResourcesByAccess ($ content , $ allowedComponents );
610+ }
611+ }
612+
613+ return $ content ;
614+ }
615+
616+ /**
617+ * Filter resources based on access patterns
618+ *
619+ * @param array $resources Array of resources to filter
620+ * @param array $allowedComponents Array of allowed component patterns
621+ * @return array Filtered resources
622+ */
623+ private function filterResourcesByAccess ($ resources , $ allowedComponents )
624+ {
625+ if (in_array ('* ' , $ allowedComponents )) {
626+ return $ resources ; // Full access
627+ }
628+
629+ $ filtered = [];
630+
631+ foreach ($ resources as $ resource ) {
632+ if (is_array ($ resource ) && isset ($ resource ['name ' ])) {
633+ $ resourceName = $ resource ['name ' ];
634+ } elseif (is_string ($ resource )) {
635+ $ resourceName = $ resource ;
636+ } else {
637+ continue ;
638+ }
639+
640+ // Check if this resource is allowed
641+ if ($ this ->isResourceAllowed ($ resourceName , $ allowedComponents )) {
642+ $ filtered [] = $ resource ;
643+ }
644+ }
645+
646+ return $ filtered ;
647+ }
648+
649+ /**
650+ * Check if a resource is allowed based on component patterns
651+ *
652+ * @param string $resourceName Name of the resource to check
653+ * @param array $allowedComponents Array of allowed component patterns
654+ * @return bool True if resource is allowed
655+ */
656+ private function isResourceAllowed ($ resourceName , $ allowedComponents )
657+ {
658+ foreach ($ allowedComponents as $ pattern ) {
659+ if ($ pattern === '* ' ) {
660+ return true ;
661+ }
662+
663+ if ($ pattern === $ resourceName ) {
664+ return true ;
665+ }
666+
667+ // Handle wildcard patterns like "table/*"
668+ if (strpos ($ pattern , '* ' ) !== false ) {
669+ $ pattern = str_replace ('* ' , '.* ' , $ pattern );
670+ $ pattern = '/^ ' . $ pattern . '$/ ' ;
671+ if (preg_match ($ pattern , $ resourceName )) {
672+ return true ;
673+ }
674+ }
675+
676+ // Handle dynamic parameters like "table/{id}"
677+ if (strpos ($ pattern , '{ ' ) !== false ) {
678+ $ regexPattern = preg_replace ('/\{[^}]+\}/ ' , '[^/]+ ' , $ pattern );
679+ $ regexPattern = '/^ ' . $ regexPattern . '$/ ' ;
680+ if (preg_match ($ regexPattern , $ resourceName )) {
681+ return true ;
682+ }
683+ }
684+ }
685+
686+ return false ;
687+ }
688+
550689 /**
551690 * Make the service instance.
552691 *
0 commit comments