GitHub user johannes-ws created 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

Reply via email to