Google Calendar API v3 จะส่งคืน BadRequest เสมอเมื่อสร้างกิจกรรม

Aug 18 2020

ฉันสร้างปฏิทินที่แชร์และต้องการเพิ่มกิจกรรมในปฏิทิน

[email protected]ฉันสร้างโครงการและการตั้งค่าบัญชีบริการ

แล้วฉันจะแชร์ปฏิทินเพื่อบัญชีผู้ใช้บริการเป็นเจ้าของ

จากนั้นฉันก็สังเกตเห็น

บัญชีบริการต้องเพิ่มปฏิทินที่แชร์ด้วยตนเอง

ตามที่อธิบายไว้ที่นี่ https://stackoverflow.com/a/62232361/298430 และ https://issuetracker.google.com/issues/148804709

ดังนั้นฉันจึงเขียนรหัส:

 @Test
  fun addCalendarToServiceAccount() {

    val calList1: CalendarList = calendar.calendarList().list().execute()
    logger.info("calList1 = {}", calList1)

    val inserted = calendar.calendarList().insert(CalendarListEntry().setId(calendarId)).execute()
    logger.info("inserted = {}", inserted)

    val calList2: CalendarList = calendar.calendarList().list().execute()
    logger.info("calList2 = {}", calList2)
  }

มันทำงานได้อย่างสมบูรณ์ เมื่อเรียกครั้งแรกฉันเห็นcalList1ว่างเปล่าและcalList2มีบางอย่างอยู่

จากนั้นฉันแทรกเหตุการณ์หนึ่งลงในปฏิทินด้วยตนเอง (ด้วย Google ปฏิทิน WEB UI) ฉันต้องการตรวจสอบว่าฉันสามารถดึงเหตุการณ์ได้หรือไม่:

@Test
  fun listEvents() {
    val events: Events = calendar.events().list(calendarId).execute()
    logger.info("events = {}", events)
    events.items.forEachIndexed { index, e ->
      logger.info("Event [index = {}] , event = {}", index, e)
    }
  }

มันยังใช้งานได้

{
   "accessRole":"owner",
   "defaultReminders":[

   ],
   "etag":"\"xxx\"",
   "items":[
      {
         "created":"2020-08-17T17:51:21.000Z",
         "creator":{
            "email":"[email protected]"
         },
         "end":{
            "date":"2020-08-20"
         },
         "etag":"\"xxx\"",
         "htmlLink":"https://www.google.com/calendar/event?eid=xxx",
         "iCalUID":"[email protected]",
         "id":"xxx",
         "kind":"calendar#event",
         "organizer":{
            "displayName":"xxx",
            "email":"[email protected]",
            "self":true
         },
         "reminders":{
            "useDefault":false
         },
         "sequence":0,
         "start":{
            "date":"2020-08-19"
         },
         "status":"confirmed",
         "summary":"xxx  test1",
         "transparency":"transparent",
         "updated":"2020-08-18T01:07:54.441Z"
      }
   ],
   "kind":"calendar#events",
   "nextSyncToken":"xxx",
   "summary":"xxx",
   "timeZone":"Asia/Taipei",
   "updated":"2020-08-18T01:07:54.688Z"
}

จากนั้นฉันต้องการแทรกบางอย่างโดยทางโปรแกรมเช่นตัวอย่าง API แสดง:

@Test
  fun testInsertEvent() {
    val now = LocalDateTime.now().withSecond(0).withNano(0)
    val zoneId = ZoneId.of("Asia/Taipei")
    val fromDate = Date.from(now.atZone(zoneId).toInstant())
    val endDate = Date.from(now.plusMinutes(60).atZone(zoneId).toInstant())

    val event = Event()
      .setSummary("Google I/O 2015")
      .setLocation("800 Howard St., San Francisco, CA 94103")
      .setDescription("A chance to hear more about Google's developer products.")
      .setStart(EventDateTime().setDate(DateTime(fromDate, TimeZone.getTimeZone(zoneId))))
      .setEnd(EventDateTime().setDate(DateTime(endDate, TimeZone.getTimeZone(zoneId))))

    logger.info("before insert event : {}", event)

    val eventResult: Event = calendar.events().insert(calendarId, event).execute()
    logger.info("eventResult = {}", eventResult)
  }

ฉันสามารถเห็นไคลเอ็นต์ POST ไปยังตำแหน่งปลายทางของ google'e อย่างแท้จริง:

ร่างกายคือ:

{
   "description":"A chance to hear more about Google's developer products.",
   "end":{
      "date":"2020-08-18T11:32:00.000+08:00"
   },
   "location":"800 Howard St., San Francisco, CA 94103",
   "start":{
      "date":"2020-08-18T10:32:00.000+08:00"
   },
   "summary":"Google I/O 2015"
}

แต่ Google ตอบกลับ 400 BadRequest โดยไม่มีคำอธิบายเพิ่มเติม:

