Permissions graph cannot parsed

Hii :wave: ,
i tried to update permissions through api (requests) with endpoint /api/permissions/graph . i hit by an error i posted my code at the end and the log details are

2022-06-07T10:21:54+05:30 DEBUG metabase.server.middleware.log PUT /api/permissions/graph 400 3.3 ms (0 DB calls)
{:viastrong text
[{:type clojure.lang.ExceptionInfo,
:message
"Cannot parse permissions graph because it is invalid: {:body {:revision 33, :groups {:2 {:7 {:data {:native "write", :schemas "all"}, :download {:native "full", :schemas "full"}, :data-model {:schemas "all"}, :details "yes"}, :1 {:data {:native "write", :schemas "all"}, :download {:native "full", :schemas "full"}, :data-model {:schemas "all"}, :details "yes"}, :6 {:data {:native "write", :schemas "all"}, :download {:native "full", :schemas "full"}, :data-model {:schemas "all"}, :details "yes"}}, :1 {:1 {:download {:native "full", :schemas "full"}}, :6 {:download {:schemas "full", :native "full"}}}, :5 {:7 {:data {:schemas "all"}}, :6 {:data {:schemas "all"}}, :1 {:data {:schemas "all"}}}}}} - failed: (contains? % :groups) spec: :metabase.api.permission-graph/data-permissions-graph\n",
:data
{:status-code 400,
:error
{:clojure.spec.alpha/problems
({:path [],
:pred (clojure.core/fn [%] (clojure.core/contains? % :groups)),
:val
{:body
{:revision 33,
:groups
{:2
{:7
{:data {:native "write", :schemas "all"},
:download {:native "full", :schemas "full"},
:data-model {:schemas "all"},
:details "yes"},
:1
{:data {:native "write", :schemas "all"},
:download {:native "full", :schemas "full"},
:data-model {:schemas "all"},
:details "yes"},
:6
{:data {:native "write", :schemas "all"},
:download {:native "full", :schemas "full"},
:data-model {:schemas "all"},
:details "yes"}},
:1 {:1 {:download {:native "full", :schemas "full"}}, :6 {:download {:schemas "full", :native "full"}}},
:5 {:7 {:data {:schemas "all"}}, :6 {:data {:schemas "all"}}, :1 {:data {:schemas "all"}}}}}},
:via [:metabase.api.permission-graph/data-permissions-graph],
:in []}),
:clojure.spec.alpha/spec :metabase.api.permission-graph/data-permissions-graph,
:clojure.spec.alpha/value
{:body
{:revision 33,
:groups
{:2
{:7
{:data {:native "write", :schemas "all"},
:download {:native "full", :schemas "full"},
:data-model {:schemas "all"},
:details "yes"},
:1
{:data {:native "write", :schemas "all"},
:download {:native "full", :schemas "full"},
:data-model {:schemas "all"},
:details "yes"},
:6
{:data {:native "write", :schemas "all"},
:download {:native "full", :schemas "full"},
:data-model {:schemas "all"},
:details "yes"}},
:1 {:1 {:download {:native "full", :schemas "full"}}, :6 {:download {:schemas "full", :native "full"}}},
:5 {:7 {:data {:schemas "all"}}, :6 {:data {:schemas "all"}}, :1 {:data {:schemas "all"}}}}}}}},
:at [metabase.api.permissions$fn__60512 invokeStatic "permissions.clj" 47]}],
:trace

**i took the permissions graph structure from developer tools network tab (payload)
and my code
**

url ='https://meta**********.com/api/permissions/graph'

headers = {"Content-Type": "application/json;charset=utf-8",'X-Metabase-Session': token}

payload ={"groups":{"1":{"1":{"download":{"native":"full","schemas":"full"}},
"6":{"download":{"schemas":"full","native":"full"}}},
"2":{"1":{"data":{"native":"write","schemas":"all"},"download":{"native":"full","schemas":"full"},"data-model":{"schemas":"all"},"details":"yes"},
"6":{"data":{"native":"write","schemas":"all"},"download":{"native":"full","schemas":"full"},"data-model":{"schemas":"all"},"details":"yes"},
"7":{"data":{"native":"write","schemas":"all"},"download":{"native":"full","schemas":"full"},"data-model":{"schemas":"all"},"details":"yes"}},
"5":{"6":{"data":{"native":"write","schemas":"none"}},"7":{"data":{"schemas":"all"}}}},"revision":37}

data= {'body':payload}

response = requests.put(url, headers=headers,json=data)

print("Status Code", response.status_code)

print("JSON Response ", response.json())

i am not able to understand is this bug or my code was wrong if my code wrong
please mention right way to do it
i hope i will get a reply
Thank you

Hi @Rajesh_Yalla
There's no bug, but you are wrapping the payload incorrectly.
response = requests.put(url, headers=headers, json=payload)

Thank you for response @flamber is there any refference how to do it correctly

@Rajesh_Yalla Have a look at other Python API projects to learn some from there:
https://github.com/vvaezian/metabase_api_python

Thank you @flamber we have able to get it to work ,it works well
i was not setting the latest revision in the payload and thats why it is failed
Thank you

@Rajesh_Yalla No, then you would have received a 409 status code with the message:
Looks like someone else edited the permissions and your data is out of date. Please fetch new data and try again.

yes after wrapping correctly i mean in requests i got 409 then i changed revision number i figured it out and understand graph structure well.
thank you so much @flamber

Hi Rajesh, I am trying to do the same, it failing for me.

you need to give the correct revision number otherwise it will fail if possible show your payload

Current Response -
{
"revision":14,
"groups":{
"1":{
"5":{
"download":{
"native":"full",
"schemas":"full"
},
"data":{
"schemas":"all",
"native":"write"
}
},
"4":{
"download":{
"native":"full",
"schemas":"full"
}
},
"3":{
"download":{
"native":"full",
"schemas":"full"
}
},
"2":{
"download":{
"native":"full",
"schemas":"full"
}
},
"1":{
"download":{
"native":"full",
"schemas":"full"
}
}
},
"2":{
"1":{
"data":{
"native":"write",
"schemas":"all"
},
"download":{
"native":"full",
"schemas":"full"
},
"data-model":{
"schemas":"all"
},
"details":"yes"
},
"4":{
"data":{
"native":"write",
"schemas":"all"
},
"download":{
"native":"full",
"schemas":"full"
},
"data-model":{
"schemas":"all"
},
"details":"yes"
},
"3":{
"data":{
"native":"write",
"schemas":"all"
},
"download":{
"native":"full",
"schemas":"full"
},
"data-model":{
"schemas":"all"
},
"details":"yes"
},
"2":{
"data":{
"native":"write",
"schemas":"all"
},
"download":{
"native":"full",
"schemas":"full"
},
"data-model":{
"schemas":"all"
},
"details":"yes"
},
"5":{
"data":{
"native":"write",
"schemas":"all"
},
"download":{
"native":"full",
"schemas":"full"
},
"data-model":{
"schemas":"all"
},
"details":"yes"
}
},
"3":{
"5":{
"data":{
"schemas":"all",
"native":"write"
}
}
}
}
}

Modified Response-
Not allowing All User Group to See db (5) | Next Revison 14+1

{
"revision":15,
"groups":{
"1":{
"5":{
"download":{
"native":"full",
"schemas":"full"
}
},
"4":{
"download":{
"native":"full",
"schemas":"full"
}
},
"3":{
"download":{
"native":"full",
"schemas":"full"
}
},
"2":{
"download":{
"native":"full",
"schemas":"full"
}
},
"1":{
"download":{
"native":"full",
"schemas":"full"
}
}
},
"2":{
"1":{
"data":{
"native":"write",
"schemas":"all"
},
"download":{
"native":"full",
"schemas":"full"
},
"data-model":{
"schemas":"all"
},
"details":"yes"
},
"4":{
"data":{
"native":"write",
"schemas":"all"
},
"download":{
"native":"full",
"schemas":"full"
},
"data-model":{
"schemas":"all"
},
"details":"yes"
},
"3":{
"data":{
"native":"write",
"schemas":"all"
},
"download":{
"native":"full",
"schemas":"full"
},
"data-model":{
"schemas":"all"
},
"details":"yes"
},
"2":{
"data":{
"native":"write",
"schemas":"all"
},
"download":{
"native":"full",
"schemas":"full"
},
"data-model":{
"schemas":"all"
},
"details":"yes"
},
"5":{
"data":{
"native":"write",
"schemas":"all"
},
"download":{
"native":"full",
"schemas":"full"
},
"data-model":{
"schemas":"all"
},
"details":"yes"
}
},
"3":{
"5":{
"data":{
"schemas":"all",
"native":"write"
}
}
}
}
}

Case-1

permission_graph = requests.get('http://localhost:3000/api/permissions/graph',headers=headers).json()
permission_graph['groups']['1']['5'] = {
"download": {
"native": "full",
"schemas": "full"
}
}
permission_graph['revision']= permission_graph['revision']+1
response = requests.put('http://localhost:3000/api/permissions/graph', headers=headers, json=permission_graph)
print("Status Code", response.status_code)
print("JSON Response ", response.json())

Error -> Status Code 409

Case-2
permission_graph = requests.get('http://localhost:3000/api/permissions/graph',headers=headers).json()
permission_graph['groups']['1']['5'] = {
"download": {
"native": "full",
"schemas": "full"
}
}
response = requests.put('http://localhost:3000/api/permissions/graph', headers=headers, json=permission_graph)
print("Status Code", response.status_code)
print("JSON Response ", response.json())

Error -> Status Code 500

i will tell you how i am handling my permissions first stop 'ALL USERS' group permisions to all databases from metabase go and change there in settings in metabase page then you can freely give access to individual group permisions separetly then you can give permisions for each group.i will put small notes to understand graph structure this will help but you need to understand permissions clearly

Do a batch update of Permissions by passing in a modified graph. This should return the same graph, in the same format, that you got from GET [/api/permissions/graph] , with any changes made in the wherever necessary. This modified graph must correspond to the PermissionsGraph schema. If successful, this endpoint returns the updated permissions graph; use this as a base for any further modifications.

Revisions to the permissions graph are tracked. If you fetch the permissions graph and some other third-party modifies it before you can submit you revisions, the endpoint will instead make no changes and return a 409 (Conflict) response. In this case, you should fetch the updated graph and make desired changes to that.

You must be a superuser to do this.

Note:

  • updating new schema will rewrite the schema
  • if hit by 409 code update revision id
  • key words
    ["full" full access]
    ["all" all access for particular part]
    ["none" no access]
**structure example:**{'groups': {'1': {'1': {'download': {'native': 'full', 'schemas': 'full'}}, 
                                                                       '10': {'7': {'data': {'schemas': {'testschematwo': 'all'}}

{'groups': {'group_id': {'database_id': {'download': {'native(sql_editor)': 'full', 'schemas': 'full'}}
```**

Are you handling "all user" permission from UI. (If I understood correctly).

I am able to handle permission from api for all group except "all user" group,
I am only facing for group id =1 , can we do the same with api.