Het SURFdrive dashboard bevat een API, waarmee dezelfde verzoeken kunnen worden gedaan als via de webomgeving. 
Voor de API gelden dezelfde rechten voor je account als voor de webomgeving. 

Op deze pagina beschrijven we een aantal voorbeelden, alleen gebaseerd op CURL.
Met wat programmeerwerk, bijvoorbeeld met de programmeertaal Python, kan dit API endpoint heel eenvoudig worden gebruikt.
 
Alle mogelijke calls zijn te vinden op de speciale API documentatie pagina, waar je ook een aantal voorbeeld requests vindt.
De API documentatiepagina kan worden gevonden op https://surfdrive.surf.nl/dashboard/api/documentation


Experimenteren

Wil je gebruik gaan maken van de SURFdrive Dashboard API. Probeer dan eerst je scripts tegen de SURFdrive Acceptatie omgeving, zodat je geen onverwachte dingen kunt krijgen.
De SURFdrive acceptatie omgeving is te bereiken via ; https://surfdrive-acc.surf.nl


Om toegang te krijgen tot de Dashboard API moet je een access token aanmaken via je accountgegevens.

1. Klik op je gebruikersnaam in de rechterbovenhoek om direct toegang te krijgen tot je accountgegevens.


2. Via je accountgegevens kun je de API inschakelen.


3. Sla je API token op. Het wordt eenmalig getoond.

Met je API access token kun je je accountgegevens bekijken.

curl -X 'GET' 'https://surfdrive.surf.nl/dashboard/api/me' \
  -H 'accept: application/json' \
  -H 'Accept-Language: en' \
  -H 'Authorization: Bearer <your-access-token>'

Voorbeeld reactie;

{
  "data": {
    "id": 2075,
    "username": "dashboardadmin1",
    "name": "dashboardadmin1",
    "email": "None",
    "backend": {
      "value": "local",
      "trans": "Local"
    },
    "mfa": {
      "value": "disabled",
      "trans": "Disabled"
    },
    "description": null,
    "last_login": null,
    "status": {
      "value": "active",
      "trans": "Active"
    },
    "inviter": false,
    "max_groups": null,
    "create_date": "2022-12-06 15:01:02",
    "change_date": "2023-02-06 13:40:37",
    "is_application_account": true,
    "is_surf_admin": false,
    "is_portal_admin": true,
    "is_contract_admin": false,
    "application_account": {
      "id": 790,
      "username": "dashboardadmin1",
      "role": {
        "value": "portal_admin",
        "trans": "Portal admin"
      },
      "is_surf_admin": false,
      "is_portal_admin": true
    },
    "groups": [
      {
        "id": 2294,
        "username": "project_x",
        "name": "Project-X",
        "email": "None",
        "backend": {
          "value": "local",
          "trans": "Local"
        },
        "mfa": null,
        "description": "This is test",
        "last_login": null,
        "status": {
          "value": "active",
          "trans": "Active"
        },
        "inviter": false,
        "max_groups": null,
        "create_date": "2023-01-30 23:17:39",
        "change_date": "2023-02-06 13:40:37",
        "groups_membership": {
          "id": 55865204,
          "shared_from": 2294,
          "shared_with": 2075,
          "role": {
            "value": "member",
            "trans": "Member"
          },
          "is_projectfolder_owner": false,
          "is_member": true
        }
      }
    ],
    "contracts": []
  },
  "auth": {
    "can_store_account": true,
    "can_store_contract": true,
    "can_store_any_functional_account": true
  },
  "message": "Successfully retrieved user."
}


Ophalen van alle account-, configuratie- en gebruiksinformatie.

curl -X 'GET' 'https://surfdrive.surf.nl/dashboard/api/account' \
  -H 'accept: application/json' \
  -H 'Accept-Language: en' \
  -H 'Authorization: Bearer <your-access-token>'

Voorbeeld reactie;

