Skip to content

Commit

Permalink
Merge pull request #52 from kurusugawa-computer/change_operator
Browse files Browse the repository at this point in the history
[task change_operator] タスクの担当者を変更するコマンドを追加する
  • Loading branch information
yuji38kwmt authored Aug 30, 2019
2 parents 059d0f0 + 41cffa8 commit 62cab4e
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 24 deletions.
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ annofabapiを使ったCLI(Command Line Interface)ツールです。
# 注意
* 作者または著作権者は、ソフトウェアに関してなんら責任を負いません。
* 予告なく互換性のない変更がある可能性をご了承ください。
* AnnoFabプロジェクトに大きな変更を及ぼすツールも存在します。間違えて実行してしまわないよう、注意してご利用ください。
* AnnoFabプロジェクトに大きな変更を及ぼすコマンドも存在します。間違えて実行してしまわないよう、注意してご利用ください。


## 廃止予定
Expand Down Expand Up @@ -33,7 +33,7 @@ AnnoFabの認証情報を設定する方法は2つあります。
AnnoFabの認証情報が設定されていない状態で`annofabcli`コマンドを実行すると、標準入力からAnnoFabの認証情報を入力できるようになります。

```
$ annofabcli diff_projects aaa bbb
$ annofabcli project diff aaa bbb
Enter AnnoFab User ID: XXXXXX
Enter AnnoFab Password:
```
Expand Down Expand Up @@ -67,9 +67,10 @@ $ docker run -it -e ANNOFAB_USER_ID=XXXX -e ANNOFAB_PASSWORD=YYYYY annofab-cli a
|----|-------------------------------|----------------------------------------------------------------------------------------------------------|------------|
|input_data|list | 入力データ一覧を出力する。 |-|
|instruction| upload | HTMLファイルを作業ガイドとして登録する。 |チェッカー/オーナ|
|task|list | タスク一覧を出力する。 |-|
|task| cancel_acceptance | 受け入れ完了タスクを、受け入れ取り消しする。 |オーナ|
|task| change_operator | タスクの担当者を変更する。 |チェッカー/オーナ|
|task| complete | 未処置の検査コメントを適切な状態に変更して、タスクを受け入れ完了にする。 |チェッカー/オーナ|
|task|list | タスク一覧を出力する。 |-|
|task| reject | 検査コメントを付与してタスクを差し戻す。 |チェッカー/オーナ|
|project| diff | プロジェクト間の差分を表示する |チェッカー/オーナ|
|project| download | タスクや検査コメント、アノテーションなどをダウンロードします。 |オーナ|
Expand Down Expand Up @@ -104,13 +105,13 @@ CSVのフォーマットをJSON形式で指定します。`--format`が`csv`で


### `--disable_log`
ログを無効化する
ログを無効化にします

### `f` / `--format`
出力フォーマットを指定します。基本的に以下のフォーマットを指定できます。
* csv : CSV(デフォルとはカンマ区切り)
* json : インデントや空白がないJSON
* pretty_json : インデントされたJSON
* `csv` : CSV(デフォルとはカンマ区切り)
* `json` : インデントや空白がないJSON
* `pretty_json` : インデントされたJSON

list系のコマンドで利用できます。

Expand All @@ -130,7 +131,7 @@ $ annofabcli project diff -h
ログファイルを保存するディレクトリを指定します。指定しない場合、`.log`ディレクトリにログファイルを出力します。

### `--logging_yaml`
ロギグングの設定ファイル(YAML)を指定します。指定した場合、`--logdir`オプションは無視されます。指定しない場合、デフォルトのロギング設定ファイルが読み込まれます。
以下のような、ロギグングの設定ファイル(YAML)を指定します。指定した場合、`--logdir`オプションは無視されます。指定しない場合、デフォルトのロギング設定ファイルが読み込まれます。
設定ファイルの書き方は https://docs.python.org/ja/3/howto/logging.html を参照してください。

