@@ -1190,22 +1190,70 @@ def get(self, request):
11901190 workspace_id = getattr (settings , "POWERBI_WORKSPACE_ID" , None ) or os .getenv ("POWERBI_WORKSPACE_ID" )
11911191 # Receive report id from GET parameter only; do not use env/settings
11921192 report_id_param = request .query_params .get ("report_id" )
1193+ # Optional multi-resource dataset ids (pipe-separated GUIDs) – e.g. POWERBI_DATASET_IDS="id1|id2"
1194+ dataset_ids_raw = (
1195+ getattr (settings , "POWERBI_DATASET_IDS" , None )
1196+ or os .getenv ("POWERBI_DATASET_IDS" )
1197+ or os .getenv ("DATASET_IDS" ) # alternate env name if provided
1198+ )
1199+ # Azure CI cannot use comma-separated env values; switch to pipe "|".
1200+ # For backward compatibility we also accept commas if someone overrides locally.
1201+ if dataset_ids_raw and "|" in dataset_ids_raw :
1202+ raw_parts = dataset_ids_raw .split ("|" )
1203+ else :
1204+ raw_parts = (dataset_ids_raw or "" ).split ("," ) # legacy fallback
1205+ dataset_ids = [p .strip () for p in raw_parts if p .strip ()]
11931206 access_token = _pbi_token_via_managed_identity ()
11941207
11951208 # Optional debug-lite: log selected token claims and config when requested
11961209 debug_flag = str (request .query_params .get ("debug" , "" )).lower () in {"1" , "true" , "yes" , "on" }
11971210 if debug_flag :
1211+ tenant_id = getattr (settings , "AZURE_TENANT_ID" , None ) or os .getenv ("AZURE_TENANT_ID" ) or os .getenv ("TENANT_ID" )
11981212 logger .info (
1199- "AuthPowerBI debug-lite enabled: workspace_id=%s report_id_param=%s has_token=%s" ,
1213+ "AuthPowerBI debug-lite enabled: workspace_id=%s report_id_param=%s has_token=%s tenant_id=%s dataset_ids=%s " ,
12001214 workspace_id ,
12011215 report_id_param ,
12021216 bool (access_token ),
1217+ tenant_id ,
1218+ dataset_ids ,
12031219 )
12041220 if access_token :
12051221 _log_token_claims_safe (access_token )
12061222
12071223 if access_token and workspace_id :
12081224 try :
1225+ # Multi-resource token flow if dataset IDs are provided and we have a report id.
1226+ if dataset_ids and report_id_param :
1227+ headers = {"Authorization" : f"Bearer { access_token } " }
1228+ # Fetch report metadata (embedUrl) first
1229+ r = requests .get (f"{ PBI_BASE } /groups/{ workspace_id } /reports/{ report_id_param } " , headers = headers , timeout = 10 )
1230+ r .raise_for_status ()
1231+ rep = r .json ()
1232+ embed_url = rep .get ("embedUrl" )
1233+ # Generate multi-resource embed token
1234+ m_headers = {** headers , "Content-Type" : "application/json" }
1235+ multi_payload = {
1236+ "datasets" : [{"id" : did , "xmlaPermissions" : "ReadOnly" } for did in dataset_ids ],
1237+ "reports" : [{"id" : report_id_param }],
1238+ }
1239+ t = requests .post (f"{ PBI_BASE } /GenerateToken" , headers = m_headers , json = multi_payload , timeout = 10 )
1240+ t .raise_for_status ()
1241+ token_json = t .json ()
1242+ embed_token = token_json .get ("token" )
1243+ expires_at = token_json .get ("expiration" )
1244+ return Response (
1245+ {
1246+ "detail" : "ok" ,
1247+ "embed_url" : embed_url ,
1248+ "report_id" : report_id_param ,
1249+ "embed_token" : embed_token ,
1250+ "expires_at" : expires_at ,
1251+ "user" : request .user .username ,
1252+ "multi_resource" : True ,
1253+ "dataset_ids" : dataset_ids ,
1254+ }
1255+ )
1256+ # Single-report fallback (original behavior)
12091257 embed_url , report_id , embed_token , expires_at = _pbi_get_embed_info (access_token , workspace_id , report_id_param )
12101258 return Response (
12111259 {
@@ -1215,10 +1263,12 @@ def get(self, request):
12151263 "embed_token" : embed_token ,
12161264 "expires_at" : expires_at ,
12171265 "user" : request .user .username ,
1266+ "multi_resource" : False ,
1267+ "dataset_ids" : dataset_ids or None ,
12181268 }
12191269 )
12201270 except Exception as e :
1221- logger .exception ("Power BI REST call failed, falling back to mock: %s" , e )
1271+ logger .exception ("AuthPowerBI: Power BI REST call failed, falling back to mock: %s" , e )
12221272
12231273 # Fallback mock if not configured or failed
12241274 embed_token = secrets .token_hex (8 ) # 16-char hex
@@ -1234,5 +1284,7 @@ def get(self, request):
12341284 "embed_token" : embed_token ,
12351285 "expires_at" : expires_at ,
12361286 "user" : request .user .username ,
1287+ "multi_resource" : False ,
1288+ "dataset_ids" : None ,
12371289 }
12381290 )
0 commit comments