Skip to content

Commit

Permalink
feat: add workspace add-user command (#3712)
Browse files Browse the repository at this point in the history
<!-- Thanks for your contribution! As part of our Community Growers
initiative 🌱, we're donating Justdiggit bunds in your name to reforest
sub-Saharan Africa. To claim your Community Growers certificate, please
contact David Berenstein in our Slack community or fill in this form
https://tally.so/r/n9XrxK once your PR has been merged. -->

# Description

This PR adds a new CLI command python -m argilla workspaces create.

Closes #3680

**Type of change**

(Please delete options that are not relevant. Remember to title the PR
according to the type of change)

- [x] New feature (non-breaking change which adds functionality)

**How Has This Been Tested**

Unit tests have been added to tests/unit/tasks/workspaces directory

 - [x] Add user to workspace
 - [x] Add user to non-existent workspace
 - [x] Add non-existent user to workspace
 - [x] Add user belonging to same workspace
 - [x] Add user to workspace without specifying workspace name
 - [x]  Add user to workspace without logging in

**Checklist**

- [ ] I added relevant documentation
- [x] I followed the style guidelines of this project
- [x] I did a self-review of my code
- [ ] I made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I filled out [the contributor form](https://tally.so/r/n9XrxK)
(see text above)
- [x] I have added relevant notes to the `CHANGELOG.md` file (See
https://keepachangelog.com/)

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: gabrielmbmb <[email protected]>
  • Loading branch information
3 people authored Sep 6, 2023
1 parent 4880733 commit 9408193
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ These are the section headers that we use:
- Added `info` command to get info about the used Argilla client and server ([#3707](https://github.com/argilla-io/argilla/pull/3707)).
- Added `datasets delete` command to delete a `FeedbackDataset` from Argilla ([#3703](https://github.com/argilla-io/argilla/pull/3703)).
- Added `created_at` and `updated_at` properties to `RemoteFeedbackDataset` and `FilteredRemoteFeedbackDataset` ([#3709](https://github.com/argilla-io/argilla/pull/3709)).
- Added `workspaces add-user` command to add a user to workspace ([#3712](https://github.com/argilla-io/argilla/pull/3712)).

### Changed

Expand Down
2 changes: 2 additions & 0 deletions src/argilla/tasks/workspaces/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from argilla.tasks.callback import init_callback

from .add_user import add_user
from .create import create_workspace
from .delete_user import delete_user
from .list import list_workspaces
Expand Down Expand Up @@ -57,6 +58,7 @@ def callback(
app.command(name="create", help="Create a workspace")(create_workspace)
app.command(name="list", help="Lists workspaces of the logged user.")(list_workspaces)
app.command(name="delete-user", help="Deletes a user from a workspace.")(delete_user)
app.command(name="add-user", help="Adds a user to a workspace.")(add_user)


if __name__ == "__main__":
Expand Down
64 changes: 64 additions & 0 deletions src/argilla/tasks/workspaces/add_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright 2021-present, the Recognai S.L. team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import TYPE_CHECKING

import typer

if TYPE_CHECKING:
from argilla.client.workspaces import Workspace


def add_user(
ctx: typer.Context,
username: str = typer.Argument(..., help="The username of the user to be added to the workspace"),
) -> None:
from rich.console import Console

from argilla.client.users import User
from argilla.tasks.rich import get_argilla_themed_panel

workspace: "Workspace" = ctx.obj

try:
user = User.from_name(username)
except ValueError as e:
typer.echo(f"User with username '{username}' does not exist")
raise typer.Exit(code=1) from e
except RuntimeError as e:
typer.echo("An unexpected error occurred when trying to retrieve the user from the Argilla server")
raise typer.Exit(code=1) from e

if user.is_owner:
typer.echo(
f"User with name={username} is an owner. Users with owner role don't need specific permissions per"
" workspace, as those are super-users with privileges over everything under Argilla."
)
raise typer.Exit(code=1)

try:
workspace.add_user(user.id)
except ValueError as e:
typer.echo(f"User with username '{username}' already exists in workspace '{workspace.name}'")
raise typer.Exit(code=1) from e
except RuntimeError as e:
typer.echo("An unexpected error occurred when trying to add user to the workspace")
raise typer.Exit(code=1) from e

panel = get_argilla_themed_panel(
f"User with username '{username}' has been added to '{workspace.name}' workspace",
title="User Added",
title_align="left",
)
Console().print(panel)
122 changes: 122 additions & 0 deletions tests/unit/tasks/workspaces/test_add_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Copyright 2021-present, the Recognai S.L. team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import TYPE_CHECKING

import pytest

if TYPE_CHECKING:
from click.testing import CliRunner
from pytest_mock import MockerFixture
from typer import Typer


@pytest.mark.usefixtures("login_mock")
class TestSuiteWorkspaceAddUser:
def test_workspace_add_user(
self, cli_runner: "CliRunner", cli: "Typer", mocker: "MockerFixture", workspace, user
) -> None:
mocker.patch("argilla.client.workspaces.Workspace.from_name", return_value=workspace)
mocker.patch("argilla.client.users.User.from_name", return_value=user)
mocker.patch("argilla.client.workspaces.Workspace.add_user")

result = cli_runner.invoke(cli, "workspaces --name unit-test add-user unit-test")

assert result.exit_code == 0
assert "User with username 'unit-test' has been added to 'unit-test' workspace" in result.stdout

def test_workspace_add_user_with_non_existing_workspace(
self, cli_runner: "CliRunner", cli: "Typer", mocker: "MockerFixture"
) -> None:
mocker.patch("argilla.client.workspaces.Workspace.from_name", side_effect=ValueError)

result = cli_runner.invoke(cli, "workspaces --name unit-test add-user unit-test")

assert result.exit_code == 1
assert "Workspace 'unit-test' does not exist" in result.stdout

def test_workspace_add_user_with_non_existing_user(
self, cli_runner: "CliRunner", cli: "Typer", mocker: "MockerFixture", workspace, user
) -> None:
mocker.patch("argilla.client.workspaces.Workspace.from_name", return_value=workspace)
mocker.patch("argilla.client.users.User.from_name", side_effect=ValueError)

result = cli_runner.invoke(cli, "workspaces --name unit-test add-user unit-test")

assert result.exit_code == 1
assert "User with username 'unit-test' does not exist" in result.stdout

def test_workspace_add_user_with_owner_user(
self, cli_runner: "CliRunner", cli: "Typer", mocker: "MockerFixture", workspace, user
) -> None:
user.role = "owner"
mocker.patch("argilla.client.workspaces.Workspace.from_name", return_value=workspace)
mocker.patch("argilla.client.users.User.from_name", return_value=user)

result = cli_runner.invoke(cli, "workspaces --name unit-test add-user unit-test")

assert result.exit_code == 1
assert (
"User with name=unit-test is an owner. Users with owner role don't need specific permissions per"
" workspace, as those are super-users with privileges over everything under Argilla." in result.stdout
)

def test_workspace_add_user_with_user_belonging_to_workspace(
self, cli_runner: "CliRunner", cli: "Typer", mocker: "MockerFixture", workspace, user
) -> None:
mocker.patch("argilla.client.workspaces.Workspace.from_name", return_value=workspace)
mocker.patch("argilla.client.users.User.from_name", return_value=user)
mocker.patch("argilla.client.workspaces.Workspace.add_user", side_effect=ValueError)

result = cli_runner.invoke(cli, "workspaces --name unit-test add-user unit-test")

assert result.exit_code == 1
assert "User with username 'unit-test' already exists in workspace 'unit-test'" in result.stdout

def test_workspace_add_user_with_unexpected_error(
self, cli_runner: "CliRunner", cli: "Typer", mocker: "MockerFixture", workspace, user
) -> None:
mocker.patch("argilla.client.workspaces.Workspace.from_name", return_value=workspace)
mocker.patch("argilla.client.users.User.from_name", return_value=user)
mocker.patch("argilla.client.workspaces.Workspace.add_user", side_effect=RuntimeError)

result = cli_runner.invoke(cli, "workspaces --name unit-test add-user unit-test")

assert result.exit_code == 1
assert "An unexpected error occurred when trying to add user to the workspace" in result.stdout

def test_workspace_add_user_with_unexpected_error_retieve_user(
self, cli_runner: "CliRunner", cli: "Typer", mocker: "MockerFixture", workspace, user
) -> None:
mocker.patch("argilla.client.workspaces.Workspace.from_name", return_value=workspace)
mocker.patch("argilla.client.users.User.from_name", side_effect=RuntimeError)
mocker.patch("argilla.client.workspaces.Workspace.add_user")

result = cli_runner.invoke(cli, "workspaces --name unit-test add-user unit-test")

assert result.exit_code == 1
assert "An unexpected error occurred when trying to retrieve the user from the Argilla server" in result.stdout

def test_workspace_add_user_without_workspace_name(self, cli_runner: "CliRunner", cli: "Typer") -> None:
result = cli_runner.invoke(cli, "workspaces add-user unit-test")

assert result.exit_code == 2


@pytest.mark.usefixtures("not_logged_mock")
def test_list_users_needs_login(cli_runner: "CliRunner", cli: "Typer") -> None:
result = cli_runner.invoke(cli, "workspaces --name unit-test add-user unit-test")

assert result.exit_code == 1
assert "You are not logged in. Please run `argilla login` to login to an Argilla server." in result.stdout

0 comments on commit 9408193

Please sign in to comment.