댓글 및 제안 사용하기

Google Docs를 사용하면 공동작업자가 댓글을 작성하고 승인을 기다리는 지연된 수정사항 역할을 하는 제안을 하여 공동작업할 수 있습니다.

API를 사용하여 문서 텍스트 내에서 제안된 변경사항을 인라인으로 볼 수 있습니다. 개발자 프리뷰에서는 댓글 및 제안 대화목록을 프로그래매틱 방식으로 읽고, 만들고, 답장하고, 업데이트하거나 삭제할 수도 있습니다.

documents.get 메서드를 사용하여 문서 콘텐츠를 가져올 때 콘텐츠에 해결되지 않은 제안이 포함될 수 있습니다. 이 documents.get제안을 나타내는 방식을 제어하려면 선택적 SuggestionsViewMode 매개변수를 사용하세요. 이 매개변수에는 다음과 같은 필터 조건을 사용할 수 있습니다.

  • SUGGESTIONS_INLINE으로 콘텐츠를 가져오므로 삭제 또는 삽입 대기 중인 텍스트가 문서에 표시됩니다.
  • 모든 제안이 수락된 상태로 콘텐츠를 미리보기로 가져옵니다.
  • 제안 없이 모든 제안이 거부된 상태로 콘텐츠를 미리보기로 가져옵니다.

SuggestionsViewMode를 제공하지 않으면 Google Docs API는 현재 사용자의 권한에 적합한 기본 설정을 사용합니다.

문서를 가져올 때 댓글을 포함할지 여부를 제어하려면 선택적 commentsViewMode 매개변수를 사용하세요. commentsViewModeCOMMENTS_VIEW_MODE_INCLUDED로 설정하는 경우 includeTabsContenttrue로 설정해야 합니다. 또한 tabs 필드 (또는 하위 필드)를 참조하는 필드 마스크를 사용하는 경우 API는 includeTabsContenttrue로 설정한 것처럼 요청을 암시적으로 처리합니다.

제안 및 색인

SuggestionsViewMode가 중요한 한 가지 이유는 다음 예와 같이 제안이 있는지 여부에 따라 응답의 색인이 다를 수 있기 때문입니다.

