Gestion des Locataires

Créer, lister, récupérer et mettre à jour les locataires sur la plateforme mindzieStudio.

IMPORTANT : Tous les points de terminaison de cette page nécessitent une clé API globale. Les clés API spécifiques aux locataires recevront une erreur 401 Unauthorized.


Lister Tous les Locataires

GET /api/tenant

Récupère une liste paginée de tous les locataires dans le système avec des statistiques résumées.

Paramètres de Requête

Paramètre Type Défaut Description
page entier 1 Numéro de page pour la pagination
pageSize entier 50 Nombre d'éléments par page (max : 100)

Réponse (200 OK)

{
  "tenants": [
    {
      "tenantId": "12345678-1234-1234-1234-123456789012",
      "name": "acme-corp",
      "displayName": "Acme Corporation",
      "description": "Locataire principal pour Acme Corporation",
      "caseCount": 50000,
      "maxUserCount": 100,
      "maxAnalystCount": 20,
      "analystCount": 12,
      "userCount": 45,
      "preRelease": false,
      "isAcademic": false,
      "autoload": true,
      "dateCreated": "2024-01-15T10:30:00Z",
      "isDisabled": false
    }
  ],
  "totalCount": 5,
  "page": 1,
  "pageSize": 50
}

Champs de l'Objet Locataire

Champ Type Description
tenantId GUID Identifiant unique du locataire
name chaîne Nom système unique (utilisé dans les URL)
displayName chaîne Nom affiché lisible par l'humain
description chaîne Description du locataire
caseCount entier Nombre total d'incidents dans tous les ensembles de données
maxUserCount entier Nombre maximal d'utilisateurs autorisés
maxAnalystCount entier Nombre maximal d'analystes autorisés
analystCount entier Nombre actuel d'analystes
userCount entier Nombre actuel d'utilisateurs
preRelease booléen Indique si le locataire possède des fonctionnalités préliminaires
isAcademic booléen Indique si c'est un locataire académique
autoload booléen Indique s'il faut charger automatiquement les projets
dateCreated datetime Date de création du locataire
isDisabled booléen Indique si le locataire est désactivé

Réponses d'Erreur

Non Autorisé (401) :

{
  "error": "Ce point de terminaison nécessite une clé API globale. Les clés API spécifiques aux locataires ne peuvent pas lister tous les locataires.",
  "hint": "Les clés API globales peuvent être créées sur /admin/global-api-keys"
}

Obtenir un Locataire par ID

GET /api/tenant/{tenantId}

Récupère les informations détaillées pour un locataire spécifique par son ID.

Paramètres de Chemin

Paramètre Type Obligatoire Description
tenantId GUID Oui Identifiant unique du locataire

Réponse (200 OK)

{
  "tenantId": "12345678-1234-1234-1234-123456789012",
  "name": "acme-corp",
  "displayName": "Acme Corporation",
  "description": "Locataire principal pour Acme Corporation",
  "isAcademic": false,
  "preRelease": false,
  "maxUserCount": 100,
  "maxAnalystCount": 20,
  "maxCases": 100000,
  "dateCreated": "2024-01-15T10:30:00Z",
  "isDisabled": false
}

Réponses d'Erreur

Non Trouvé (404) :

{
  "error": "Locataire avec l'ID '12345678-1234-1234-1234-123456789012' introuvable"
}

Créer un Locataire

POST /api/tenant

Crée un nouveau locataire dans le système avec toute l'infrastructure nécessaire.

Corps de la Requête

{
  "name": "new-tenant",
  "displayName": "New Tenant Corp",
  "description": "Description du nouveau locataire",
  "maxUsers": 50,
  "maxAnalyst": 10,
  "maxCases": 100000,
  "timeZone": "America/New_York"
}

Champs de la Requête

