schemaVersion: 3
meta:
  sourceVersionId: 01981470-39de-733f-86e5-9f4a818e5af8 # DO NOT CHANGE - Hex uses this to match up project versions when reimporting the file
  description: null
  projectId: 01975672-11fc-7ff5-8768-a822c7df951b # DO NOT CHANGE - Unique ID of the project from which this file was generated
  title: Admin API Endpoint Example - Users & Groups
  timezone: null
  appTheme: SYS_PREF
  codeLanguage: PYTHON
  status:
    name: Approved
  categories:
    - name: External
  castDecimalsDefault: true
  logicQueryCacheTimeout: null
  publishedQueryCacheTimeout: null
  hexType: PROJECT
  allowExecutionReordering: true
  prerunApp: false
  cachePublishedAppState: true
  refreshStalePublishedApp: false
  autoRerunApp: true
projectAssets:
  dataConnections: []
  envVars: []
  secrets:
    - secretName: admin_api_personal_token
sharedAssets:
  secrets: []
  vcsPackages: []
  dataConnections:
    - dataConnectionId: f1fcffd9-4b37-41d8-a1f4-42f5124abd37 # [Demo] Hex Public Data (snowflake)
  externalFileIntegrations: []
cells:
  - cellType: COLLAPSIBLE
    cellId: 01975672-1233-7ff5-876b-0eaf81414b21 # DO NOT CHANGE - Hex uses this to match up cells when reimporting the file, and detect any changes to existing cells
    cellLabel: Misc/Helpers
    config:
      labelStyle: AUTO
      cells:
        - cellType: CODE
          cellId: 01975672-1243-7ff5-876d-552dadcdff22
          cellLabel: null
          config:
            source: |-
              import requests
              import json 
              from types import SimpleNamespace


              def make_request(url_path, params, method, body=None):
                  headers = {
                      'Authorization': 'Bearer ' + admin_api_personal_token,
                  }

                  try:
                      domain = 'rc.hex.tech'
                      response = requests.request(method, f"https://{domain}/api/{url_path}",headers=headers,params=params, json=body, timeout=10)
                      if response.status_code > 299:
                          print(f"ERR:{response.json()}")
                          return(response.status_code)
                      response.raise_for_status()
                      if response.content:
                          return (response.json())
                      #return None
                  except requests.exceptions.RequestException as e:
                      print(f"HTTP Request failed: {e}")
        - cellType: CODE
          cellId: 01975672-1243-7ff5-876d-58b3e2fdddd9
          cellLabel: null
          config:
            source: |
              def helper_w_pagination(params = None, url = None, method = None):
                  first_page = make_request(url, params, method)
                  obj = json.loads(json.dumps(first_page), object_hook=lambda d: SimpleNamespace(**d))
                  after = obj.pagination.after
                  contents = obj.values

                  while after:
                      params['after'] = after
                      new_page = make_request(url, params, method)
                      response = json.loads(json.dumps(new_page), object_hook=lambda d: SimpleNamespace(**d))
                      try:
                          after = response.pagination.after
                          new_contents = response.values
                          contents = [*contents, *new_contents]
                      except:
                          break
                  return contents
        - cellType: CODE
          cellId: 01975672-1243-7ff5-876d-6190236fbffe
          cellLabel: null
          config:
            source: |
              def make_df(input_obj):
                  for i, item in enumerate(input_obj):
                      if i == 0:
                          df = pd.DataFrame(columns = list(item.__dict__.keys()))
                      for col in list(item.__dict__.keys()):
                          df.loc[i, col] = eval('item.' + col)
                  return df
        - cellType: CODE
          cellId: 01975672-1243-7ff5-876d-6b674acd7889
          cellLabel: null
          config:
            source: |-
              def get_user_ids_by_emails(email_list):
                  # Filter users_df for rows where 'email' is in the provided list
                  filtered_df = users_df[users_df['email'].isin(email_list)]
                  return filtered_df['id'].tolist()
  - cellType: COLLAPSIBLE
    cellId: 01975672-1233-7ff5-876b-137d70473260 # DO NOT CHANGE - Hex uses this to match up cells when reimporting the file, and detect any changes to existing cells
    cellLabel: Users
    config:
      labelStyle: AUTO
      cells:
        - cellType: MARKDOWN
          cellId: 01975672-1245-7ff5-876e-2f73a99af8b0
          cellLabel: null
          config:
            source: "### Get a list of users, their user ids, and Hex roles"
        - cellType: CODE
          cellId: 01975672-1243-7ff5-876d-770461923533
          cellLabel: null
          config:
            source: |-
              method = 'GET'
              url = 'v1/users'
              params = {
                  'limit': 100
              }

              users = helper_w_pagination(url = url, params = params, method = method)
              users_df = make_df(users)
        - cellType: PIVOT
          cellId: 01975672-1255-7ff5-876f-340de6245af3
          cellLabel: null
          config:
            castDecimals: true
            dataframeName: users_df
            resultVariable: pivot_result
            pivotConfig:
              rows:
                - field: role
                  fieldType: STRING
              values:
                - field: id
                  fieldType: STRING
                  aggregation: COUNT
              columns: []
            tableDisplayConfig:
              pageSize: 50
              height: null
              hideIcons: false
              defaultColumnWidth: null
              hideIndex: false
              defaultSortColumn: null
              defaultSortIndexColumn: null
              defaultSortDirection: ASC
              conditionalFormatting: null
              calcs: null
              filters: null
              columnProperties:
                - originalName: pivot-header-role
                  renameTo: null
                  size: 90
                  wrapText: null
                  displayFormat: null
              columnOrdering: []
              customColumnOrdering: null
              pinnedColumns: null
              hiddenColumns: null
              pinIndexColumns: true
              showAggregations: false
              columnAggregations: null
        - cellType: TABLE_DISPLAY
          cellId: 01975672-1257-7ff5-876f-955e825f5e82
          cellLabel: null
          config:
            dataFrameVariableName: users_df
            resultVariable: table_result
            tableDisplayConfig:
              pageSize: 50
              height: null
              hideIcons: false
              defaultColumnWidth: null
              hideIndex: false
              defaultSortColumn: null
              defaultSortIndexColumn: null
              defaultSortDirection: ASC
              conditionalFormatting: null
              calcs: null
              filters: []
              columnProperties:
                - originalName: email
                  renameTo: null
                  size: 188
                  wrapText: null
                  displayFormat: null
                - originalName: id
                  renameTo: null
                  size: 278
                  wrapText: null
                  displayFormat: null
                - originalName: name
                  renameTo: null
                  size: 82
                  wrapText: null
                  displayFormat: null
                - originalName: role
                  renameTo: null
                  size: 81
                  wrapText: null
                  displayFormat: null
                - originalName: row-index-0
                  renameTo: null
                  size: 46
                  wrapText: null
                  displayFormat: null
              columnOrdering: null
              customColumnOrdering: null
              pinnedColumns: null
              hiddenColumns: null
              pinIndexColumns: false
              showAggregations: false
              columnAggregations: null
  - cellType: COLLAPSIBLE
    cellId: 01975672-1233-7ff5-876b-1ebd5f745e7a # DO NOT CHANGE - Hex uses this to match up cells when reimporting the file, and detect any changes to existing cells
    cellLabel: Groups
    config:
      labelStyle: AUTO
      cells:
        - cellType: MARKDOWN
          cellId: 01975672-1245-7ff5-876e-36809d2dca51
          cellLabel: null
          config:
            source: "### Get a list of all groups currently defined in Hex. "
        - cellType: CODE
          cellId: 01975672-1243-7ff5-876d-7d11acca08d7
          cellLabel: null
          config:
            source: |-
              method = 'GET'
              url = 'v1/groups'
              params = {
                  'limit': 100
              }

              groups = helper_w_pagination(url = url, params = params, method = method)
              groups_df = make_df(groups)
        - cellType: TABLE_DISPLAY
          cellId: 01975672-1257-7ff5-876f-9f2cf6631ccc
          cellLabel: null
          config:
            dataFrameVariableName: groups_df
            resultVariable: table_result_2
            tableDisplayConfig:
              pageSize: 50
              height: null
              hideIcons: false
              defaultColumnWidth: null
              hideIndex: false
              defaultSortColumn: null
              defaultSortIndexColumn: null
              defaultSortDirection: ASC
              conditionalFormatting: null
              calcs: null
              filters: null
              columnProperties:
                - originalName: createdAt
                  renameTo: null
                  size: 188
                  wrapText: null
                  displayFormat: null
                - originalName: email
                  renameTo: null
                  size: 188
                  wrapText: null
                  displayFormat: null
                - originalName: id
                  renameTo: null
                  size: 312
                  wrapText: null
                  displayFormat: null
                - originalName: name
                  renameTo: null
                  size: 159
                  wrapText: null
                  displayFormat: null
                - originalName: role
                  renameTo: null
                  size: 81
                  wrapText: null
                  displayFormat: null
                - originalName: row-index-0
                  renameTo: null
                  size: 46
                  wrapText: null
                  displayFormat: null
              columnOrdering: null
              customColumnOrdering: null
              pinnedColumns: null
              hiddenColumns: null
              pinIndexColumns: false
              showAggregations: false
              columnAggregations: null
        - cellType: MARKDOWN
          cellId: 01975672-1245-7ff5-876e-38ed1b5c9800
          cellLabel: null
          config:
            source: |-
              ### Create a new group given a list of user emails

              NOTE: Group names are not unique!

              If you create a group with the same name as one that already exists a new group with the same name will be created!
        - cellType: INPUT
          cellId: 01975672-124e-7ff5-876e-c02a6e643058
          cellLabel: user_emails_csv
          config:
            inputType: FILE_UPLOAD
            name: user_emails_csv
            outputType: DATA_FRAME
            options: null
            defaultValue:
              id: 01981470-39f1-733f-86e5-bf7c67afaac5
              name: user_emails_example (1).csv
              type: FILE
        - cellType: INPUT
          cellId: 01975672-124e-7ff5-876e-cfa568efb7c3
          cellLabel: new_group_name
          config:
            inputType: TEXT_INPUT
            name: new_group_name
            outputType: STRING
            options: null
            defaultValue: New Group from Email list
        - cellType: INPUT
          cellId: 01975672-124e-7ff5-876e-d23d409d0fea
          cellLabel: create_group
          config:
            inputType: BUTTON
            name: create_group
            outputType: BOOLEAN
            options: null
            defaultValue: null
        - cellType: CODE
          cellId: 01975672-1243-7ff5-876d-849c70bf0418
          cellLabel: null
          config:
            source: |-
              if create_group:
                  # Retrieve the user ids associated with the given user emails
                  # NOTE: A MAXIMUM OF 100 USER EMAILS CAN BE PASSED IN AT A TIME. IF YOU HAVE MORE THAN 100 USERS THAT NEED TO BE ADDED TO A GROUP.
                  #       YOU WILL NEED TO SPLIT THEM UP INTO MULTPLE SUBSETS AND USE THE EDIT GROUP FUNCTIONALITY AFTER THE FIRST BATCH

                  new_group_user_ids = get_user_ids_by_emails(user_emails_csv["email"].tolist())

                  params = {}
                  group_details = {
                      "name": new_group_name,
                      "members": {"users": [{"id": u_id} for u_id in new_group_user_ids]},
                  }

                  new_group_response = make_request(f"v1/groups", params, "POST", body=group_details)
                  new_group_id = new_group_response["id"]
                  print(f"Created a new group, '{new_group_name}', with id: {new_group_id}")
        - cellType: INPUT
          cellId: 01975672-124e-7ff5-876e-d894ac7060de
          cellLabel: Users to add
          config:
            inputType: FILE_UPLOAD
            name: users_to_add_csv
            outputType: DATA_FRAME
            options: null
            defaultValue:
              id: 01981470-39f1-733f-86e5-e032dfa7686f
              name: user_emails_to_add_example (1).csv
              type: FILE
        - cellType: INPUT
          cellId: 01975672-124e-7ff5-876e-e75ece273208
          cellLabel: Users to remove csv
          config:
            inputType: FILE_UPLOAD
            name: users_to_remove_csv
            outputType: DATA_FRAME
            options: null
            defaultValue:
              id: 01981470-39f1-733f-86e5-d8bf55e242ed
              name: user_emails_to_remove_example (1).csv
              type: FILE
        - cellType: INPUT
          cellId: 01975672-124e-7ff5-876e-e956e6ed50af
          cellLabel: Group id
          config:
            inputType: TEXT_INPUT
            name: group_id
            outputType: STRING
            options: null
            defaultValue: 019755f1-209c-7000-a50d-b8983c28d734
        - cellType: INPUT
          cellId: 01975672-124e-7ff5-876e-f594ba63f024
          cellLabel: edit_group
          config:
            inputType: BUTTON
            name: edit_group
            outputType: BOOLEAN
            options: null
            defaultValue: null
        - cellType: CODE
          cellId: 01975672-1243-7ff5-876d-8c12a9641e26
          cellLabel: null
          config:
            source: |
              user_ids_to_remove = get_user_ids_by_emails(users_to_remove_csv["email"].tolist())

              group_details_edit = {
                  "members": {
                      "remove": {},
                      "add": {}
                  }
              }

              if users_to_add_csv is not None:
                  user_ids_to_add = get_user_ids_by_emails(users_to_add_csv["email"].tolist())
                  group_details_edit["members"]["add"]["users"] = [{"id": u_id} for u_id in user_ids_to_add]

              if users_to_remove_csv is not None:
                  user_ids_to_remove = get_user_ids_by_emails(users_to_remove_csv["email"].tolist())
                  group_details_edit["members"]["remove"]["users"] = [{"id": u_id} for u_id in user_ids_to_remove]

              if edit_group:
                  params = {}
                  edit_group_response = make_request(f"v1/groups/{group_id}", params, "PATCH", body=group_details_edit)
                  print(f'Updated group with id {group_id}.')
        - cellType: MARKDOWN
          cellId: 01975672-1245-7ff5-876e-45a1d59aee1e
          cellLabel: null
          config:
            source: |-
              ### Now delete a group

              NOTE: If you get an error message about like `you are not authorized to perform this action`, it is likely the group id you have provided is not accurate or does not exist. 
        - cellType: INPUT
          cellId: 01975672-124e-7ff5-876e-fb9ec9ab42a1
          cellLabel: group_id_to_delete
          config:
            inputType: TEXT_INPUT
            name: group_id_to_delete
            outputType: STRING
            options: null
            defaultValue: 019755dc-c4a7-766c-be9e-11e516777dea
        - cellType: INPUT
          cellId: 01975672-124e-7ff5-876f-07206bc15514
          cellLabel: delete_group
          config:
            inputType: BUTTON
            name: delete_group
            outputType: BOOLEAN
            options: null
            defaultValue: null
        - cellType: CODE
          cellId: 01975672-1243-7ff5-876d-978755b0d2eb
          cellLabel: null
          config:
            source: |-
              if delete_group:
                  delete_group_response = make_request(f"v1/groups/{group_id_to_delete}", {}, "DELETE")
                  if isinstance(delete_group_response, int):
                      print(f'Failed to delete group with id {group_id_to_delete}.')
                  else:
                      print(f'Deleted group with id {group_id_to_delete}')
        - cellType: MARKDOWN
          cellId: 01975672-1245-7ff5-876e-4ab468608316
          cellLabel: null
          config:
            source: "### Return the list of users who belong to a given group"
        - cellType: INPUT
          cellId: 01975672-124e-7ff5-876f-081a51460baa
          cellLabel: Check group id
          config:
            inputType: TEXT_INPUT
            name: check_group_id
            outputType: STRING
            options: null
            defaultValue: 9ab3a3c5-e35e-46af-bf1f-3e1cca863441
        - cellType: CODE
          cellId: 01975672-1243-7ff5-876d-9a4652d58674
          cellLabel: null
          config:
            source: |-
              method = 'GET'
              url = 'v1/users'
              params = {
                  'limit': 100
                  , 'groupId': check_group_id
              }

              check_users_in_group = helper_w_pagination(url = url, params = params, method = method)
              check_users_in_group_df = make_df(check_users_in_group)
              check_users_in_group_df