2020-08-18 10:32:15.974 [main] INFO  c.g.a.c.h.HttpResponse - -------------- RESPONSE --------------
HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
Alt-Svc: h3-29=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Server: ESF
X-Content-Type-Options: nosniff
Pragma: no-cache
Date: Tue, 18 Aug 2020 02:32:15 GMT
X-Frame-Options: SAMEORIGIN
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Encoding: gzip
Vary: Referer
Vary: X-Origin
Vary: Origin
Expires: Mon, 01 Jan 1990 00:00:00 GMT
X-XSS-Protection: 0
Content-Type: application/json; charset=UTF-8

2020-08-18 10:32:15.980 [main] INFO  c.g.a.c.u.LoggingByteArrayOutputStream - Total: 171 bytes
2020-08-18 10:32:15.980 [main] INFO  c.g.a.c.u.LoggingByteArrayOutputStream - {
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "badRequest",
    "message": "Bad Request"
   }
  ],
  "code": 400,
  "message": "Bad Request"
 }
}

ฉันใช้เดียวกันปฏิทินเช่นสามารถประสบความสำเร็จaddCalendarToServiceAccount()(เป็นowner) listEvents()และ แต่เกิดอะไรขึ้นเมื่อแทรกเหตุการณ์? ฉันพลาดอะไรไปหรือเปล่า?

ฟิลด์อื่น ๆ จะเริ่มต้นดังนี้:

  @Value("\${google.calendar.id}") private lateinit var calendarId: String @Value("\${google.calendar.apiKey}")
  private lateinit var apiKey : String

  private val httpTransport: HttpTransport by lazy {
    GoogleNetHttpTransport.newTrustedTransport()
  }

  private val jacksonFactory: JsonFactory by lazy {
    JacksonFactory.getDefaultInstance()
  }

  private val saCredentials: GoogleCredentials by lazy {
    javaClass.getResourceAsStream("/chancer-d1de03c4c25a.json").use { iStream ->
      ServiceAccountCredentials.fromStream(iStream)
        .createScoped(listOf(
          "https://www.googleapis.com/auth/cloud-platform",
          *CalendarScopes.all().toTypedArray()
        ))
    }.apply {
      refreshIfExpired()
    }
  }


  private val requestInitializer: HttpRequestInitializer by lazy {
    HttpCredentialsAdapter(saCredentials)
  }

  private val calendar: Calendar by lazy {
    Calendar.Builder(httpTransport, jacksonFactory, requestInitializer)
      .build()
  }

สภาพแวดล้อม:

    <java.version>1.8</java.version>
    <kotlin.version>1.4.0</kotlin.version>


    <dependency>
      <groupId>com.google.api-client</groupId>
      <artifactId>google-api-client</artifactId>
      <version>1.30.10</version>
    </dependency>
    <dependency>
      <groupId>com.google.apis</groupId>
      <artifactId>google-api-services-calendar</artifactId>
      <version>v3-rev20200610-1.30.10</version>
    </dependency>
    <dependency>
      <groupId>com.google.auth</groupId>
      <artifactId>google-auth-library-oauth2-http</artifactId>
      <version>0.21.1</version>
    </dependency>

คำตอบ

2 RafaGuillermo Aug 18 2020 at 17:14

ตอบ:

คุณต้องใช้start.dateTimeและend.dateTimeมากกว่าstart.dateและend.date

แก้ไข:

ตามเอกสาร :

end.date: วันที่ในรูปแบบ "yyyy-mm-dd" หากเป็นเหตุการณ์ตลอดทั้งวัน

end.dateTime: เวลาเป็นค่าวันที่ - เวลารวม (จัดรูปแบบตาม RFC3339) โซนเวลาชดเชยจะต้องเว้นแต่โซนเวลาที่มีการระบุไว้อย่างชัดเจนในเขตเวลา

start.date: วันที่ในรูปแบบ "yyyy-mm-dd" หากเป็นเหตุการณ์ตลอดทั้งวัน

start.dateTime: เวลาเป็นค่าวันที่ - เวลารวม (จัดรูปแบบตาม RFC3339) โซนเวลาชดเชยจะต้องเว้นแต่โซนเวลาที่มีการระบุไว้อย่างชัดเจนในเขตเวลา

ดังนั้นคุณต้องเปลี่ยนวิธีการตั้งค่าวันที่และเวลาจาก:

EventDateTime().setDate(DateTime(fromDate, TimeZone.getTimeZone(zoneId))))

ถึง:

EventDateTime().setDateTime(DateTime(fromDate, TimeZone.getTimeZone(zoneId))))

ซึ่งจะเปลี่ยนเนื้อหาคำขอเป็น:

{
  "description": "A chance to hear more about Google's developer products.",
  "end": {
      "dateTime": "2020-08-18T11:32:00.000+08:00" // modified
  },
  "location": "800 Howard St., San Francisco, CA 94103",
  "start": {
    "dateTime": "2020-08-18T10:32:00.000+08:00" // modified
  },
  "summary": "Google I/O 2015"
}

คุณสามารถดูเอกสารสำหรับวิธีการนี้ที่นี่

ฉันหวังว่านี่จะเป็นประโยชน์กับคุณ!

อ้างอิง:

  • เหตุการณ์: แทรก | API ปฏิทิน | Google Developers
  • RFC 3339 - วันที่และเวลาบนอินเทอร์เน็ต: การประทับเวลา
  • EventDateTime (Calendar API v3-rev20200610-1.30.10)