johannes-ws opened a new issue, #34548:
URL: https://github.com/apache/superset/issues/34548

   ### Bug description
   
   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
           ]
         }
       }
   
   In https://superset.apache.org/docs/api, there is not response with code 201 
at method put endpoint /api/v1/rowlevelsecurity/{pk}.
   
   Anyone can help me?
   
   ### Screenshots/recordings
   
   _No response_
   
   ### Superset version
   
   5.0.0
   
   ### Python version
   
   3.11
   
   ### Node version
   
   18 or greater
   
   ### Browser
   
   Chrome
   
   ### Additional context
   
   _No response_
   
   ### Checklist
   
   - [x] I have searched Superset docs and Slack and didn't find a solution to 
my problem.
   - [x] I have searched the GitHub issue tracker and didn't find a similar bug 
report.
   - [x] I have checked Superset's logs for errors and if I found a relevant 
Python stacktrace, I included it here as text in the "additional context" 
section.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to