Champ Type Obligatoire Description
name chaîne Oui Nom système unique (3-63 caractères, alphanumérique en minuscules avec des traits d'union)
displayName chaîne Oui Nom affiché lisible par l'humain
description chaîne Non Description du locataire
maxUsers entier Oui Nombre maximal d'utilisateurs
maxAnalyst entier Oui Nombre maximal d'analystes
maxCases entier Oui Nombre maximal d'incidents
timeZone chaîne Non Fuseau horaire du locataire

Exigences pour le Nom du Locataire

  • 3 à 63 caractères
  • Alphanumérique en minuscules avec uniquement des traits d'union
  • Pas d'espaces ni de caractères spéciaux
  • Doit être unique parmi tous les locataires

Réponse (201 Créé)

{
  "tenantId": "aabbccdd-1234-1234-1234-123456789012",
  "name": "new-tenant",
  "displayName": "New Tenant Corp",
  "message": "Locataire 'New Tenant Corp' créé avec succès",
  "storageContainerCreated": true
}

Réponses d'Erreur

Conflit (409) :

{
  "error": "Un locataire avec le nom 'new-tenant' existe déjà"
}

Limite de Licence (429) :

{
  "error": "Nombre maximal de locataires atteint. Votre licence autorise 10 locataires.",
  "hint": "Mettez à niveau votre licence pour créer plus de locataires"
}

Erreur de Validation (400) :

{
  "error": "Échec de la validation",
  "validationErrors": [
    "Le nom doit contenir entre 3 et 63 caractères",
    "Le nom ne peut contenir que des lettres minuscules, des chiffres et des traits d'union"
  ]
}

Mettre à Jour un Locataire

PUT /api/tenant

Met à jour les propriétés d'un locataire existant. Seuls les champs fournis seront mis à jour ; les valeurs nulles sont ignorées.

Corps de la Requête

{
  "tenantId": "12345678-1234-1234-1234-123456789012",
  "displayName": "Acme Corporation Updated",
  "description": "Description mise à jour",
  "maxUsers": 100,
  "maxAnalyst": 25,
  "maxCases": 200000,
  "timeZone": "America/New_York",
  "isAcademic": false,
  "preRelease": true,
  "isDisabled": false
}

Champs de la Requête

Champ Type Obligatoire Description
tenantId GUID Oui Identifiant du locataire à modifier
displayName chaîne Non Nouveau nom affiché (null = pas de changement)
description chaîne Non Nouvelle description (null = pas de changement, "" = effacer)
maxUsers entier Non Nombre maximal d'utilisateurs (null = pas de changement)
maxAnalyst entier Non Nombre maximal d'analystes (null = pas de changement)
maxCases entier Non Nombre maximal d'incidents (null = pas de changement, -1 = illimité)
timeZone chaîne Non ID du fuseau horaire (null = pas de changement)
isAcademic booléen Non Indicateur académique (null = pas de changement)
preRelease booléen Non Fonctionnalités préliminaires (null = pas de changement)
isDisabled booléen Non Désactiver le locataire (null = pas de changement)

Note : Le name du locataire ne peut pas être modifié après la création.

Réponse (200 OK)

{
  "tenantId": "12345678-1234-1234-1234-123456789012",
  "name": "acme-corp",
  "displayName": "Acme Corporation Updated",
  "message": "Locataire 'acme-corp' mis à jour avec succès",
  "isDisabled": false
}

Réponses d'Erreur

Non Trouvé (404) :

{
  "error": "Locataire avec l'ID '12345678-1234-1234-1234-123456789012' introuvable"
}

Erreur de Validation (400) :

{
  "error": "Échec de la validation",
  "validationErrors": ["Le nom affiché ne peut pas dépasser 255 caractères"]
}

Exemples d'Implémentation

cURL

# Lister tous les locataires
curl -X GET "https://your-mindzie-instance.com/api/tenant?page=1&pageSize=50" \
  -H "Authorization: Bearer YOUR_GLOBAL_API_KEY"

# Obtenir un locataire spécifique par ID
curl -X GET "https://your-mindzie-instance.com/api/tenant/12345678-1234-1234-1234-123456789012" \
  -H "Authorization: Bearer YOUR_GLOBAL_API_KEY"

# Créer un locataire
curl -X POST "https://your-mindzie-instance.com/api/tenant" \
  -H "Authorization: Bearer YOUR_GLOBAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "new-tenant",
    "displayName": "New Tenant Corp",
    "description": "Test tenant",
    "maxUsers": 50,
    "maxAnalyst": 10,
    "maxCases": 100000
  }'

# Mettre à jour un locataire
curl -X PUT "https://your-mindzie-instance.com/api/tenant" \
  -H "Authorization: Bearer YOUR_GLOBAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "12345678-1234-1234-1234-123456789012",
    "displayName": "New Tenant Corp Updated",
    "maxUsers": 100,
    "isDisabled": false
  }'

Python

import requests

BASE_URL = 'https://your-mindzie-instance.com'