제안이 있는 콘텐츠 제안이 없는 콘텐츠
{
 "tabs": [
  {
   "documentTab": {
    "body": {
     "content": [
      {
       "startIndex": 1,
       "endIndex": 31,
       "paragraph": {
        "elements": [
         {
          "startIndex": 1,
          "endIndex": 31,
          "textRun": {
           "content": "Text preceding the suggestion\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      },
      {
       "startIndex": 31,
       "endIndex": 51,
       "paragraph": {
        "elements": [
         {
          "startIndex": 31,
          "endIndex": 50,
          "textRun": {
           "content": "Suggested insertion",
           "suggestedInsertionIds": [
            "suggest.vcti8ewm4mww"
           ],
           "textStyle": {}
          }
         },
         {
          "startIndex": 50,
          "endIndex": 51,
          "textRun": {
           "content": "\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      },
      {
       "startIndex": 51,
       "endIndex": 81,
       "paragraph": {
        "elements": [
         {
          "startIndex": 51,
          "endIndex": 81,
          "textRun": {
           "content": "Text following the suggestion\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      }
     ]
    }
   }
  }
 ]
},

{
 "tabs": [
  {
   "documentTab": {
    "body": {
     "content": [
      {
       "startIndex": 1,
       "endIndex": 31,
       "paragraph": {
        "elements": [
         {
          "startIndex": 1,
          "endIndex": 31,
          "textRun": {
           "content": "Text preceding the suggestion\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      },
      {
       "startIndex": 31,
       "endIndex": 32,
       "paragraph": {
        "elements": [
         {
          "startIndex": 31,
          "endIndex": 32,
          "textRun": {
           "content": "\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      },
      {
       "startIndex": 32,
       "endIndex": 62,
       "paragraph": {
        "elements": [
         {
          "startIndex": 32,
          "endIndex": 62,
          "textRun": {
           "content": "Text following the suggestion\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      }
     ]
    }
   }
  }
 ]
},

앞의 응답에서 'Text following the suggestion' 줄이 포함된 단락은 SuggestionsViewMode를 사용할 때의 차이점을 보여줍니다. 값이 SUGGESTIONS_INLINE으로 설정된 경우 startIndexParagraphElement 는 51에서 시작하고 endIndex는 81에서 중지됩니다. 제안이 없으면 startIndexendIndex 범위는 32~62입니다.

제안 없이 콘텐츠 가져오기

다음 부분 코드 샘플은 SuggestionsViewMode 매개변수를 PREVIEW_WITHOUT_SUGGESTIONS로 설정하여 제안이 있는 경우 모든 제안이 거부된 상태로 문서를 미리보기로 가져오는 방법을 보여줍니다.

자바

final string SUGGEST_MODE = "PREVIEW_WITHOUT_SUGGESTIONS";
Document doc =
    service
        .documents()
        .get(DOCUMENT_ID)
        .setIncludeTabsContent(true)
        .setSuggestionsViewMode(SUGGEST_MODE)
        .execute();

Python

SUGGEST_MODE = "PREVIEW_WITHOUT_SUGGESTIONS"
result = (
  service.documents()
  .get(
      documentId=DOCUMENT_ID,
      includeTabsContent=True,
      suggestionsViewMode=SUGGEST_MODE,
  )
  .execute()
)

SuggestionsViewMode 매개변수를 생략하는 것은 DEFAULT_FOR_CURRENT_ACCESS를 파라미터 값으로 제공하는 것과 같습니다.

스타일 제안

문서에 스타일 제안 이 있을 수도 있습니다. 이러한 제안은 콘텐츠 변경이 아닌 서식 및 프레젠테이션에 대한 변경사항입니다.

텍스트 삽입 또는 삭제와 달리 이러한 제안은 색인을 오프셋하지는 않지만 TextRun을 더 작은 청크로 나눌 수는 있습니다. 제안된 스타일 변경에 대한 주석만 추가합니다.

이러한 주석 중 하나는 SuggestedTextStyle, 두 부분으로 구성된 것입니다.

  • textStyle: 제안된 변경 후 텍스트의 스타일을 설명하지만 변경된 내용은 설명하지 않습니다.

  • textStyleSuggestionState은(는) 제안이 textStyle의 필드를 변경하는 방법을 나타냅니다.

제안된 스타일 변경이 포함된 다음 문서 탭 추출에서 이를 확인할 수 있습니다.

[01] "paragraph": {
[02]    "elements": [
[03]        {
[04]            "endIndex": 106,
[05]            "startIndex": 82,
[06]            "textRun": {
[07]                "content": "Some text that does not ",
[08]                "textStyle": {}
[09]            }
[10]        },
[11]        {
[12]            "endIndex": 115,
[13]            "startIndex": 106,
[14]            "textRun": {
[15]                "content": "initially",
[16]                "suggestedTextStyleChanges": {
[17]                    "suggest.xymysbs9zldp": {
[18]                        "textStyle": {
[19]                            "backgroundColor": {},
[20]                            "baselineOffset": "NONE",
[21]                            "bold": true,
[22]                            "fontSize": {
[23]                                "magnitude": 11,
[24]                                "unit": "PT"
[25]                            },
[26]                            "foregroundColor": {
[27]                                "color": {
[28]                                    "rgbColor": {}
[29]                                }
[30]                            },
[31]                            "italic": false,
[32]                            "smallCaps": false,
[33]                            "strikethrough": false,
[34]                            "underline": false
[35]                        },
[36]                        "textStyleSuggestionState": {
[37]                            "boldSuggested": true,
[38]                            "weightedFontFamilySuggested": true
[39]                        }
[40]                    }
[41]                },
[42]                "textStyle": {
[43]                    "italic": true
[44]                }
[45]            }
[46]        },
[47]        {
[48]            "endIndex": 143,
[49]            "startIndex": 115,
[50]            "textRun": {
[51]                "content": " contain any boldface text.\n",
[52]                "textStyle": {}
[53]            }
[54]        }
[55]    ],
[56]    "paragraphStyle": {
[57]        "direction": "LEFT_TO_RIGHT",
[58]        "namedStyleType": "NORMAL_TEXT"
[59]    }
[60] }

앞의 샘플에서 단락은 6, 14, 50번째 줄에서 시작하는 세 개의 텍스트 실행으로 구성됩니다. 중간 텍스트 실행을 검사합니다.

  • 16번째 줄: suggestedTextStyleChanges 객체가 있습니다.
  • 18번째 줄: textStyle은 다양한 서식을 지정합니다.
  • 36번째 줄: textStyleSuggestionState는 이 사양의 굵은 부분만 제안이었음을 알려줍니다.
  • 42번째 줄: 이 텍스트 실행의 기울임꼴 스타일은 현재 문서의 일부이며 제안의 영향을 받지 않습니다.

textStyleSuggestionState에서 true로 설정된 스타일 기능만 제안의 일부입니다.

댓글 만들기 및 관리

`documents.batchUpdate` 메서드를 사용하여 댓글과 답글을 프로그래매틱 방식으로 추가하고, 댓글을 수정하고, 댓글 또는 답글을 삭제할 수 있습니다.

댓글 또는 제안과 관련된 일괄 업데이트를 실행할 때는 잠재적인 부분적 오류를 모니터링해야 합니다. 자세한 내용은 댓글 및 제안 업데이트 상태를 참고하세요.

댓글 삽입

댓글 대화목록을 삽입하려면 InsertCommentRequest 객체를 사용합니다. 댓글 텍스트 콘텐츠와 댓글이 첨부된 앵커 위치 (예: 범위)를 제공해야 합니다.

다음 JSON 예는 지정된 범위에 할당되지 않은 댓글 대화목록을 추가합니다.

{
  "requests": [
    {
      "insertComment": {
        "content": "This is a comment added via the API.",
        "range": {
          "startIndex": 10,
          "endIndex": 25
        }
      }
    }
  ]
}

assigneeEmailAddress 필드에 이메일을 제공하여 특정 사용자에게 댓글을 할당할 수 있습니다.

{
  "requests": [
    {
      "insertComment": {
        "content": "Please review this paragraph.",
        "assigneeEmailAddress": "user@example.com",
        "range": {
          "startIndex": 10,
          "endIndex": 25
        }
      }
    }
  ]
}

답글 추가 또는 조치 취하기

댓글 또는 제안 대화목록에 답글을 달거나 대화목록을 해결 또는 다시 열려면 AddCommentReplyRequest를 사용합니다.

답글은 Post 객체로 표시됩니다. Post 객체에는 답글 content가 포함되어 있으며 선택적으로 commentAction(대화목록을 RESOLVE 또는 REOPEN하기 위한)을 지정할 수 있습니다.

Post 객체에서 새 assigneeEmail을 지정하여 댓글 대화목록을 다시 할당할 수도 있습니다.

다음 샘플은 기존 댓글 대화목록에 답글을 답니다.

{
  "requests": [
    {
      "addCommentReply": {
        "commentId": "comment_thread_id",
        "post": {
          "content": "Replying to the comment thread."
        }
      }
    }
  ]
}

다음 샘플은 콘텐츠가 필요하지 않은 댓글 대화목록을 해결합니다.

{
  "requests": [
    {
      "addCommentReply": {
        "commentId": "comment_thread_id",
        "post": {
          "commentAction": "RESOLVE"
        }
      }
    }
  ]
}

다음 JSON 샘플은 댓글 대화목록을 다시 할당하는 방법을 보여줍니다.

{
  "requests": [
    {
      "addCommentReply": {
        "commentId": "comment_thread_id",
        "post": {
          "content": "Replying to the comment thread.",
          "assigneeEmail": "user@example.com"
        }
      }
    }
  ]
}

게시물 수정하기

작성한 게시물의 텍스트 콘텐츠를 수정하려면 UpdateCommentPostRequest를 사용합니다. 대화목록 ID (commentId 또는 suggestionId), 수정하려는 게시물의 postId, 새 일반 텍스트 content를 지정해야 합니다.

제안 대화목록의 헤드 게시물은 수정할 수 없습니다 (제안 모드 수정으로 생성됨).

{
  "requests": [
    {
      "updateCommentPost": {
        "commentId": "comment_thread_id",
        "postId": "post_id",
        "content": "This is the updated comment text."
      }
    }
  ]
}

댓글 및 답글 삭제

  • 댓글 대화목록 삭제: 전체 댓글 대화목록을 삭제하려면 DeleteCommentRequest를 사용합니다. 대화목록의 헤드 게시물 작성자인 경우에만 댓글 대화목록을 삭제할 수 있습니다.
  • 답글 삭제: 특정 답글 게시물을 삭제하려면 DeleteCommentReplyRequest를 사용합니다. 작성한 답글만 삭제할 수 있습니다. 작업 또는 할당자가 포함된 답글 게시물은 삭제할 수 없습니다.

다음 샘플은 댓글 대화목록을 삭제합니다.

{
  "requests": [
    {
      "deleteComment": {
        "commentId": "comment_thread_id"
      }
    }
  ]
}

제안 작성 및 제안 대화목록 관리

직접 수정하는 대신 수정을 제안으로 작성하고 제안 대화목록을 프로그래매틱 방식으로 수락, 거부 또는 삭제할 수 있습니다.

제안과 관련된 일괄 업데이트를 실행할 때는 잠재적인 부분적 오류를 모니터링해야 합니다. 자세한 내용은 댓글 및 제안 업데이트 상태를 참고하세요.

제안 모드를 사용하여 제안 만들기

수정을 제안으로 적용하려면 일괄 업데이트 요청에서 WriteControl 객체의 writeMode 필드를 SUGGEST로 설정합니다. 요청의 모든 업데이트는 제안으로 처리됩니다.

{
  "requests": [
    {
      "insertText": {
        "text": "suggested insertion text",
        "location": {
          "index": 1
        }
      }
    }
  ],
  "writeControl": {
    "writeMode": "SUGGEST"
  }
}

제안 모드에서 지원되지 않는 요청

WriteMode.SUGGEST를 사용하는 경우 다음 요청 유형은 지원되지 않으며 오류를 반환합니다.

  • AddDocumentTab
  • CreateNamedRange
  • DeleteFooter
  • DeleteHeader
  • DeleteNamedRange
  • DeleteTab
  • UpdateDocumentTabProperties
  • UpdateTableColumnProperties

또한 문서 형식 또는 머리글 및 바닥글 설정에 대한 변경사항을 제안할 수 없습니다. UpdateDocumentStyle에서 다음 스타일 유형에는 제안이 지원되지 않습니다.

  • documentFormat
  • useEvenPageHeaderFooter
  • useFirstPageHeaderFooter

제안 대화목록 수락, 거부 또는 삭제

다음 요청을 사용하여 제안 대화목록을 관리할 수 있습니다.

  • 제안 수락: 제안을 수락하려면 AcceptSuggestionRequest를 사용하세요. 그러려면 문서에 대한 수정 액세스 권한이 필요합니다.
  • 제안 거부: RejectSuggestionRequest를 사용하여 제안을 거부합니다. 그러려면 문서에 대한 수정 액세스 권한이 있거나 제안 작성자여야 합니다.
  • 제안 삭제: DeleteSuggestionRequest를 사용하여 제안을 삭제합니다. 그러려면 제안 작성자여야 합니다.

다음 샘플은 제안 대화목록을 수락합니다.

{
  "requests": [
    {
      "acceptSuggestion": {
        "suggestionId": "suggestion_thread_id"
      }
    }
  ]
}

댓글 및 제안 업데이트 상태

댓글 삽입, 답글 추가 또는 제안과 같이 댓글 또는 제안 대화목록을 저장해야 하는 요청은 부분적 오류가 발생할 수 있습니다. 이러한 경우 텍스트 삽입 또는 삭제와 같은 문서 모델 변경사항이 Docs 모델에 성공적으로 커밋될 수 있지만 연결된 댓글 또는 제안은 저장하지 못할 수 있습니다.

BatchUpdateDocumentResponsecommentUpdateState 필드를 확인하여 댓글 또는 제안 업데이트가 성공적으로 적용되었는지 확인할 수 있습니다.

다음 상태가 CommentUpdateState에 반환됩니다.

  • NO_UPDATES_REQUESTED: 일괄 작업에서 댓글 또는 제안 업데이트가 요청되지 않았습니다.
  • ALL_SAVED: 요청된 모든 댓글 또는 제안 업데이트가 성공적으로 적용되었습니다.
  • ALL_FAILED_UNKNOWN_REASON: Docs 모델 변경사항이 커밋되었을 수 있지만 요청된 모든 댓글 또는 제안 업데이트를 저장하지 못했습니다.