Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 38 additions & 53 deletions superannotate/db/project_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
get_project_default_image_quality_in_editor, _get_available_image_counts,
get_project_metadata
)
from .teams import get_team_metadata
from ..mixp.decorators import Trackable
from .utils import _get_upload_auth_token, _get_boto_session_by_credentials, upload_image_array_to_s3, get_image_array_to_upload, __create_image, __copy_images, __move_images, get_project_folder_string

Expand Down Expand Up @@ -564,25 +565,28 @@ def assign_images(project, image_names, user):
:param user: user email
:type user: str
"""

# TODO:
# logger.info("Assign %s images to user %s", len(image_names), user)
# if len(image_names) == 0:
# return
logger.info("Assign %s images to user %s", len(image_names), user)
if len(image_names) == 0:
return

project, folder = get_project_and_folder_metadata(project)
if not folder:
folder = 'root'

project_meta = get_project_metadata(project)
params = {
"project_id": project_meta['id'],
"team_id": project_meta["team_id"]
}
verified_users = get_team_metadata()["users"]
verified_users = [i['id'] for i in verified_users]
if user not in verified_users:
logging.warn(
f'Skipping {user}. {user} is not a verified contributor for the {project["name"]}'
)

folder_name = 'root'
if folder:
folder_name = folder['name']

params = {"project_id": project['id'], "team_id": project["team_id"]}
json_req = {
"image_names": image_names,
"assign_user_id": user,
"folder_name": folder,
"folder_name": folder_name,
}
response = _api.send_request(
req_type='PUT',
Expand All @@ -596,30 +600,6 @@ def assign_images(project, image_names, user):
response.status_code, "Couldn't assign images " + response.text
)

# images = search_images((project, project_folder), return_metadata=True)
# image_dict = {}
# for image in images:
# image_dict[image["name"]] = image["id"]

# image_ids = []
# for image_name in image_names:
# image_ids.append(image_dict[image_name])
# team_id, project_id = project["team_id"], project["id"]
# params = {"team_id": team_id, "project_id": project_id}
# if project_folder is not None:
# params['folder_id'] = project_folder['id']
# json_req = {"user_id": user, "image_ids": image_ids}
# response = _api.send_request(
# req_type='POST',
# path='/images/assign',
# params=params,
# json_req=json_req
# )
# if not response.ok:
# raise SABaseException(
# response.status_code, "Couldn't assign images " + response.text
# )


def assign_folder(project, folder_name, users):
"""Assigns folder to users. With SDK, the user can be
Expand All @@ -634,25 +614,24 @@ def assign_folder(project, folder_name, users):
"""

project_meta = get_project_metadata(project, include_contributors=True)
project_users = project_meta["contributors"]
verified_users = get_team_metadata()["users"]
project_name = project_meta['name']
project_users = [i['user_id'] for i in project_users]
verified_contributor = []
verified_users = [i['id'] for i in verified_users]
verified_users = set(users).intersection(set(verified_users))
unverified_contributor = set(users) - verified_users

for user in users:
if user not in project_users:
logging.warn(
f'Skipping {user} from assignees. {user} is not a verified contributor for the {project_name}'
)
continue
verified_contributor.append(user)
for user in unverified_contributor:
logging.warn(
f'Skipping {user} from assignees. {user} is not a verified contributor for the {project_name}'
)
continue

params = {
"project_id": project_meta['id'],
"team_id": project_meta["team_id"]
}
json_req = {
"assign_user_ids": verified_contributor,
"assign_user_ids": list(verified_users),
"folder_name": folder_name
}
response = _api.send_request(
Expand All @@ -666,7 +645,7 @@ def assign_folder(project, folder_name, users):
raise SABaseException(
response.status_code, "Couldn't assign folder " + response.text
)
logger.info(f'Assigned {folder_name} to users: {verified_contributor}')
logger.info(f'Assigned {folder_name} to users: {list(verified_users)}')


def unassign_folder(project, folder_name):
Expand Down Expand Up @@ -697,7 +676,6 @@ def unassign_folder(project, folder_name):
raise SABaseException(
response.status_code, "Couldn't unassign folder " + response.text
)
print('unassign_folder>>>>>>', response.text)


def unassign_images(project, image_names):
Expand All @@ -711,11 +689,20 @@ def unassign_images(project, image_names):
:type image_names: list of str
"""
project_meta = get_project_metadata(project)
project, folder = get_project_and_folder_metadata(project)
folder_name = 'root'
if folder:
folder_name = folder['name']
params = {
"project_id": project_meta['id'],
"team_id": project_meta["team_id"]
}
json_req = {"image_names": image_names, "remove_user_ids": ["all"]}
json_req = {
"image_names": image_names,
"remove_user_ids": ["all"],
"folder_name": folder_name
}