{
  "data": [
    {
      "id": 2339,
      "username": "JfDa1eozv7ZvPpG4Y73XDiEHQ982FEnYMYTDOjKY",
      "name": "John Doe",
      "email": "john@doe.nl",
      "backend": null,
      "mfa": null,
      "description": null,
      "last_login": null,
      "status": {
        "value": "new",
        "trans": "New"
      },
      "inviter": false,
      "max_groups": null,
      "create_date": "2023-02-16 09:28:47",
      "change_date": null,
      "contract_id": "KlantX"
    },
    {
      "id": 2168,
      "username": "pietje@puk.nl",
      "name": "Pietje Puk",
      "email": "pietje@puk.nl",
      "backend": {
        "value": "institutional",
        "trans": "Institutional"
      },
      "mfa": null,
      "description": "wijzig meerdere velden tegelijk",
      "last_login": null,
      "status": {
        "value": "active",
        "trans": "Active"
      },
      "inviter": false,
      "max_groups": null,
      "create_date": "2022-12-16 09:24:55",
      "change_date": "2023-02-06 13:40:37",
      "contract_id": "default",
      "end_date": "2020-03-28"
    },
    ..
    ..
  ],
  "order_directions": [
    {
      "value": "asc"
    },
    {
      "value": "desc"
    }
  ],
  "message": "Accounts retrieved."
}

De accountstatus van een specifieke account bijwerken.

  • userid: Vervang userid door de uniq numerieke userid van de gebruikersaccount. Voorbeeld: 2168
  • status: Vervang status door de bedoelde status. Dit kan zijn;  active, inactive, remove or force_remove


curl -X 'PUT' 'https://surfdrive.surf.nl/dashboard/api/account/<userid>/status/<status>' \
  -H 'accept: application/json' \
  -H 'Accept-Language: en' \
  -H 'Authorization: Bearer <your-access-token>'

Voorbeeld reactie;

{
  "message": "Account blocked."
}

Ophalen van een specifieke account, inclusief configuratie- en gebruiksinformatie.

curl -X 'GET' 'https://<environment_url>/dashboard/api/account/2168' \
  -H 'accept: application/json' \
  -H 'Accept-Language: en' \
  -H 'Authorization: Bearer <your-access-token>'

Voorbeeld antwoord;