```yaml:logging-sample.yaml
Expand Down Expand Up @@ -320,6 +321,18 @@ $ annofabcli task cancel_acceptance --project_id prj1 --task_id file://task.txt
```
### task change_operator
タスクの担当者を変更します。
```
# 指定されたタスクの担当者を 'user1' に変更する。
$ annofabcli task change_operator --project_id prj1 --task_id file://task.txt --user_id usr1

# 指定されたタスクの担当者を未割り当てに変更する。
$ annofabcli task change_operator --project_id prj1 --task_id file://task.txt --not_assign
```
### task complete
未処置の検査コメントを適切な状態に変更して、タスクを受け入れ完了にします。
Expand Down
2 changes: 1 addition & 1 deletion annofabcli/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.5.1'
__version__ = '1.6.0'
5 changes: 3 additions & 2 deletions annofabcli/common/facade.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,15 @@ def download_latest_simple_annotation_archive_with_waiting(self, project_id: str
# operateTaskのfacade
##################

def change_operator_of_task(self, project_id: str, task_id: str, account_id: str) -> Dict[str, Any]:
def change_operator_of_task(self, project_id: str, task_id: str,
account_id: Optional[str] = None) -> Dict[str, Any]:
"""
タスクの担当者を変更する
Args:
self:
project_id:
task_id:
account_id:
account_id: 新しい担当者のuser_id. Noneの場合未割り当てになる。
Returns:
変更後のtask情報
Expand Down
129 changes: 129 additions & 0 deletions annofabcli/task/change_operator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
"""
検査コメントを付与してタスクを差し戻します。
"""

import argparse
import logging
from typing import Any, Dict, List, Optional # pylint: disable=unused-import

import requests
from annofabapi.dataclass.task import Task
from annofabapi.models import ProjectMemberRole, TaskStatus

import annofabcli
import annofabcli.common.cli
from annofabcli import AnnofabApiFacade
from annofabcli.common.cli import AbstractCommandLineInterface, ArgumentParser, build_annofabapi_resource_and_login

logger = logging.getLogger(__name__)


class ChangeOperator(AbstractCommandLineInterface):
def confirm_change_operator(self, task: Task, user_id: Optional[str] = None) -> bool:
if user_id is None:
str_user_id = "未割り当て"
else:
str_user_id = user_id

confirm_message = f"task_id = {task.task_id} のタスクの担当者を '{str_user_id}' にしますか?"
return self.confirm_processing(confirm_message)

def change_operator(self, project_id: str, task_id_list: List[str], user_id: Optional[str] = None):
"""
検査コメントを付与して、タスクを差し戻す
Args:
project_id:
task_id_list:
user_id: タスクを担当するユーザのuser_id。Noneの場合タスクの担当者は未割り当て
"""

super().validate_project(project_id, [ProjectMemberRole.OWNER, ProjectMemberRole.ACCEPTER])

if user_id is not None:
account_id = self.facade.get_account_id_from_user_id(project_id, user_id)
if account_id is None:
logger.error(f"ユーザ '{user_id}' のaccount_idが見つかりませんでした。終了します。")
return
else:
account_id = None

logger.info(f"タスクの担当者を変更する件数: {len(task_id_list)}")
success_count = 0

for task_index, task_id in enumerate(task_id_list):
str_progress = annofabcli.utils.progress_msg(task_index + 1, len(task_id_list))

dict_task, _ = self.service.api.get_task(project_id, task_id)
task: Task = Task.from_dict(dict_task)

logger.debug(f"{str_progress} : task_id = {task.task_id}, "
f"status = {task.status.value}, "
f"phase = {task.phase.value}, "
f"user_id = {self.facade.get_user_id_from_account_id(project_id, task.account_id)}")

if task.status in [TaskStatus.COMPLETE, TaskStatus.WORKING]:
logger.warning(
f"{str_progress} : task_id = {task_id} : タスクのstatusがworking or complete なので、担当者を変更できません。")
continue

if not self.confirm_change_operator(task, user_id):
continue

try:
# 担当者を変更する
self.facade.change_operator_of_task(project_id, task_id, account_id)
success_count += 1
logger.debug(f"{str_progress} : task_id = {task_id}, phase={dict_task['phase']}, {user_id}に担当者を変更しました。")

except requests.exceptions.HTTPError as e:
logger.warning(e)
logger.warning(f"{str_progress} : task_id = {task_id} の担当者を変更するのに失敗しました。")
continue

logger.info(f"{success_count} / {len(task_id_list)} 件 タスクの担当者を変更しました。")

def main(self):
args = self.args

task_id_list = annofabcli.common.cli.get_list_from_args(args.task_id)
if args.user_id is not None:
user_id = args.user_id
elif args.not_assign:
user_id = None
else:
logger.error(f"タスクの担当者の指定方法が正しくありません。")
return

self.change_operator(args.project_id, task_id_list, user_id)


def main(args: argparse.Namespace):
service = build_annofabapi_resource_and_login()
facade = AnnofabApiFacade(service)
ChangeOperator(service, facade, args).main()


def parse_args(parser: argparse.ArgumentParser):
argument_parser = ArgumentParser(parser)

argument_parser.add_project_id()
argument_parser.add_task_id()

assign_group = parser.add_mutually_exclusive_group(required=True)

assign_group.add_argument('-u', '--user_id', type=str, help='タスクを新しく担当するユーザのuser_idを指定してください。')

assign_group.add_argument('--not_assign', action="store_true", help='指定した場合、タスクの担当者は未割り当てになります。')

parser.set_defaults(subcommand_func=main)


def add_parser(subparsers: argparse._SubParsersAction):
subcommand_name = "change_operator"
subcommand_help = "タスクの担当者を変更します。"
description = ("タスクの担当者を変更します。ただし、作業中のタスクに対しては変更しません。")
epilog = "チェッカーまたはオーナロールを持つユーザで実行してください。"

parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description, epilog=epilog)
parse_args(parser)
6 changes: 4 additions & 2 deletions annofabcli/task/subcommand_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import annofabcli
import annofabcli.common.cli
import annofabcli.task.cancel_acceptance
import annofabcli.task.change_operator
import annofabcli.task.complete_tasks
import annofabcli.task.list_tasks
import annofabcli.task.reject_tasks
Expand All @@ -13,10 +14,11 @@ def parse_args(parser: argparse.ArgumentParser):
subparsers = parser.add_subparsers(dest='subcommand_name')

# サブコマンドの定義
annofabcli.task.cancel_acceptance.add_parser(subparsers)
annofabcli.task.change_operator.add_parser(subparsers)
annofabcli.task.complete_tasks.add_parser(subparsers)
annofabcli.task.list_tasks.add_parser(subparsers)
annofabcli.task.reject_tasks.add_parser(subparsers)
annofabcli.task.complete_tasks.add_parser(subparsers)
annofabcli.task.cancel_acceptance.add_parser(subparsers)


def add_parser(subparsers: argparse._SubParsersAction):
Expand Down
42 changes: 31 additions & 11 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"""
import configparser
import datetime
import json
import os
from pathlib import Path

Expand Down Expand Up @@ -35,16 +34,37 @@ def get_organization_name(project_id: str) -> str:
return organization["organization_name"]


def test_task():
main([
'task', 'list', '--project_id', project_id, '--task_query',
f'{{"user_id": "{user_id}", "phase":"acceptance", "status": "complete"}}', '--format', 'csv'
])
class TestTask:
command_name = "task"

def test_list(self):
main([
self.command_name, 'list', '--project_id', project_id, '--task_query',
f'{{"user_id": "{user_id}", "phase":"acceptance", "status": "complete"}}', '--format', 'csv'
])

def test_cancel_acceptance(self):
main([self.command_name, 'cancel_acceptance', '--project_id', project_id, '--task_id', task_id, '--yes'])

def test_reject_task(self):
inspection_comment = datetime.datetime.now().isoformat()
main([
self.command_name, 'reject', '--project_id', project_id, '--task_id', task_id, '--comment',
inspection_comment, '--yes'
])

main(['task', 'cancel_acceptance', '--project_id', project_id, '--task_id', task_id, '--yes'])
def test_change_operator(self):
# user指定
main([
self.command_name, 'change_operator', '--project_id', project_id, '--task_id', task_id, '--user_id',
user_id, '--yes'
])

inspection_comment = datetime.datetime.now().isoformat()
main(['task', 'reject', '--project_id', project_id, '--task_id', task_id, '--comment', inspection_comment, '--yes'])
# 未割り当て
main([
self.command_name, 'change_operator', '--project_id', project_id, '--task_id', task_id, '--not_assign',
'--yes'
])


def test_project():
Expand Down Expand Up @@ -93,8 +113,8 @@ def test_filesystem():
main([
'filesystem', 'write_annotation_image', '--annotation',
str(zip_path), '--output_dir',
str(output_image_dir), '--image_size', '64x64', '--label_color',
f"file://{str(label_color_file)}", '--image_extension', 'jpg'
str(output_image_dir), '--image_size', '64x64', '--label_color', f"file://{str(label_color_file)}",
'--image_extension', 'jpg'
])


Expand Down

0 comments on commit 62cab4e

Please sign in to comment.