appLayout:
  visibleMetadataFields:
    - NAME
    - DESCRIPTION
    - AUTHOR
    - LAST_EDITED
    - LAST_RUN
    - CATEGORIES
    - STATUS
    - TABLE_OF_CONTENTS
  fullWidth: false
  tabs:
    - name: Tab 1
      rows:
        - columns:
            - start: 0
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-1245-7ff5-876e-2f73a99af8b0
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-1255-7ff5-876f-340de6245af3
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-1257-7ff5-876f-955e825f5e82
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-1245-7ff5-876e-36809d2dca51
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-1257-7ff5-876f-9f2cf6631ccc
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-1245-7ff5-876e-38ed1b5c9800
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 40
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-124e-7ff5-876e-c02a6e643058
                  sharedFilterId: null
                  height: null
                  showLabel: true
            - start: 40
              end: 80
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-124e-7ff5-876e-cfa568efb7c3
                  sharedFilterId: null
                  height: null
                  showLabel: true
            - start: 80
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-124e-7ff5-876e-d23d409d0fea
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 30
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-124e-7ff5-876e-d894ac7060de
                  sharedFilterId: null
                  height: null
                  showLabel: true
            - start: 30
              end: 60
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-124e-7ff5-876e-e75ece273208
                  sharedFilterId: null
                  height: null
                  showLabel: true
            - start: 60
              end: 90
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-124e-7ff5-876e-e956e6ed50af
                  sharedFilterId: null
                  height: null
                  showLabel: true
            - start: 90
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-124e-7ff5-876e-f594ba63f024
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-1245-7ff5-876e-45a1d59aee1e
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 30
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-124e-7ff5-876e-fb9ec9ab42a1
                  sharedFilterId: null
                  height: null
                  showLabel: true
            - start: 30
              end: 60
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-124e-7ff5-876f-07206bc15514
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-1245-7ff5-876e-4ab468608316
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 30
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-124e-7ff5-876f-081a51460baa
                  sharedFilterId: null
                  height: null
                  showLabel: true
        - columns:
            - start: 0
              end: 120
              elements:
                - showSource: false
                  hideOutput: false
                  type: CELL
                  cellId: 01975672-1243-7ff5-876d-9a4652d58674
                  sharedFilterId: null
                  height: null
                  showLabel: true
sharedFilters: []