{
  "data": {
    "id": 2168,
    "username": "pietje@puk.nl",
    "name": "Pietje Puk",
    "email": "pietje@puk.nl",
    "backend": {
      "value": "institutional",
      "trans": "Institutional"
    },
    "mfa": null,
    "description": "wijzig meerdere velden tegelijk",
    "last_login": null,
    "status": {
      "value": "active",
      "trans": "Active"
    },
    "invited_by": {
      "id": 628,
      "username": "johnd",
      "name": "John Doe",
      "email": "John.Doe@surf.nl",
      "backend": {
        "value": "local",
        "trans": "Local"
      },
      "mfa": {
        "value": "disabled",
        "trans": "Disabled"
      },
      "description": null,
      "last_login": null,
      "status": {
        "value": "active",
        "trans": "Active"
      },
      "inviter": false,
      "max_groups": null,
      "create_date": "2020-01-13 11:54:01",
      "change_date": "2023-02-06 13:40:37"
    },
    "inviter": false,
    "max_groups": null,
    "create_date": "2022-12-16 09:24:55",
    "change_date": "2023-02-06 13:40:37",
    "is_application_account": null,
    "is_surf_admin": null,
    "is_portal_admin": null,
    "application_account": null,
    "storage": {
      "id": 2138,
      "type": {
        "value": "personal",
        "trans": "Personal"
      },
      "usage": {
        "value": 0,
        "trans": "0.00 GB"
      },
      "quotum": {
        "value": 0,
        "trans": "0.00 GB"
      },
      "status": {
        "value": "active",
        "trans": "Active"
      },
      "last_update": null,
      "contract": {
        "id": 6,
        "contract_id": "default",
        "owner": "Jane Doe",
        "owner_email": "Jane@Doe.nl",
        "contact": null,
        "description": "Default contract",
        "quotum": {
          "value": 30000,
          "trans": "30 TB"
        },
        "start_date": "2019-03-14",
        "end_date": "2020-03-28",
        "status": {
          "value": "active",
          "trans": "Active"
        },
        "internal": 0,
        "ocgroup": null,
        "remove_period": {
          "value": 90
        },
        "inviter": true,
        "strictaudit": false,
        "invitation_whitelist": null,
        "quotum_option": [
          {
            "value": 1,
            "trans": "500 GB",
            "quotum": 500
          },
          {
            "value": 2,
            "trans": "1000 GB",
            "quotum": 1000
          },
          {
            "value": 16,
            "trans": "10 GB",
            "quotum": 10
          },
          {
            "value": 32,
            "trans": "25 GB",
            "quotum": 25
          },
          {
            "value": 64,
            "trans": "50 GB",
            "quotum": 50
          },
          {
            "value": 128,
            "trans": "Custom input",
            "quotum": null
          },
          {
            "value": 256,
            "trans": "100 GB",
            "quotum": 100
          }
        ],
        "max_groups": 0,
        "accounts": [],
        "storages_sum_usage": {
          "value": 320.238141642,
          "trans": "320.24 GB"
        },
        "storages_sum_quotum": {
          "value": 28399,
          "trans": "28.4 TB"
        }
      }
    },
    "services": [
      {
        "id": 6,
        "service": "Jupyter Hub",
        "description": "",
        "ocgroup": "jupyter"
      },
      {
        "id": 9,
        "service": "Dashboard",
        "description": "Research Drive Dashboard",
        "ocgroup": "dashboard"
      },
      {
        "id": 12,
        "service": "OnlyOffice",
        "description": "OnlyOffice Collaborative Editing",
        "ocgroup": "onlyoffice"
      },
    ],
    "groups": [
      {
        "id": 2309,
        "username": "pietjespuk_atvnistz",
        "name": "PietjesPuk",
        "email": "None",
        "backend": {
          "value": "local",
          "trans": "Local"
        },
        "mfa": null,
        "description": "Test Example",
        "last_login": null,
        "status": {
          "value": "active",
          "trans": "Active"
        },
        "inviter": false,
        "max_groups": null,
        "create_date": "2023-02-03 08:39:38",
        "change_date": "2023-02-06 13:40:37",
        "groups_membership": {
          "id": 55865228,
          "shared_from": 2309,
          "shared_with": 2168,
          "role": {
            "value": "projectfolder_owner",
            "trans": "Projectfolder owner"
          },
          "is_projectfolder_owner": true,
          "is_member": false
        }
      },
      {
        "id": 2312,
        "username": "test_uzgqfkiz",
        "name": "Test",
        "email": "None",
        "backend": {
          "value": "local",
          "trans": "Local"
        },
        "mfa": null,
        "description": null,
        "last_login": null,
        "status": {
          "value": "active",
          "trans": "Active"
        },
        "inviter": false,
        "max_groups": null,
        "create_date": "2023-02-03 10:50:19",
        "change_date": "2023-02-06 13:40:37",
        "groups_membership": {
          "id": 55865231,
          "shared_from": 2312,
          "shared_with": 2168,
          "role": {
            "value": "projectfolder_owner",
            "trans": "Projectfolder owner"
          },
          "is_projectfolder_owner": true,
          "is_member": false
        }
      }
    ]
  },
  "auth": {
    "is_inviter": false,
    "is_contract_admin": false,
    "can_update": true,
    "can_update_status": [
      {
        "value": "inactive",
        "trans": "Inactive"
      },
      {
        "value": "remove",
        "trans": "Remove"
      }
    ],
    "can_attach_contract": true,
    "can_attach_any_service": true,
    "can_store_personal_access_token": false,
    "can_destroy_personal_access_token": false,
    "can_update_setting": true,
    "can_store_invite": false,
    "can_destroy_mfa": false,
    "can_update_password": false
  },
  "message": "Account retrieved."
}


De API is beperkt tot een maximum van 1000 records in één keer. Dit is gedaan omdat het laden van de vele relaties enige tijd kost.
Het is sneller om over meerdere lijsten met een kleiner aantal records te lussen.


Een snel voorbeeld wat zou kunnen;

for i in `seq 1 $(curl -s -X GET '<environment_url>/dashboard/api/account?per_page=250' \
                  -H 'accept: application/json' -H 'Accept-Language: en' \
                  -H 'Authorization: <your-access-token>' | jq .meta.last_page)`
do
  echo "Loop over page: ${i}"
  curl -X GET "https://surfdrive.surf.nl/dashboard/api/account?page=${i}&per_page=250" \
    -H "accept: application/json" \
    -H "Accept-Language: en" \
    -H "Authorization: <your-access-token>" | jq .data  
done