class TenantManager:
    def __init__(self, global_api_key):
        """Initialiser avec une clé API GLOBALE (non spécifique au locataire)."""
        self.headers = {
            'Authorization': f'Bearer {global_api_key}',
            'Content-Type': 'application/json'
        }

    def list_tenants(self, page=1, page_size=50):
        """Lister tous les locataires dans le système."""
        url = f'{BASE_URL}/api/tenant'
        params = {'page': page, 'pageSize': page_size}
        response = requests.get(url, headers=self.headers, params=params)
        response.raise_for_status()
        return response.json()

    def get_tenant(self, tenant_id):
        """Obtenir un locataire spécifique par ID."""
        url = f'{BASE_URL}/api/tenant/{tenant_id}'
        response = requests.get(url, headers=self.headers)
        response.raise_for_status()
        return response.json()

    def create_tenant(self, name, display_name, description='',
                      max_users=50, max_analyst=10, max_cases=100000, timezone=None):
        """Créer un nouveau locataire."""
        url = f'{BASE_URL}/api/tenant'
        payload = {
            'name': name,
            'displayName': display_name,
            'description': description,
            'maxUsers': max_users,
            'maxAnalyst': max_analyst,
            'maxCases': max_cases
        }
        if timezone:
            payload['timeZone'] = timezone

        response = requests.post(url, json=payload, headers=self.headers)
        response.raise_for_status()
        return response.json()

    def update_tenant(self, tenant_id, display_name=None, description=None,
                      max_users=None, max_analyst=None, is_disabled=None):
        """Mettre à jour un locataire existant."""
        url = f'{BASE_URL}/api/tenant'
        payload = {'tenantId': tenant_id}
        if display_name is not None:
            payload['displayName'] = display_name
        if description is not None:
            payload['description'] = description
        if max_users is not None:
            payload['maxUsers'] = max_users
        if max_analyst is not None:
            payload['maxAnalyst'] = max_analyst
        if is_disabled is not None:
            payload['isDisabled'] = is_disabled

        response = requests.put(url, json=payload, headers=self.headers)
        response.raise_for_status()
        return response.json()

# Utilisation
manager = TenantManager('your-global-api-key')

# Lister tous les locataires
result = manager.list_tenants()
print(f"Nombre total de locataires : {result['totalCount']}")
for tenant in result['tenants']:
    print(f"- {tenant['displayName']} ({tenant['name']})")
    print(f"  Utilisateurs : {tenant['userCount']}/{tenant['maxUserCount']}")

# Créer un nouveau locataire
new_tenant = manager.create_tenant(
    name='test-tenant',
    display_name='Test Tenant',
    description='Créé via API',
    max_users=25,
    max_analyst=5,
    max_cases=50000
)
print(f"Locataire créé : {new_tenant['tenantId']}")

# Mettre à jour les limites du locataire
manager.update_tenant(
    tenant_id=new_tenant['tenantId'],
    max_users=50,
    max_analyst=10
)
print("Limites du locataire mises à jour")

JavaScript

const BASE_URL = 'https://your-mindzie-instance.com';

class TenantManager {
  constructor(globalApiKey) {
    this.headers = {
      'Authorization': `Bearer ${globalApiKey}`,
      'Content-Type': 'application/json'
    };
  }

  async listTenants(page = 1, pageSize = 50) {
    const url = `${BASE_URL}/api/tenant?page=${page}&pageSize=${pageSize}`;
    const response = await fetch(url, { headers: this.headers });
    if (!response.ok) throw new Error(`Échec : ${response.status}`);
    return await response.json();
  }

  async getTenant(tenantId) {
    const url = `${BASE_URL}/api/tenant/${tenantId}`;
    const response = await fetch(url, { headers: this.headers });
    if (!response.ok) throw new Error(`Échec : ${response.status}`);
    return await response.json();
  }

  async createTenant(config) {
    const url = `${BASE_URL}/api/tenant`;
    const response = await fetch(url, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify(config)
    });
    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.error || `Échec : ${response.status}`);
    }
    return await response.json();
  }

  async updateTenant(tenantId, updates) {
    const url = `${BASE_URL}/api/tenant`;
    const response = await fetch(url, {
      method: 'PUT',
      headers: this.headers,
      body: JSON.stringify({ tenantId, ...updates })
    });
    if (!response.ok) throw new Error(`Échec : ${response.status}`);
    return await response.json();
  }
}

// Utilisation
const manager = new TenantManager('your-global-api-key');

// Lister les locataires
const tenants = await manager.listTenants();
console.log(`Nombre de locataires trouvés : ${tenants.totalCount}`);

// Créer un locataire
const newTenant = await manager.createTenant({
  name: 'new-tenant',
  displayName: 'Nouveau Locataire',
  maxUsers: 50,
  maxAnalyst: 10,
  maxCases: 100000
});
console.log(`Créé : ${newTenant.tenantId}`);

// Mettre à jour un locataire
await manager.updateTenant(newTenant.tenantId, {
  displayName: 'Nom du Locataire Mis à Jour',
  maxUsers: 100
});

Bonnes Pratiques

  1. Clés API Globales : Utilisez uniquement des clés API globales pour la gestion des locataires - elles ont des privilèges importants au niveau système
  2. Conformité à la Licence : Surveillez le nombre de locataires par rapport aux limites de votre licence avant de créer de nouveaux locataires
  3. Planification de la Capacité : Définissez des limites adéquates pour les utilisateurs et les analystes en fonction de l'usage prévu
  4. Conventions de Nommage : Utilisez une nomenclature cohérente, en minuscules et avec des traits d'union pour les noms de locataires