response = _api.send_request(
req_type='PUT',
path='/images/editAssignment',
Expand All @@ -727,5 +714,3 @@ def unassign_images(project, image_names):
raise SABaseException(
response.status_code, "Couldn't unassign images " + response.text
)

print('unassign_images>>>>>>', response.text)
1 change: 1 addition & 0 deletions superannotate/db/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from ..exceptions import SABaseException, SAImageSizeTooLarge, SANonExistingProjectNameException
import datetime
import boto3
from .project_api import get_project_metadata_bare

_api = API.get_instance()
logger = logging.getLogger("superannotate-python-sdk")
Expand Down
123 changes: 118 additions & 5 deletions tests/test_assign_images.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from pathlib import Path
import time

import pytest

import superannotate as sa
from superannotate.api import API

_api = API.get_instance()

PROJECT_NAME_VECTOR1 = "test assign images1"
PROJECT_NAME_VECTOR2 = "test assign images2"
Expand All @@ -16,7 +17,7 @@ def test_assign_images(tmpdir):
projects = sa.search_projects(PROJECT_NAME_VECTOR1, return_metadata=True)
for project in projects:
sa.delete_project(project)

time.sleep(1)
project = sa.create_project(PROJECT_NAME_VECTOR1, "test", "Vector")
email = sa.get_team_metadata()["users"][0]["email"]
sa.share_project(project, email, "QA")
Expand Down Expand Up @@ -70,7 +71,7 @@ def test_assign_images_folder(tmpdir):
projects = sa.search_projects(PROJECT_NAME_VECTOR2, return_metadata=True)
for project in projects:
sa.delete_project(project)

time.sleep(1)
project = sa.create_project(PROJECT_NAME_VECTOR2, "test", "Vector")
email = sa.get_team_metadata()["users"][0]["email"]
sa.share_project(project, email, "QA")
Expand Down Expand Up @@ -118,4 +119,116 @@ def test_assign_images_folder(tmpdir):
assert im1_metadata["annotator_id"] == email
assert im2_metadata["annotator_id"] == email
assert im1_metadata["qa_id"] is None
assert im2_metadata["qa_id"] is None
assert im2_metadata["qa_id"] is None


def test_unassign_images(tmpdir):
tmpdir = Path(tmpdir)
projects = sa.search_projects(PROJECT_NAME_VECTOR1, return_metadata=True)
for project in projects:
sa.delete_project(project)
time.sleep(1)
project = sa.create_project(PROJECT_NAME_VECTOR1, "test", "Vector")
email = sa.get_team_metadata()["users"][0]["email"]
sa.share_project(project, email, "QA")
sa.upload_images_from_folder_to_project(
project, "./tests/sample_project_vector"
)
sa.assign_images(
project, ["example_image_1.jpg", "example_image_2.jpg"], email
)
sa.unassign_images(
project,
["example_image_1.jpg", "example_image_2.jpg"],
)

im1_metadata = sa.get_image_metadata(project, "example_image_1.jpg")
im2_metadata = sa.get_image_metadata(project, "example_image_2.jpg")

assert im1_metadata["qa_id"] == None
assert im2_metadata["qa_id"] == None


def test_assign_folder(tmpdir):
tmpdir = Path(tmpdir)
projects = sa.search_projects(PROJECT_NAME_VECTOR1, return_metadata=True)
for project in projects:
sa.delete_project(project)
time.sleep(1)
project = sa.create_project(PROJECT_NAME_VECTOR1, "test", "Vector")
folder_name = "assign_folder"
sa.create_folder(project, folder_name)
email = sa.get_team_metadata()["users"][1]["email"]
sa.share_project(project, email, "QA")
sa.assign_folder(project, folder_name, [email])
folders = _search_folders(project, includeUsers=True)
assert len(folders["data"][0]['folder_users']) > 0


def test_unassign_folder(tmpdir):
tmpdir = Path(tmpdir)
projects = sa.search_projects(PROJECT_NAME_VECTOR1, return_metadata=True)
for project in projects:
sa.delete_project(project)
time.sleep(1)
project = sa.create_project(PROJECT_NAME_VECTOR1, "test", "Vector")
folder_name = "assign_folder"
sa.create_folder(project, folder_name)
email = sa.get_team_metadata()["users"][1]["email"]
sa.share_project(project, email, "QA")
sa.assign_folder(project, folder_name, [email])
folders = _search_folders(project, includeUsers=True)
assert len(folders["data"][0]['folder_users']) > 0
sa.unassign_folder(project, folder_name)
folders = _search_folders(project, includeUsers=True)
assert len(folders["data"][0]['folder_users']) == 0


def _search_folders(project, folder_name=None, includeUsers=False):
team_id, project_id = project["team_id"], project["id"]
params = {
'team_id': team_id,
'project_id': project_id,
'offset': 0,
'name': folder_name,
'is_root': 0,
'includeUsers': includeUsers
}

response = _api.send_request(req_type='GET', path='/folders', params=params)
response = response.json()
return response


def test_assign_folder_unverified_users(tmpdir, caplog):
tmpdir = Path(tmpdir)
projects = sa.search_projects(PROJECT_NAME_VECTOR1, return_metadata=True)
for project in projects:
sa.delete_project(project)
time.sleep(1)
project = sa.create_project(PROJECT_NAME_VECTOR1, "test", "Vector")
folder_name = "assign_folder"
sa.create_folder(project, folder_name)
email = "unverified_user@mail.com"
sa.assign_folder(project, folder_name, [email])
"Skipping unverified_user@mail.com from assignees." in caplog.text


def test_assign_images_unverified_user(tmpdir, caplog):
tmpdir = Path(tmpdir)

projects = sa.search_projects(PROJECT_NAME_VECTOR2, return_metadata=True)
for project in projects:
sa.delete_project(project)
time.sleep(1)
project = sa.create_project(PROJECT_NAME_VECTOR2, "test", "Vector")
sa.create_folder(project, FOLDER2)
project_folder = project["name"] + "/" + FOLDER2
sa.upload_images_from_folder_to_project(
project_folder, "./tests/sample_project_vector"
)
email = "unverified_user@email.com"
sa.assign_images(
project_folder, ["example_image_1.jpg", "example_image_2.jpg"], email
)
"Skipping unverified_user@mail.com from assignees." in caplog.text