Het bovenstaande is gedaan op een Unix machine. In dit voorbeeld maken we gebruik van de JSON processor JQ (https://jqlang.github.io/jq/)
Uitleggen wat hier gebeurt;

  1. We doen een eerste verzoek naar het API endpoint, waar we het totale aantal pagina's ophalen. 

    curl -s -X GET '<environment_url>/dashboard/api/account?per_page=250' \
    -H 'accept: application/json' -H 'Accept-Language: en' \
    -H 'Authorization: <your-access-token>' | jq .meta.last_page
  2. We loop-en over het resultaat van de totaal aantal pagina's;

    for i in `seq 1 $(curl -s -X GET '<environment_url>/dashboard/api/account?per_page=250' \
                      -H 'accept: application/json' -H 'Accept-Language: en' \
                      -H 'Authorization: <your-access-token>' | jq .meta.last_page)`
    do
      echo "Loop over page: ${i}" 
    done
  3. Verzamel de gegevensrecords van elke pagina

    for i in `seq 1 $(curl -s -X GET '<environment_url>/dashboard/api/account?per_page=250' \
                      -H 'accept: application/json' -H 'Accept-Language: en' \
                      -H 'Authorization: <your-access-token>' | jq .meta.last_page)`
    do
      echo "Loop over page: ${i}"
      curl -X GET "https://<environment_url>/dashboard/api/account?page=${i}&per_page=250" \
        -H "accept: application/json" \
        -H "Accept-Language: en" \
        -H "Authorization: <your-access-token>" | jq .data  >> /tmp/api_results.json 
    done

Dit is slechts een klein voorbeeld met CURL. Met talen als Python kan dit vrij eenvoudig worden gedaan.


Dit is een voorbeeld om met gebruik van de programmeertaal Python een account van status te kunnen wisselen.

Dit is een in 5-minuten in elkaar gezet script, gebruik dit niet in productie omdat fout afhandeling er niet in zit!


Een snel voorbeeld ;

#!/usr/bin/env python
import os
import argparse
import requests
import json

###
# Variables
###

env_url = "surfdrive-acc.surf.nl"
api_token = "" # Your AccessToken Here

###
# Argument Parser from command-line
###
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--debug", action="count", default=0, help="Enable debug output")
parser.add_argument("--active", action="count", default=0, help="Activate user")
parser.add_argument("--remove", action="count", default=0, help="Remove user")
parser.add_argument("--disable", action="count", default=0, help="Disable user")
parser.add_argument("-u", "--user", type=str, required=True, help="Username of user to lookup")
args = parser.parse_args()

# Set input in readable string
debug = args.debug
input_user = args.user
activate_account = args.active
remove_account = args.remove
disable_account = args.disable

###
# Lookup where an user lives based on emailaddress or username
###
def get_user_by_username(user):
    try:
        if debug == 1:
            print(f"DEBUG - try to lookup user: {user}")

        url = f"https://{env_url}/dashboard/api/account?search={user}"
        headers = {
            'Accept': 'application/json',
            'Authorization': 'Bearer ' +str(api_token ),
        }
        response = requests.get(url, headers=headers)
        response_code = response.raise_for_status()

        if debug == 1:
            print("DEBUG - Status Code", response.status_code)
            print("DEBUG - Response ", response.text)

        # load the json to a string
        api_json = json.dumps(response.json())
        api_resp = json.loads(api_json)

        return(api_resp['data'])
    except requests.exceptions.HTTPError as err:
        raise SystemExit(err)

def set_user_status_by_id(userid,status):
    try:
        if debug == 1:
            print(f"DEBUG - try to set user {userid} to status {status}")

        url = f"https://{env_url}/dashboard/api/account/{userid}/status/{status}"
        headers = {
            'Accept': 'application/json',
            'Authorization': 'Bearer ' +str(api_token ),
        }
        response = requests.put(url, headers=headers)
        response_code = response.raise_for_status()

        if debug == 1:
            print("DEBUG - Status Code", response.status_code)
            print("DEBUG - Response ", response.text)

        if not response.status_code in [100, 200, 201]:
            print(f"Request for {userid} was unsuccesful.")
            raise

        return(response.text)
    except requests.exceptions.HTTPError as err:
        raise SystemExit(err)

###
# Main
###
def main():
    account = get_user_by_username(input_user)
    if debug == 1:
        print(f"Account details: {account}")

    if len(account) > 1:
        print(f"Got more then 1 result.")
        exit()

    try:
        account_id = account[0]['id']
        print(f"Handle account {input_user} with uniq account id: {account_id}")
        if activate_account == 1:
            status = 'active'
            set_user_status_by_id(account_id,status)
        elif disable_account == 1:
            status = 'inactive'
            set_user_status_by_id(account_id,status)
        elif remove_account == 1:
            status = 'remove'
            set_user_status_by_id(account_id,status)

    except Exception as e:
        print(f"Error during account handling. Error was {e}")

if __name__ == '__main__':
    main()

Dit is een in 5-minuten in elkaar gezet script, gebruik dit niet in productie omdat fout afhandeling er niet in zit!



  • No labels