Я работаю над сценарием Python для удаления прямых назначений пользователей в Azure DevOps на основе их адресов электронной почты из CSV-файла. Сценарий использует API Azure DevOps Graph для извлечения пользователей и сопоставления их mailAddress или PrincipalName с электронными письмами, указанными в CSV.
Проблема:
Когда я пытаюсь получить пользователей с помощью Конечная точка API https://vssps.dev.azure.com/{organizati ... -preview.1, я столкнулся с этой ошибкой:
ERROR:__main__:Error fetching users: Expecting value: line 3 column 1 (char 4)
The raw response indicates an empty or malformed response from the API.
Несмотря на то, что почтовый адрес совпадает (с нормализованным сравнением без учета регистра), я всегда вижу:
WARNING:__main__:User not found in Azure DevOps: john.doe@example.com. Check casing and presence in Azure DevOps.
Примечание. Адрес электронной почты john.doe@example.com существует в Azure DevOps как John.Doe@example.com.
Что я сделал Пробовал:
Нормализованные электронные письма: CSV-файл и полученный адрес электронной почты были преобразованы в нижний регистр для сравнения.
Откат к PrincipalName: использовалось PrincipalName в качестве вторичного идентификатора, если mailAddress был указан. не найден.
Журналирование: регистрируются все выбранные пользователи и их атрибуты для отладки:
logger.debug(f"Fetched users: {[user.get('mailAddress') for user in users]}")
The log shows no users being fetched (Fetched 0 users from Azure DevOps).
Проверенные разрешения API:
Токен личного доступа (PAT) имеет области «График» (чтение) и «Управление правами пользователей».
PAT работает для других вызовов API в Azure DevOps.
Особенности скрипта:
Вот функция для получения пользователей:
def fetch_all_users():
users = []
continuation_token = None
while True:
url = f"{BASE_URL}/graph/users?api-version=7.1-preview.1"
if continuation_token:
url += f"&continuationToken={continuation_token}"
try:
response = requests.get(url, headers=HEADERS, timeout=30)
logger.debug(f"Raw response: {response.status_code}, Content: {response.text}")
response.raise_for_status()
data = response.json()
users.extend(data.get("value", []))
continuation_token = data.get("continuationToken")
if not continuation_token:
break
except Exception as e:
logger.error(f"Error fetching users: {e}")
break
logger.info(f"Fetched {len(users)} users from Azure DevOps.")
return users
Среда:
URL-адрес организации: https://dev.azure.com/myorganization
URL-адрес базового API: https://vssps.dev.azure.com /myorganization/_apis
Версия API: 7.1-preview.1
Версия Python: 3.10
Вопросы:
Почему /graph/users конечная точка возвращает пустой или неверный ответ? Есть ли другая конечная точка, которую мне следует использовать?
Есть ли способ надежно получать пользователей с сопоставлением адресов электронной почты без учета регистра в Azure DevOps?
Может ли это быть связано с настройками уровня организации в Azure DevOps, которые ограничивают доступ к пользовательским данным?
Как я могу отладить это дальше, чтобы гарантировать, что пользователи правильно выбираются и сопоставляются?
Любые рекомендации или предложения будут с благодарностью приняты! Дайте мне знать, если потребуются дополнительные подробности.
Вот весь сценарий:
import os
import csv
import requests
import logging
import time
from requests.exceptions import RequestException
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
ORGANIZATION = "company"
PAT = "your_actual_pat_value"
CSV_FILE_PATH = "...Report.csv"
BASE_URL = "https://vssps.dev.azure.com/company/_apis"
HEADERS = {
"Content-Type": "application/json",
"Authorization": f"Basic {requests.auth._basic_auth_str('', PAT)}"
}
def validate_csv_columns(required_columns, csv_reader):
missing_columns = [col for col in required_columns if col not in csv_reader.fieldnames]
if missing_columns:
raise ValueError(f"CSV is missing required columns: {missing_columns}. Found: {csv_reader.fieldnames}")
def fetch_all_users():
users = []
continuation_token = None
while True:
url = f"{BASE_URL}/graph/users?api-version=7.1-preview.1"
if continuation_token:
url += f"&continuationToken={continuation_token}"
try:
response = requests.get(url, headers=HEADERS, timeout=30)
logger.debug(f"Raw response: {response.status_code}, Content: {response.text}")
response.raise_for_status()
data = response.json()
users.extend(data.get("value", []))
continuation_token = data.get("continuationToken")
if not continuation_token:
break
except RequestException as e:
logger.error(f"Error fetching users: {e}")
break
except ValueError as ve:
logger.error(f"Malformed JSON response: {ve}")
break
logger.info(f"Fetched {len(users)} users from Azure DevOps.")
logger.debug(f"Fetched users: {[user.get('mailAddress') for user in users]}")
return users
def get_user_descriptor_map():
users = fetch_all_users()
user_map = defaultdict(str)
for user in users:
email = user.get("mailAddress", "").strip()
principal_name = user.get("principalName", "").strip()
descriptor = user.get("descriptor")
if email:
user_map[email.lower()] = descriptor
if principal_name and principal_name.lower() not in user_map:
user_map[principal_name.lower()] = descriptor
return user_map
def remove_direct_assignment(user_descriptor):
url = f"{BASE_URL}/graph/memberships/{user_descriptor}?api-version=7.1-preview.1"
try:
response = requests.delete(url, headers=HEADERS)
response.raise_for_status()
if response.status_code == 204:
logger.info(f"Successfully removed direct assignment for user: {user_descriptor}")
except RequestException as e:
logger.error(f"Error removing direct assignment for {user_descriptor}: {e}")
def process_users_in_parallel(user_descriptors):
with ThreadPoolExecutor(max_workers=10) as executor:
executor.map(remove_direct_assignment, user_descriptors)
def process_csv():
try:
user_map = get_user_descriptor_map()
with open(CSV_FILE_PATH, mode='r') as file:
csv_reader = csv.DictReader(file)
validate_csv_columns(["UserEmail"], csv_reader)
user_descriptors = []
for row in csv_reader:
email = row.get("UserEmail", "").strip().lower()
if not email:
logger.warning("Skipping row with missing UserEmail field")
continue
logger.info(f"Processing user: {email}")
user_descriptor = user_map.get(email)
if user_descriptor:
user_descriptors.append(user_descriptor)
else:
logger.warning(f"User not found in Azure DevOps: {email}. Check casing and presence in Azure DevOps.")
process_users_in_parallel(user_descriptors)
except FileNotFoundError:
logger.error(f"CSV file not found: {CSV_FILE_PATH}")
except ValueError as ve:
logger.error(f"CSV validation error: {ve}")
except Exception as e:
logger.error(f"Unexpected error: {e}")
if __name__ == "__main__":
try:
logger.info("Starting the process to remove direct assignments.")
process_csv()
logger.info("Script completed successfully.")
import sys
sys.exit(0)
except Exception as e:
logger.error(f"Script terminated with errors: {e}")
sys.exit(1)
Подробнее здесь: https://stackoverflow.com/questions/793 ... matching-e
Azure DevOps API: ошибка «Ожидаемая ценность» и пользователи не найдены, несмотря на совпадение электронных писем ⇐ Python
Программы на Python
1737467398
Anonymous
Я работаю над сценарием Python для удаления прямых назначений пользователей в Azure DevOps на основе их адресов электронной почты из CSV-файла. Сценарий использует API Azure DevOps Graph для извлечения пользователей и сопоставления их mailAddress или PrincipalName с электронными письмами, указанными в CSV.
Проблема:
Когда я пытаюсь получить пользователей с помощью Конечная точка API https://vssps.dev.azure.com/{organization}/_apis/graph/users?api-version=7.1-preview.1, я столкнулся с этой ошибкой:
ERROR:__main__:Error fetching users: Expecting value: line 3 column 1 (char 4)
The raw response indicates an empty or malformed response from the API.
Несмотря на то, что почтовый адрес совпадает (с нормализованным сравнением без учета регистра), я всегда вижу:
WARNING:__main__:User not found in Azure DevOps: john.doe@example.com. Check casing and presence in Azure DevOps.
Примечание. Адрес электронной почты john.doe@example.com существует в Azure DevOps как John.Doe@example.com.
Что я сделал Пробовал:
Нормализованные электронные письма: CSV-файл и полученный адрес электронной почты были преобразованы в нижний регистр для сравнения.
Откат к PrincipalName: использовалось PrincipalName в качестве вторичного идентификатора, если mailAddress был указан. не найден.
Журналирование: регистрируются все выбранные пользователи и их атрибуты для отладки:
logger.debug(f"Fetched users: {[user.get('mailAddress') for user in users]}")
The log shows no users being fetched (Fetched 0 users from Azure DevOps).
Проверенные разрешения API:
Токен личного доступа (PAT) имеет области «График» (чтение) и «Управление правами пользователей».
PAT работает для других вызовов API в Azure DevOps.
Особенности скрипта:
Вот функция для получения пользователей:
def fetch_all_users():
users = []
continuation_token = None
while True:
url = f"{BASE_URL}/graph/users?api-version=7.1-preview.1"
if continuation_token:
url += f"&continuationToken={continuation_token}"
try:
response = requests.get(url, headers=HEADERS, timeout=30)
logger.debug(f"Raw response: {response.status_code}, Content: {response.text}")
response.raise_for_status()
data = response.json()
users.extend(data.get("value", []))
continuation_token = data.get("continuationToken")
if not continuation_token:
break
except Exception as e:
logger.error(f"Error fetching users: {e}")
break
logger.info(f"Fetched {len(users)} users from Azure DevOps.")
return users
Среда:
URL-адрес организации: https://dev.azure.com/myorganization
URL-адрес базового API: https://vssps.dev.azure.com /myorganization/_apis
Версия API: 7.1-preview.1
Версия Python: 3.10
Вопросы:
Почему /graph/users конечная точка возвращает пустой или неверный ответ? Есть ли другая конечная точка, которую мне следует использовать?
Есть ли способ надежно получать пользователей с сопоставлением адресов электронной почты без учета регистра в Azure DevOps?
Может ли это быть связано с настройками уровня организации в Azure DevOps, которые ограничивают доступ к пользовательским данным?
Как я могу отладить это дальше, чтобы гарантировать, что пользователи правильно выбираются и сопоставляются?
Любые рекомендации или предложения будут с благодарностью приняты! Дайте мне знать, если потребуются дополнительные подробности.
Вот весь сценарий:
import os
import csv
import requests
import logging
import time
from requests.exceptions import RequestException
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
ORGANIZATION = "company"
PAT = "your_actual_pat_value"
CSV_FILE_PATH = "...Report.csv"
BASE_URL = "https://vssps.dev.azure.com/company/_apis"
HEADERS = {
"Content-Type": "application/json",
"Authorization": f"Basic {requests.auth._basic_auth_str('', PAT)}"
}
def validate_csv_columns(required_columns, csv_reader):
missing_columns = [col for col in required_columns if col not in csv_reader.fieldnames]
if missing_columns:
raise ValueError(f"CSV is missing required columns: {missing_columns}. Found: {csv_reader.fieldnames}")
def fetch_all_users():
users = []
continuation_token = None
while True:
url = f"{BASE_URL}/graph/users?api-version=7.1-preview.1"
if continuation_token:
url += f"&continuationToken={continuation_token}"
try:
response = requests.get(url, headers=HEADERS, timeout=30)
logger.debug(f"Raw response: {response.status_code}, Content: {response.text}")
response.raise_for_status()
data = response.json()
users.extend(data.get("value", []))
continuation_token = data.get("continuationToken")
if not continuation_token:
break
except RequestException as e:
logger.error(f"Error fetching users: {e}")
break
except ValueError as ve:
logger.error(f"Malformed JSON response: {ve}")
break
logger.info(f"Fetched {len(users)} users from Azure DevOps.")
logger.debug(f"Fetched users: {[user.get('mailAddress') for user in users]}")
return users
def get_user_descriptor_map():
users = fetch_all_users()
user_map = defaultdict(str)
for user in users:
email = user.get("mailAddress", "").strip()
principal_name = user.get("principalName", "").strip()
descriptor = user.get("descriptor")
if email:
user_map[email.lower()] = descriptor
if principal_name and principal_name.lower() not in user_map:
user_map[principal_name.lower()] = descriptor
return user_map
def remove_direct_assignment(user_descriptor):
url = f"{BASE_URL}/graph/memberships/{user_descriptor}?api-version=7.1-preview.1"
try:
response = requests.delete(url, headers=HEADERS)
response.raise_for_status()
if response.status_code == 204:
logger.info(f"Successfully removed direct assignment for user: {user_descriptor}")
except RequestException as e:
logger.error(f"Error removing direct assignment for {user_descriptor}: {e}")
def process_users_in_parallel(user_descriptors):
with ThreadPoolExecutor(max_workers=10) as executor:
executor.map(remove_direct_assignment, user_descriptors)
def process_csv():
try:
user_map = get_user_descriptor_map()
with open(CSV_FILE_PATH, mode='r') as file:
csv_reader = csv.DictReader(file)
validate_csv_columns(["UserEmail"], csv_reader)
user_descriptors = []
for row in csv_reader:
email = row.get("UserEmail", "").strip().lower()
if not email:
logger.warning("Skipping row with missing UserEmail field")
continue
logger.info(f"Processing user: {email}")
user_descriptor = user_map.get(email)
if user_descriptor:
user_descriptors.append(user_descriptor)
else:
logger.warning(f"User not found in Azure DevOps: {email}. Check casing and presence in Azure DevOps.")
process_users_in_parallel(user_descriptors)
except FileNotFoundError:
logger.error(f"CSV file not found: {CSV_FILE_PATH}")
except ValueError as ve:
logger.error(f"CSV validation error: {ve}")
except Exception as e:
logger.error(f"Unexpected error: {e}")
if __name__ == "__main__":
try:
logger.info("Starting the process to remove direct assignments.")
process_csv()
logger.info("Script completed successfully.")
import sys
sys.exit(0)
except Exception as e:
logger.error(f"Script terminated with errors: {e}")
sys.exit(1)
Подробнее здесь: [url]https://stackoverflow.com/questions/79370764/azure-devops-api-expecting-value-error-and-users-not-found-despite-matching-e[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия