diff --git a/dictation_server/src/api/odms/openapi.json b/dictation_server/src/api/odms/openapi.json index 16900de..c09bd8a 100644 --- a/dictation_server/src/api/odms/openapi.json +++ b/dictation_server/src/api/odms/openapi.json @@ -158,396 +158,6 @@ "tags": ["accounts"] } }, - "/task/checkout": { - "post": { - "operationId": "checkout", - "summary": "", - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusRequest" - } - } - } - }, - "responses": { - "200": { - "description": "成功時のレスポンス", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusResponse" - } - } - } - }, - "401": { - "description": "認証エラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "指定したIDの音声ファイルが存在しない場合", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "想定外のサーバーエラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "tags": ["task"], - "security": [ - { - "bearer": [] - } - ] - } - }, - "/task/checkin": { - "post": { - "operationId": "checkin", - "summary": "", - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusRequest" - } - } - } - }, - "responses": { - "200": { - "description": "成功時のレスポンス", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusResponse" - } - } - } - }, - "401": { - "description": "認証エラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "指定したIDの音声ファイルが存在しない場合", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "想定外のサーバーエラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "tags": ["task"], - "security": [ - { - "bearer": [] - } - ] - } - }, - "/task/cancel": { - "post": { - "operationId": "cancel", - "summary": "", - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusRequest" - } - } - } - }, - "responses": { - "200": { - "description": "成功時のレスポンス", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusResponse" - } - } - } - }, - "401": { - "description": "認証エラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "指定したIDの音声ファイルが存在しない場合", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "想定外のサーバーエラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "tags": ["task"], - "security": [ - { - "bearer": [] - } - ] - } - }, - "/task/suspend": { - "post": { - "operationId": "suspend", - "summary": "", - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusRequest" - } - } - } - }, - "responses": { - "200": { - "description": "成功時のレスポンス", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusResponse" - } - } - } - }, - "401": { - "description": "認証エラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "指定したIDの音声ファイルが存在しない場合", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "想定外のサーバーエラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "tags": ["task"], - "security": [ - { - "bearer": [] - } - ] - } - }, - "/task/send-back": { - "post": { - "operationId": "sendBack", - "summary": "", - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusRequest" - } - } - } - }, - "responses": { - "200": { - "description": "成功時のレスポンス", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusResponse" - } - } - } - }, - "401": { - "description": "認証エラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "指定したIDの音声ファイルが存在しない場合", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "想定外のサーバーエラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "tags": ["task"], - "security": [ - { - "bearer": [] - } - ] - } - }, - "/task/backup": { - "post": { - "operationId": "backup", - "summary": "", - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusRequest" - } - } - } - }, - "responses": { - "200": { - "description": "成功時のレスポンス", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusResponse" - } - } - } - }, - "401": { - "description": "認証エラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "指定したIDの音声ファイルが存在しない場合", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "想定外のサーバーエラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "tags": ["task"], - "security": [ - { - "bearer": [] - } - ] - } - }, "/users/confirm": { "post": { "operationId": "confirmUser", @@ -803,6 +413,722 @@ ] } }, + "/files/audio/upload-finished": { + "post": { + "operationId": "createTask", + "summary": "", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AudioUploadFinishedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AudioUploadFinishedResponse" + } + } + } + }, + "400": { + "description": "不正なパラメータ", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["files"] + } + }, + "/files/audio/upload-location": { + "get": { + "operationId": "uploadLocation", + "summary": "", + "parameters": [], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AudioUploadLocationResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["files"], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/files/audio/download-location": { + "get": { + "operationId": "downloadLocation", + "summary": "", + "parameters": [ + { + "name": "audioFileId", + "required": true, + "in": "query", + "description": "音声ファイル情報をDBから取得するためのID", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AudioDownloadLocationResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["files"], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/files/template/download-location": { + "get": { + "operationId": "downloadTemplateLocation", + "summary": "", + "parameters": [ + { + "name": "audioFileId", + "required": true, + "in": "query", + "description": "文字起こし対象の音声ファイルID", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TemplateDownloadLocationResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["files"], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/files/audio/next": { + "get": { + "operationId": "getNextAudioFile", + "summary": "", + "parameters": [ + { + "name": "endedFileId", + "required": true, + "in": "query", + "description": "文字起こし完了したタスクの音声ファイルID", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AudioNextResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["files"], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/tasks": { + "get": { + "operationId": "getTasks", + "summary": "", + "parameters": [ + { + "name": "pageNumber", + "required": true, + "in": "query", + "description": "ページ番号(ページサイズごとに区切った何ページ目を取得するか)", + "schema": { + "minimum": 1, + "type": "number" + } + }, + { + "name": "pageSize", + "required": true, + "in": "query", + "description": "ページサイズ(一度に何件のタスクを取得するか)", + "schema": { + "minimum": 1, + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TasksResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["tasks"], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/tasks/{audioFileId}/checkout": { + "post": { + "operationId": "checkout", + "summary": "", + "parameters": [ + { + "name": "audioFileId", + "required": true, + "in": "path", + "description": "ODMS Cloud上の音声ファイルID", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeStatusResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "指定したIDの音声ファイルが存在しない場合", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["tasks"], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/tasks/{audioFileId}/checkin": { + "post": { + "operationId": "checkin", + "summary": "", + "parameters": [ + { + "name": "audioFileId", + "required": true, + "in": "path", + "description": "ODMS Cloud上の音声ファイルID", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeStatusResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "指定したIDの音声ファイルが存在しない場合", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["tasks"], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/tasks/{audioFileId}/cancel": { + "post": { + "operationId": "cancel", + "summary": "", + "parameters": [ + { + "name": "audioFileId", + "required": true, + "in": "path", + "description": "ODMS Cloud上の音声ファイルID", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeStatusResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "指定したIDの音声ファイルが存在しない場合", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["tasks"], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/tasks/{audioFileId}/suspend": { + "post": { + "operationId": "suspend", + "summary": "", + "parameters": [ + { + "name": "audioFileId", + "required": true, + "in": "path", + "description": "ODMS Cloud上の音声ファイルID", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeStatusResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "指定したIDの音声ファイルが存在しない場合", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["tasks"], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/tasks/{audioFileId}/send-back": { + "post": { + "operationId": "sendBack", + "summary": "", + "parameters": [ + { + "name": "audioFileId", + "required": true, + "in": "path", + "description": "ODMS Cloud上の音声ファイルID", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeStatusResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "指定したIDの音声ファイルが存在しない場合", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["tasks"], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/tasks/{audioFileId}/backup": { + "post": { + "operationId": "backup", + "summary": "", + "parameters": [ + { + "name": "audioFileId", + "required": true, + "in": "path", + "description": "ODMS Cloud上の音声ファイルID", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeStatusResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "指定したIDの音声ファイルが存在しない場合", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["tasks"], + "security": [ + { + "bearer": [] + } + ] + } + }, "/notification/register": { "post": { "operationId": "register", @@ -867,161 +1193,6 @@ } ] } - }, - "/files/audio/upload-location": { - "get": { - "operationId": "uploadLocation", - "summary": "", - "parameters": [], - "responses": { - "200": { - "description": "成功時のレスポンス", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AudioUploadLocationResponse" - } - } - } - }, - "401": { - "description": "認証エラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "想定外のサーバーエラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "tags": ["files"], - "security": [ - { - "bearer": [] - } - ] - } - }, - "/files/audio/download-location": { - "get": { - "operationId": "downloadLocation", - "summary": "", - "parameters": [ - { - "name": "id", - "required": true, - "in": "query", - "description": "音声ファイル情報をDBから取得するためのID", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "成功時のレスポンス", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AudioDownloadLocationResponse" - } - } - } - }, - "401": { - "description": "認証エラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "想定外のサーバーエラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "tags": ["files"], - "security": [ - { - "bearer": [] - } - ] - } - }, - "/files/template/download-location": { - "get": { - "operationId": "downloadTemplateLocation", - "summary": "", - "parameters": [ - { - "name": "audioFileId", - "required": true, - "in": "query", - "description": "文字起こし対象の音声ファイルID", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "成功時のレスポンス", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TemplateDownloadLocationResponse" - } - } - } - }, - "401": { - "description": "認証エラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "想定外のサーバーエラー", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "tags": ["files"], - "security": [ - { - "bearer": [] - } - ] - } } }, "info": { @@ -1137,20 +1308,6 @@ "type": "object", "properties": {} }, - "ChangeStatusRequest": { - "type": "object", - "properties": { - "audioFileId": { - "type": "string", - "description": "OMDS Cloud上の音声ファイルID" - } - }, - "required": ["audioFileId"] - }, - "ChangeStatusResponse": { - "type": "object", - "properties": {} - }, "ConfirmRequest": { "type": "object", "properties": { @@ -1358,23 +1515,95 @@ "prompt" ] }, - "RegisterRequest": { + "AudioUploadFinishedRequest": { "type": "object", "properties": { - "pns": { + "url": { "type": "string", - "description": "wns or apns" + "description": "アップロード先Blob Storage(ファイル名含む)" }, - "handler": { + "authorId": { "type": "string", - "description": "wnsのチャネルURI or apnsのデバイストークン" + "description": "自分自身(ログイン認証)したAuthorID" + }, + "fileName": { + "type": "string", + "description": "音声ファイル名" + }, + "duration": { + "type": "string", + "description": "音声ファイルの録音時間(yyyy-mm-ddThh:mm:ss.sss)" + }, + "createdDate": { + "type": "string", + "description": "音声ファイルの録音作成日時(開始日時)(yyyy-mm-ddThh:mm:ss.sss)" + }, + "completedDate": { + "type": "string", + "description": "音声ファイルの録音作成終了日時(yyyy-mm-ddThh:mm:ss.sss)" + }, + "uploadedDate": { + "type": "string", + "description": "音声ファイルのアップロード日時(yyyy-mm-ddThh:mm:ss.sss)" + }, + "fileSize": { + "type": "string" + }, + "priority": { + "type": "string", + "description": "優先度 \"00\":Normal / \"01\":High" + }, + "audioFormat": { + "type": "string", + "description": "録音形式: DSS/DS2(SP)/DS2(QP)" + }, + "comment": { + "type": "string" + }, + "workType": { + "type": "string" + }, + "optionItemLabel": { + "type": "string", + "minLength": 1, + "maxLength": 16 + }, + "optionItemValue": { + "type": "string", + "minLength": 1, + "maxLength": 20 + }, + "isEncrypted": { + "type": "boolean" } }, - "required": ["pns", "handler"] + "required": [ + "url", + "authorId", + "fileName", + "duration", + "createdDate", + "completedDate", + "uploadedDate", + "fileSize", + "priority", + "audioFormat", + "comment", + "workType", + "optionItemLabel", + "optionItemValue", + "isEncrypted" + ] }, - "RegisterResponse": { + "AudioUploadFinishedResponse": { "type": "object", - "properties": {} + "properties": { + "jobNumber": { + "type": "string", + "description": "8桁固定の数字" + } + }, + "required": ["jobNumber"] }, "AudioUploadLocationResponse": { "type": "object", @@ -1402,6 +1631,204 @@ } }, "required": ["url"] + }, + "AudioNextResponse": { + "type": "object", + "properties": { + "nextFileId": { + "type": "number", + "description": "ODMS Cloud上の次の音声ファイルID(存在しなければ空文字)" + } + }, + "required": ["nextFileId"] + }, + "Typist": { + "type": "object", + "properties": { + "typistUserId": { + "type": "number", + "description": "TypistID(TypistIDかTypistGroupIDのどちらかに値が入る)" + }, + "typistGroupId": { + "type": "number", + "description": "TypistGroupID(TypistGroupIDかTypistIDのどちらかに値が入る)" + }, + "typistName": { + "type": "string", + "description": "Typist名 / TypistGroup名" + } + }, + "required": ["typistName"] + }, + "Task": { + "type": "object", + "properties": { + "audioFileId": { + "type": "number", + "description": "ODMS Cloud上の音声ファイルID" + }, + "authorId": { + "type": "string", + "description": "AuthorID" + }, + "workType": { + "type": "string" + }, + "optionItemLabel": { + "type": "string", + "minLength": 1, + "maxLength": 16 + }, + "optionItemValue": { + "type": "string", + "minLength": 1, + "maxLength": 20 + }, + "url": { + "type": "string", + "description": "アップロード先Blob Storage(ファイル名含む)" + }, + "fileName": { + "type": "string", + "description": "音声ファイル名" + }, + "audioDuration": { + "type": "string", + "description": "音声ファイルの録音時間(yyyy-mm-ddThh:mm:ss.sss)" + }, + "audioCreatedDate": { + "type": "string", + "description": "音声ファイルの録音開始日時(yyyy-mm-ddThh:mm:ss.sss)" + }, + "audioFinishedDate": { + "type": "string", + "description": "音声ファイルの録音終了日時(yyyy-mm-ddThh:mm:ss.sss)" + }, + "audioUploadedDate": { + "type": "string", + "description": "音声ファイルのアップロード日時(yyyy-mm-ddThh:mm:ss.sss)" + }, + "fileSize": { + "type": "string", + "description": "音声ファイルのファイルサイズ" + }, + "priority": { + "type": "string", + "description": "音声ファイルの優先度 \"00\":Normal / \"01\":High" + }, + "audioFormat": { + "type": "string", + "description": "録音形式: DSS/DS2(SP)/DS2(QP)" + }, + "comment": { + "type": "string", + "description": "コメント" + }, + "isEncrypted": { + "type": "boolean" + }, + "jobNumber": { + "type": "string", + "description": "JOBナンバー" + }, + "typist": { + "description": "割り当てられたユーザー", + "allOf": [ + { + "$ref": "#/components/schemas/Typist" + } + ] + }, + "assignees": { + "description": "文字起こしに着手できる(チェックアウト可能な)、タスクにアサインされているグループ/個人の一覧", + "type": "array", + "items": { + "$ref": "#/components/schemas/Typist" + } + }, + "status": { + "type": "number", + "description": "音声ファイルのファイルステータス 1:Uploaded(Cancel) / 2:Pending / 3:InProgress / 4:Finished / 5:Backup" + }, + "transcriptionStartedDate": { + "type": "string", + "description": "文字起こし開始日時(yyyy-mm-ddThh:mm:ss.sss)" + }, + "transcriptionFinishedDate": { + "type": "string", + "description": "文字起こし終了日時(yyyy-mm-ddThh:mm:ss.sss)" + } + }, + "required": [ + "audioFileId", + "authorId", + "workType", + "optionItemLabel", + "optionItemValue", + "url", + "fileName", + "audioDuration", + "audioCreatedDate", + "audioFinishedDate", + "audioUploadedDate", + "fileSize", + "priority", + "audioFormat", + "comment", + "isEncrypted", + "jobNumber", + "assignees", + "status", + "transcriptionStartedDate", + "transcriptionFinishedDate" + ] + }, + "TasksResponse": { + "type": "object", + "properties": { + "pageNumber": { + "type": "number", + "description": "ページ番号(ページサイズごとに区切った何ページ目か。 ページ番号が存在しない場合は末尾のページ)" + }, + "pageSize": { + "type": "number", + "description": "ページサイズ(一度に何件のタスクを取得するか)" + }, + "total": { + "type": "number", + "description": "タスクの総件数" + }, + "tasks": { + "description": "音声ファイル/タスク一覧", + "type": "array", + "items": { + "$ref": "#/components/schemas/Task" + } + } + }, + "required": ["pageNumber", "pageSize", "total", "tasks"] + }, + "ChangeStatusResponse": { + "type": "object", + "properties": {} + }, + "RegisterRequest": { + "type": "object", + "properties": { + "pns": { + "type": "string", + "description": "wns or apns" + }, + "handler": { + "type": "string", + "description": "wnsのチャネルURI or apnsのデバイストークン" + } + }, + "required": ["pns", "handler"] + }, + "RegisterResponse": { + "type": "object", + "properties": {} } } } diff --git a/dictation_server/src/app.module.ts b/dictation_server/src/app.module.ts index 1355476..b2b6929 100644 --- a/dictation_server/src/app.module.ts +++ b/dictation_server/src/app.module.ts @@ -22,10 +22,12 @@ import { UsersRepositoryModule } from './repositories/users/users.repository.mod import { NotificationhubModule } from './gateways/notificationhub/notificationhub.module'; import { NotificationhubService } from './gateways/notificationhub/notificationhub.service'; import { NotificationModule } from './features/notification/notification.module'; -import { BlobModule } from './features/blob/blob.module'; -import { TaskService } from './features/task/task.service'; -import { TaskModule } from './features/task/task.module'; -import { TaskController } from './features/task/task.controller'; +import { FilesModule } from './features/files/files.module'; +import { FilesController } from './features/files/files.controller'; +import { FilesService } from './features/files/files.service'; +import { TasksService } from './features/tasks/tasks.service'; +import { TasksController } from './features/tasks/tasks.controller'; +import { TasksModule } from './features/tasks/tasks.module'; @Module({ imports: [ @@ -40,8 +42,10 @@ import { TaskController } from './features/task/task.controller'; CryptoModule, AdB2cModule, AccountsModule, - TaskModule, - UsersModule, + UsersModule, + FilesModule, + TasksModule, + UsersModule, SendGridModule, AccountsRepositoryModule, UsersRepositoryModule, @@ -61,23 +65,23 @@ import { TaskController } from './features/task/task.controller'; }), NotificationModule, NotificationhubModule, - BlobModule, - TaskModule, ], controllers: [ HealthController, AuthController, AccountsController, - TaskController, - UsersController, + UsersController, + FilesController, + TasksController, + UsersController, ], providers: [ AuthService, AccountsService, - TaskService, UsersService, NotificationhubService, - TaskService, + FilesService, + TasksService, ], }) export class AppModule { diff --git a/dictation_server/src/features/blob/blob.controller.spec.ts b/dictation_server/src/features/blob/blob.controller.spec.ts deleted file mode 100644 index d68d2c4..0000000 --- a/dictation_server/src/features/blob/blob.controller.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { BlobController } from './blob.controller'; -import { BlobService } from './blob.service'; - -describe('BlobController', () => { - let controller: BlobController; - const mockBlobService = {}; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [BlobController], - providers: [BlobService], - }) - .overrideProvider(BlobService) - .useValue(mockBlobService) - .compile(); - - controller = module.get(BlobController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/dictation_server/src/features/blob/blob.controller.ts b/dictation_server/src/features/blob/blob.controller.ts deleted file mode 100644 index b33d64a..0000000 --- a/dictation_server/src/features/blob/blob.controller.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Controller, Get, Headers, HttpStatus, Query } from '@nestjs/common'; -import { - ApiResponse, - ApiOperation, - ApiBearerAuth, - ApiTags, -} from '@nestjs/swagger'; -import { ErrorResponse } from '../../common/error/types/types'; -import { BlobService } from './blob.service'; -import { - AudioUploadLocationResponse, - AudioUploadLocationRequest, - AudioDownloadLocationResponse, - AudioDownloadLocationRequest, - TemplateDownloadLocationResponse, - TemplateDownloadLocationRequest, -} from './types/types'; - -@ApiTags('files') -@Controller('files') -export class BlobController { - constructor(private readonly blobService: BlobService) {} - @Get('audio/upload-location') - @ApiResponse({ - status: HttpStatus.OK, - type: AudioUploadLocationResponse, - description: '成功時のレスポンス', - }) - @ApiResponse({ - status: HttpStatus.UNAUTHORIZED, - description: '認証エラー', - type: ErrorResponse, - }) - @ApiResponse({ - status: HttpStatus.INTERNAL_SERVER_ERROR, - description: '想定外のサーバーエラー', - type: ErrorResponse, - }) - @ApiOperation({ operationId: 'uploadLocation' }) - @ApiBearerAuth() - async uploadLocation( - @Headers() headers, - @Query() query: AudioUploadLocationRequest, - ): Promise { - const {} = query; - // コンテナ作成処理の前にアクセストークンの認証を行う - // アップロード先を決定する国情報はトークンから取得する想定 - - return { url: '' }; - } - - @Get('audio/download-location') - @ApiResponse({ - status: HttpStatus.OK, - type: AudioDownloadLocationResponse, - description: '成功時のレスポンス', - }) - @ApiResponse({ - status: HttpStatus.UNAUTHORIZED, - description: '認証エラー', - type: ErrorResponse, - }) - @ApiResponse({ - status: HttpStatus.INTERNAL_SERVER_ERROR, - description: '想定外のサーバーエラー', - type: ErrorResponse, - }) - @ApiOperation({ operationId: 'downloadLocation' }) - @ApiBearerAuth() - async downloadLocation( - @Headers() headers, - @Query() body: AudioDownloadLocationRequest, - ): Promise { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { id } = body; - // コンテナ作成処理の前にアクセストークンの認証を行う - // - - return { url: '' }; - } - - @Get('template/download-location') - @ApiResponse({ - status: HttpStatus.OK, - type: TemplateDownloadLocationResponse, - description: '成功時のレスポンス', - }) - @ApiResponse({ - status: HttpStatus.UNAUTHORIZED, - description: '認証エラー', - type: ErrorResponse, - }) - @ApiResponse({ - status: HttpStatus.INTERNAL_SERVER_ERROR, - description: '想定外のサーバーエラー', - type: ErrorResponse, - }) - @ApiOperation({ operationId: 'downloadTemplateLocation' }) - @ApiBearerAuth() - async downloadTemplateLocation( - @Headers() headers, - @Query() body: TemplateDownloadLocationRequest, - ): Promise { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { audioFileId } = body; - // コンテナ作成処理の前にアクセストークンの認証を行う - - return { url: '' }; - } -} diff --git a/dictation_server/src/features/blob/blob.module.ts b/dictation_server/src/features/blob/blob.module.ts deleted file mode 100644 index 712a287..0000000 --- a/dictation_server/src/features/blob/blob.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Module } from '@nestjs/common'; -import { BlobService } from './blob.service'; -import { BlobController } from './blob.controller'; - -@Module({ - providers: [BlobService], - controllers: [BlobController], -}) -export class BlobModule {} diff --git a/dictation_server/src/features/blob/types/types.ts b/dictation_server/src/features/blob/types/types.ts deleted file mode 100644 index 6a6ca51..0000000 --- a/dictation_server/src/features/blob/types/types.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; - -export class AudioUploadLocationRequest {} - -export class AudioUploadLocationResponse { - @ApiProperty() - url: string; -} - -export class AudioDownloadLocationRequest { - @ApiProperty({ description: '音声ファイル情報をDBから取得するためのID' }) - id: string; -} - -export class AudioDownloadLocationResponse { - @ApiProperty() - url: string; -} - -export class TemplateDownloadLocationRequest { - @ApiProperty({ description: '文字起こし対象の音声ファイルID' }) - audioFileId: string; -} - -export class TemplateDownloadLocationResponse { - @ApiProperty() - url: string; -} diff --git a/dictation_server/src/features/files/files.controller.ts b/dictation_server/src/features/files/files.controller.ts index 1d104f6..f1add0b 100644 --- a/dictation_server/src/features/files/files.controller.ts +++ b/dictation_server/src/features/files/files.controller.ts @@ -1,4 +1,12 @@ -import { Controller, Get, Headers, HttpStatus, Query } from '@nestjs/common'; +import { + Body, + Controller, + Get, + Headers, + HttpStatus, + Post, + Query, +} from '@nestjs/common'; import { ApiResponse, ApiOperation, @@ -7,13 +15,136 @@ import { } from '@nestjs/swagger'; import { ErrorResponse } from '../../common/error/types/types'; import { FilesService } from './files.service'; -import { AudioNextRequest, AudioNextResponse } from './types/types'; +import { + AudioDownloadLocationRequest, + AudioDownloadLocationResponse, + AudioNextRequest, + AudioNextResponse, + AudioUploadFinishedRequest, + AudioUploadFinishedResponse, + AudioUploadLocationRequest, + AudioUploadLocationResponse, + TemplateDownloadLocationRequest, + TemplateDownloadLocationResponse, +} from './types/types'; @ApiTags('files') @Controller('files') export class FilesController { constructor(private readonly filesService: FilesService) {} + @ApiResponse({ + status: HttpStatus.OK, + type: AudioUploadFinishedResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.BAD_REQUEST, + description: '不正なパラメータ', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'createTask' }) + @Post('audio/upload-finished') + async uploadFinished( + @Body() body: AudioUploadFinishedRequest, + ): Promise { + console.log(body); + return { jobNumber: '00000001' }; + } + + @Get('audio/upload-location') + @ApiResponse({ + status: HttpStatus.OK, + type: AudioUploadLocationResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'uploadLocation' }) + @ApiBearerAuth() + async uploadLocation( + @Headers() headers, + @Query() query: AudioUploadLocationRequest, + ): Promise { + const {} = query; + // コンテナ作成処理の前にアクセストークンの認証を行う + // アップロード先を決定する国情報はトークンから取得する想定 + + return { url: '' }; + } + + @Get('audio/download-location') + @ApiResponse({ + status: HttpStatus.OK, + type: AudioDownloadLocationResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'downloadLocation' }) + @ApiBearerAuth() + async downloadLocation( + @Headers() headers, + @Query() body: AudioDownloadLocationRequest, + ): Promise { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { audioFileId } = body; + // コンテナ作成処理の前にアクセストークンの認証を行う + // + + return { url: '' }; + } + + @Get('template/download-location') + @ApiResponse({ + status: HttpStatus.OK, + type: TemplateDownloadLocationResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'downloadTemplateLocation' }) + @ApiBearerAuth() + async downloadTemplateLocation( + @Headers() headers, + @Query() body: TemplateDownloadLocationRequest, + ): Promise { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { audioFileId } = body; + // コンテナ作成処理の前にアクセストークンの認証を行う + + return { url: '' }; + } + @Get('audio/next') @ApiResponse({ status: HttpStatus.OK, @@ -39,6 +170,6 @@ export class FilesController { const { endedFileId } = body; console.log(endedFileId); - return { nextFileId: '1234' }; + return { nextFileId: 1234 }; } } diff --git a/dictation_server/src/features/files/types/types.ts b/dictation_server/src/features/files/types/types.ts index 782f554..1f6b38d 100644 --- a/dictation_server/src/features/files/types/types.ts +++ b/dictation_server/src/features/files/types/types.ts @@ -2,10 +2,86 @@ import { ApiProperty } from '@nestjs/swagger'; export class AudioNextRequest { @ApiProperty({ description: '文字起こし完了したタスクの音声ファイルID' }) - endedFileId: string; + endedFileId: number; } export class AudioNextResponse { - @ApiProperty({ description: 'OMDS Cloud上の次の音声ファイルID' }) - nextFileId: string; + @ApiProperty({ + description: 'ODMS Cloud上の次の音声ファイルID(存在しなければ空文字)', + }) + nextFileId: number; +} + +export class AudioUploadLocationRequest {} + +export class AudioUploadLocationResponse { + @ApiProperty() + url: string; +} + +export class AudioDownloadLocationRequest { + @ApiProperty({ description: '音声ファイル情報をDBから取得するためのID' }) + audioFileId: number; +} + +export class AudioDownloadLocationResponse { + @ApiProperty() + url: string; +} + +export class TemplateDownloadLocationRequest { + @ApiProperty({ description: '文字起こし対象の音声ファイルID' }) + audioFileId: number; +} + +export class TemplateDownloadLocationResponse { + @ApiProperty() + url: string; +} + +export class AudioUploadFinishedRequest { + @ApiProperty({ description: 'アップロード先Blob Storage(ファイル名含む)' }) + url: string; + @ApiProperty({ description: '自分自身(ログイン認証)したAuthorID' }) + authorId: string; + @ApiProperty({ description: '音声ファイル名' }) + fileName: string; + @ApiProperty({ + description: '音声ファイルの録音時間(yyyy-mm-ddThh:mm:ss.sss)', + }) + duration: string; + @ApiProperty({ + description: + '音声ファイルの録音作成日時(開始日時)(yyyy-mm-ddThh:mm:ss.sss)', + }) + createdDate: string; + @ApiProperty({ + description: '音声ファイルの録音作成終了日時(yyyy-mm-ddThh:mm:ss.sss)', + }) + completedDate: string; + @ApiProperty({ + description: '音声ファイルのアップロード日時(yyyy-mm-ddThh:mm:ss.sss)', + }) + uploadedDate: string; + @ApiProperty() + fileSize: string; + @ApiProperty({ description: '優先度 "00":Normal / "01":High' }) + priority: string; + @ApiProperty({ description: '録音形式: DSS/DS2(SP)/DS2(QP)' }) + audioFormat: string; + @ApiProperty() + comment: string; + @ApiProperty() + workType: string; + @ApiProperty({ minLength: 1, maxLength: 16 }) + optionItemLabel: string; + @ApiProperty({ minLength: 1, maxLength: 20 }) + optionItemValue: string; + @ApiProperty() + isEncrypted: boolean; +} + +export class AudioUploadFinishedResponse { + @ApiProperty({ description: '8桁固定の数字' }) + jobNumber: string; } diff --git a/dictation_server/src/features/task/task.controller.spec.ts b/dictation_server/src/features/task/task.controller.spec.ts deleted file mode 100644 index 160ee76..0000000 --- a/dictation_server/src/features/task/task.controller.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { TaskController } from './task.controller'; -import { TaskService } from './task.service'; - -describe('TaskController', () => { - let controller: TaskController; - const mockTaskervice = {}; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [TaskController], - providers: [TaskService], - }) - .overrideProvider(TaskService) - .useValue(mockTaskervice) - .compile(); - - controller = module.get(TaskController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/dictation_server/src/features/task/task.module.ts b/dictation_server/src/features/task/task.module.ts deleted file mode 100644 index 8e88d64..0000000 --- a/dictation_server/src/features/task/task.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TaskController } from './task.controller'; -import { TaskService } from './task.service'; - -@Module({ - imports: [], - controllers: [TaskController], - providers: [TaskService], -}) -export class TaskModule {} diff --git a/dictation_server/src/features/task/task.service.spec.ts b/dictation_server/src/features/task/task.service.spec.ts deleted file mode 100644 index 106fdb4..0000000 --- a/dictation_server/src/features/task/task.service.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { TaskService } from './task.service'; - -describe('TaskService', () => { - let service: TaskService; - const mockTaskService = {}; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [TaskService], - }) - .overrideProvider(TaskService) - .useValue(mockTaskService) - .compile(); - - service = module.get(TaskService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/dictation_server/src/features/task/task.service.ts b/dictation_server/src/features/task/task.service.ts deleted file mode 100644 index 0703d00..0000000 --- a/dictation_server/src/features/task/task.service.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class TaskService {} diff --git a/dictation_server/src/features/task/types/types.ts b/dictation_server/src/features/task/types/types.ts deleted file mode 100644 index ab60ad5..0000000 --- a/dictation_server/src/features/task/types/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; - - -export class ChangeStatusRequest { - @ApiProperty({ description: 'OMDS Cloud上の音声ファイルID' }) - audioFileId: string; -} - -export class ChangeStatusResponse {} diff --git a/dictation_server/src/features/tasks/tasks.controller.spec.ts b/dictation_server/src/features/tasks/tasks.controller.spec.ts new file mode 100644 index 0000000..73b5846 --- /dev/null +++ b/dictation_server/src/features/tasks/tasks.controller.spec.ts @@ -0,0 +1,23 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TasksController } from './tasks.controller'; +import { TasksService } from './tasks.service'; + +describe('TasksController', () => { + let controller: TasksController; + const mockTaskService = {}; + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [TasksController], + providers: [TasksService], + }) + .overrideProvider(TasksService) + .useValue(mockTaskService) + .compile(); + + controller = module.get(TasksController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/dictation_server/src/features/task/task.controller.ts b/dictation_server/src/features/tasks/tasks.controller.ts similarity index 69% rename from dictation_server/src/features/task/task.controller.ts rename to dictation_server/src/features/tasks/tasks.controller.ts index 19e2aa4..b5e99bc 100644 --- a/dictation_server/src/features/task/task.controller.ts +++ b/dictation_server/src/features/tasks/tasks.controller.ts @@ -1,19 +1,65 @@ -import { Body, Controller, Headers, HttpStatus, Post } from '@nestjs/common'; import { - ApiBearerAuth, - ApiOperation, + Controller, + Get, + Headers, + HttpStatus, + Param, + Post, + Query, +} from '@nestjs/common'; +import { ApiResponse, + ApiOperation, + ApiBearerAuth, ApiTags, } from '@nestjs/swagger'; -import { TaskService } from './task.service'; -import { ChangeStatusRequest, ChangeStatusResponse } from './types/types'; import { ErrorResponse } from '../../common/error/types/types'; +import { TasksService } from './tasks.service'; +import { + ChangeStatusRequest, + ChangeStatusResponse, + TasksRequest, + TasksResponse, +} from './types/types'; -@ApiTags('task') -@Controller('task') -export class TaskController { - constructor(private readonly taskService: TaskService) {} - @Post('checkout') +@ApiTags('tasks') +@Controller('tasks') +export class TasksController { + constructor(private readonly taskService: TasksService) {} + + @ApiResponse({ + status: HttpStatus.OK, + type: TasksResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'getTasks' }) + @ApiBearerAuth() + @Get() + async getTasks( + @Headers() headers, + @Query() body: TasksRequest, + ): Promise { + console.log(headers); + console.log(body); + return { + pageNumber: 1, + pageSize: 1, + total: 0, + tasks: [], + }; + } + + @Post(':audioFileId/checkout') @ApiResponse({ status: HttpStatus.OK, type: ChangeStatusResponse, @@ -38,14 +84,15 @@ export class TaskController { @ApiBearerAuth() async checkout( @Headers() headers, - @Body() body: ChangeStatusRequest, + @Param() params: ChangeStatusRequest, ): Promise { - const {} = body; + const { audioFileId } = params; + console.log(audioFileId); return {}; } - @Post('checkin') + @Post(':audioFileId/checkin') @ApiResponse({ status: HttpStatus.OK, type: ChangeStatusResponse, @@ -70,14 +117,15 @@ export class TaskController { @ApiBearerAuth() async checkin( @Headers() headers, - @Body() body: ChangeStatusRequest, + @Param() params: ChangeStatusRequest, ): Promise { - const {} = body; + const { audioFileId } = params; + console.log(audioFileId); return {}; } - @Post('cancel') + @Post(':audioFileId/cancel') @ApiResponse({ status: HttpStatus.OK, type: ChangeStatusResponse, @@ -102,14 +150,15 @@ export class TaskController { @ApiBearerAuth() async cancel( @Headers() headers, - @Body() body: ChangeStatusRequest, + @Param() params: ChangeStatusRequest, ): Promise { - const {} = body; + const { audioFileId } = params; + console.log(audioFileId); return {}; } - @Post('suspend') + @Post(':audioFileId/suspend') @ApiResponse({ status: HttpStatus.OK, type: ChangeStatusResponse, @@ -134,14 +183,15 @@ export class TaskController { @ApiBearerAuth() async suspend( @Headers() headers, - @Body() body: ChangeStatusRequest, + @Param() params: ChangeStatusRequest, ): Promise { - const {} = body; + const { audioFileId } = params; + console.log(audioFileId); return {}; } - @Post('send-back') + @Post(':audioFileId/send-back') @ApiResponse({ status: HttpStatus.OK, type: ChangeStatusResponse, @@ -166,14 +216,15 @@ export class TaskController { @ApiBearerAuth() async sendBack( @Headers() headers, - @Body() body: ChangeStatusRequest, + @Param() params: ChangeStatusRequest, ): Promise { - const {} = body; + const { audioFileId } = params; + console.log(audioFileId); return {}; } // TODO 操作としてarchiveの方が適切かもしれない - @Post('backup') + @Post(':audioFileId/backup') @ApiResponse({ status: HttpStatus.OK, type: ChangeStatusResponse, @@ -198,9 +249,10 @@ export class TaskController { @ApiBearerAuth() async backup( @Headers() headers, - @Body() body: ChangeStatusRequest, + @Param() params: ChangeStatusRequest, ): Promise { - const {} = body; + const { audioFileId } = params; + console.log(audioFileId); return {}; } diff --git a/dictation_server/src/features/tasks/tasks.module.ts b/dictation_server/src/features/tasks/tasks.module.ts new file mode 100644 index 0000000..29b72f3 --- /dev/null +++ b/dictation_server/src/features/tasks/tasks.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { TasksService } from './tasks.service'; +import { TasksController } from './tasks.controller'; + +@Module({ + providers: [TasksService], + controllers: [TasksController], +}) +export class TasksModule {} diff --git a/dictation_server/src/features/blob/blob.service.spec.ts b/dictation_server/src/features/tasks/tasks.service.spec.ts similarity index 56% rename from dictation_server/src/features/blob/blob.service.spec.ts rename to dictation_server/src/features/tasks/tasks.service.spec.ts index 8bd3902..cb48230 100644 --- a/dictation_server/src/features/blob/blob.service.spec.ts +++ b/dictation_server/src/features/tasks/tasks.service.spec.ts @@ -1,15 +1,15 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { BlobService } from './blob.service'; +import { TasksService } from './tasks.service'; -describe('BlobService', () => { - let service: BlobService; +describe('TasksService', () => { + let service: TasksService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [BlobService], + providers: [TasksService], }).compile(); - service = module.get(BlobService); + service = module.get(TasksService); }); it('should be defined', () => { diff --git a/dictation_server/src/features/blob/blob.service.ts b/dictation_server/src/features/tasks/tasks.service.ts similarity index 67% rename from dictation_server/src/features/blob/blob.service.ts rename to dictation_server/src/features/tasks/tasks.service.ts index 4e17e41..8d051eb 100644 --- a/dictation_server/src/features/blob/blob.service.ts +++ b/dictation_server/src/features/tasks/tasks.service.ts @@ -1,4 +1,4 @@ import { Injectable } from '@nestjs/common'; @Injectable() -export class BlobService {} +export class TasksService {} diff --git a/dictation_server/src/features/tasks/types/types.ts b/dictation_server/src/features/tasks/types/types.ts new file mode 100644 index 0000000..45a07ac --- /dev/null +++ b/dictation_server/src/features/tasks/types/types.ts @@ -0,0 +1,124 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class TasksRequest { + @ApiProperty({ + minimum: 1, + description: + 'ページ番号(ページサイズごとに区切った何ページ目を取得するか)', + }) + pageNumber: number; + @ApiProperty({ + minimum: 1, + description: 'ページサイズ(一度に何件のタスクを取得するか)', + }) + pageSize: number; +} + +export class Typist { + @ApiProperty({ + required: false, + description: 'TypistID(TypistIDかTypistGroupIDのどちらかに値が入る)', + }) + typistUserId?: number | undefined; + @ApiProperty({ + required: false, + description: 'TypistGroupID(TypistGroupIDかTypistIDのどちらかに値が入る)', + }) + typistGroupId?: number | undefined; + @ApiProperty({ description: 'Typist名 / TypistGroup名' }) + typistName: string; +} + +export class Task { + @ApiProperty({ description: 'ODMS Cloud上の音声ファイルID' }) + audioFileId: number; + @ApiProperty({ description: 'AuthorID' }) + authorId: string; + @ApiProperty() + workType: string; + @ApiProperty({ minLength: 1, maxLength: 16 }) + optionItemLabel: string; + @ApiProperty({ minLength: 1, maxLength: 20 }) + optionItemValue: string; + @ApiProperty({ description: 'アップロード先Blob Storage(ファイル名含む)' }) + url: string; + @ApiProperty({ description: '音声ファイル名' }) + fileName: string; + @ApiProperty({ + description: '音声ファイルの録音時間(yyyy-mm-ddThh:mm:ss.sss)', + }) + audioDuration: string; + @ApiProperty({ + description: '音声ファイルの録音開始日時(yyyy-mm-ddThh:mm:ss.sss)', + }) + audioCreatedDate: string; + @ApiProperty({ + description: '音声ファイルの録音終了日時(yyyy-mm-ddThh:mm:ss.sss)', + }) + audioFinishedDate: string; + @ApiProperty({ + description: '音声ファイルのアップロード日時(yyyy-mm-ddThh:mm:ss.sss)', + }) + audioUploadedDate: string; + @ApiProperty({ description: '音声ファイルのファイルサイズ' }) + fileSize: string; + @ApiProperty({ description: '音声ファイルの優先度 "00":Normal / "01":High' }) + priority: string; + @ApiProperty({ description: '録音形式: DSS/DS2(SP)/DS2(QP)' }) + audioFormat: string; + @ApiProperty({ description: 'コメント' }) + comment: string; + @ApiProperty() + isEncrypted: boolean; + @ApiProperty({ description: 'JOBナンバー' }) + jobNumber: string; + @ApiProperty({ + required: false, + description: '割り当てられたユーザー', + }) + typist?: Typist | undefined; + @ApiProperty({ + type: [Typist], + description: + '文字起こしに着手できる(チェックアウト可能な)、タスクにアサインされているグループ/個人の一覧', + }) + assignees: Typist[]; + @ApiProperty({ + description: + '音声ファイルのファイルステータス 1:Uploaded(Cancel) / 2:Pending / 3:InProgress / 4:Finished / 5:Backup', + }) + status: number; + @ApiProperty({ description: '文字起こし開始日時(yyyy-mm-ddThh:mm:ss.sss)' }) + transcriptionStartedDate: string; + @ApiProperty({ description: '文字起こし終了日時(yyyy-mm-ddThh:mm:ss.sss)' }) + transcriptionFinishedDate: string; +} + +export class TasksResponse { + @ApiProperty({ + description: + 'ページ番号(ページサイズごとに区切った何ページ目か。 ページ番号が存在しない場合は末尾のページ)', + }) + pageNumber: number; + @ApiProperty({ + description: 'ページサイズ(一度に何件のタスクを取得するか)', + }) + pageSize: number; + @ApiProperty({ + description: 'タスクの総件数', + }) + total: number; + + @ApiProperty({ + type: [Task], + description: '音声ファイル/タスク一覧', + }) + tasks: Task[]; +} + +export class ChangeStatusRequest { + @ApiProperty({ description: 'ODMS Cloud上の音声ファイルID' }) + audioFileId: number; +} + +export class ChangeStatusResponse {}