GitHub user johannes-ws closed a discussion: Failed when try to update rules via endpoint /api/v1/rowlevelsecurity/{pk} with status code 201 in Superset 5.0.0
When i run this code, import requests import os import json # --- REQUIRED CONFIGURATION --- SUPERSET_URL = os.getenv("SUPERSET_URL", "http://localhost:8088") ADMIN_USERNAME = os.getenv("SUPERSET_USER", "admin") ADMIN_PASSWORD = os.getenv("SUPERSET_PASSWORD", "admin") # --- PROGRAM STUDY CODE MAPPING (KAPRODI) --- # REQUIRED: Complete this dictionary with your data. # Format: "short_program_name_from_role": numeric_program_code KAPRODI_CODE_MAPPING = { "if": 135, "mesin": 131, # "elektro": 133, # Add all your kaprodi (program study) mappings here } def main(): """Main function to run the automation process with CREATE or UPDATE logic.""" # Use a session object to maintain login cookies, which are needed for CSRF with requests.Session() as session: # 1. Authenticate and get CSRF token print("1. Authenticating to Superset...") try: # Login login_data = {"username": ADMIN_USERNAME, "password": ADMIN_PASSWORD, "provider": "db"} r_login = session.post(f"{SUPERSET_URL}/api/v1/security/login", json=login_data) r_login.raise_for_status() access_token = r_login.json()["access_token"] # Set headers for the entire session session.headers.update({ "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" }) print(" -> Authentication successful.") # Get CSRF token print(" -> Fetching CSRF token...") r_csrf = session.get(f"{SUPERSET_URL}/api/v1/security/csrf_token/") r_csrf.raise_for_status() csrf_token = r_csrf.json()['result'] # Add CSRF token to headers for all future state-changing requests (POST, PUT, DELETE) session.headers['X-CSRFToken'] = csrf_token print(" -> CSRF token obtained.") except requests.exceptions.RequestException as e: print(f" -> FAILED during login/CSRF process: {e}") return # 2. Fetch all necessary data print("\n2. Fetching data from Superset...") params = {"q": json.dumps({"page_size": -1})} try: r_datasets = session.get(f"{SUPERSET_URL}/api/v1/dataset/", params=params) r_datasets.raise_for_status() all_dataset_ids = [ds['id'] for ds in r_datasets.json()['result']] r_roles = session.get(f"{SUPERSET_URL}/api/v1/security/roles/", params=params) r_roles.raise_for_status() roles_map = {role['name']: role['id'] for role in r_roles.json()['result']} # IMPORTANT CHANGE: Store the NAME and ID of existing rules in a dictionary/map r_rls = session.get(f"{SUPERSET_URL}/api/v1/rowlevelsecurity/", params=params) r_rls.raise_for_status() existing_rules_map = {rule['name']: rule['id'] for rule in r_rls.json()['result']} print(f" -> Found {len(all_dataset_ids)} datasets, {len(roles_map)} roles, and {len(existing_rules_map)} existing RLS rules.") except requests.exceptions.RequestException as e: print(f" -> FAILED to fetch data: {e}") return if not all_dataset_ids: print("\nWARNING: No datasets found. No rules will be created or updated.") return print("\n3. Processing roles and creating or updating RLS rules...") for role_name, role_id in roles_map.items(): rule_name = None clause = None # Logic to determine rule_name and clause remains the same if role_name.lower().startswith('dekan ') and role_name.lower() != 'dekan': fakultas_code = role_name.split(' ', 1)[1].upper() rule_name = f"Rule Dekan {fakultas_code}" clause = f"kd_fak = '{fakultas_code}'" elif role_name.lower().startswith('kaprodi ') and role_name.lower() != 'kaprodi': prodi_short_name = role_name.split(' ', 1)[1].lower() prodi_code = KAPRODI_CODE_MAPPING.get(prodi_short_name) if prodi_code: rule_name = f"Rule Kaprodi {prodi_short_name.upper()}" clause = f"no_ps = {prodi_code}" else: if prodi_short_name: # Only print warning if there is a name to warn about print(f"\n- WARNING: No code mapping found for '{prodi_short_name}'. Skipping role '{role_name}'.") continue # --- NEW LOGIC: CREATE OR UPDATE --- if rule_name: print(f"\n- Processing rule for role: '{role_name}'") # This payload will be used for both creating (POST) and updating (PUT) payload = { "name": rule_name, "filter_type": "Regular", "clause": clause, "roles": [role_id], "tables": all_dataset_ids, "description": "Automatically created or updated by Python script." } if rule_name in existing_rules_map: # --- IF RULE EXISTS: PERFORM UPDATE (PUT) --- rule_id_to_update = existing_rules_map[rule_name] print(f" -> Rule '{rule_name}' exists (ID: {rule_id_to_update}). Updating...") try: r_update = session.put(f"{SUPERSET_URL}/api/v1/rowlevelsecurity/{rule_id_to_update}", json=payload) if r_update.status_code == 200: print(f" -> SUCCESS: Rule updated.") else: print(f" -> FAILED to update. Status: {r_update.status_code}, Message: {r_update.text}") except requests.exceptions.RequestException as e: print(f" -> FAILED due to an exception: {e}") else: # --- IF RULE DOES NOT EXIST: PERFORM CREATE (POST) --- print(f" -> Rule '{rule_name}' does not exist. Creating...") try: r_create = session.post(f"{SUPERSET_URL}/api/v1/rowlevelsecurity/", json=payload) if r_create.status_code == 201: print(f" -> SUCCESS: Rule created.") # Add the new rule to the map so we don't try to re-create it in the same session new_rule_id = r_create.json().get('id') if new_rule_id: existing_rules_map[rule_name] = new_rule_id else: print(f" -> FAILED to create. Status: {r_create.status_code}, Message: {r_create.text}") except requests.exceptions.RequestException as e: print(f" -> FAILED due to an exception: {e}") print("\n4. Process finished.") if __name__ == "__main__": main() i got an error message when try to update rules. - Processing rule for role: 'Kaprodi Mesin' -> Rule 'Rule Kaprodi MESIN' exists (ID: 12). Updating... -> FAILED to update. Status: 201, Message: { "id": 12, "result": { "clause": "no_ps = 131", "description": "Automatically created or updated by Python script.", "filter_type": "Regular", "name": "Rule Kaprodi MESIN", "roles": [ 9 ], "tables": [ 25, 20, 11, 17, 12, 10, 18, 2, 15, 13, 21, 5, 19, 24, 8, 6, 16, 4, 23, 1, 22, 3, 14, 9, 7 ] } } Where is my fault? GitHub link: https://github.com/apache/superset/discussions/34546 ---- This is an automatically sent email for notifications@superset.apache.org. To unsubscribe, please send an email to: notifications-unsubscr...@superset.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org For additional commands, e-mail: notifications-h...@superset.apache.org