0
votes

I am trying to create event from server using java.

Here is my code for the same.

private static final String APPLICATION_NAME = "Google Calendar API Java Quickstart";
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final String TOKENS_DIRECTORY_PATH = "tokens";

private static final List<String> SCOPES = Collections.singletonList(CalendarScopes.CALENDAR);
private static final String CREDENTIALS_FILE_PATH = "/credentials.json";

private static final String projfilepath = "/quickstart-foxmatrix.json";

private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws Exception {
    // Load client secrets.

    InputStream in = CalendarQuickstart.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
    if (in == null) {
        throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
    }

    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

    // Build flow and trigger user authorization request.
    GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
            clientSecrets, SCOPES)
                    .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                    .setAccessType("offline").build();
    LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(9000).build();
    return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
}

public static void main(String... args) throws Exception {
    // Build a new authorized API client service.
    final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();

    InputStream in = CalendarQuickstart.class.getResourceAsStream(projfilepath);

    GoogleCredential credential = GoogleCredential.fromStream(in)
            .createScoped(Collections.singleton(CalendarScopes.CALENDAR));

    Calendar service = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
            .setApplicationName(APPLICATION_NAME).build();
    CalendarQuickstart obj = new CalendarQuickstart();
    obj.createEvent(service);
}

public String createEvent(Calendar service) throws IOException {
    Event event = new Event().setSummary("New Event")
            .setDescription("A chance to hear more about Google's developer products.");

    DateTime startDateTime = new DateTime("2020-02-04T09:00:00-07:00");
    EventDateTime start = new EventDateTime().setDateTime(startDateTime);
    event.setStart(start);

    DateTime endDateTime = new DateTime("2020-02-04T17:00:00-07:00");
    EventDateTime end = new EventDateTime().setDateTime(endDateTime);
    event.setEnd(end);

    EventAttendee[] attendees = new EventAttendee[] {
            new EventAttendee().setEmail("[email protected]"),
            new EventAttendee().setEmail("[email protected]"), };
    event.setAttendees(Arrays.asList(attendees));

    EventReminder[] reminderOverrides = new EventReminder[] {
            new EventReminder().setMethod("email").setMinutes(24 * 60),
            new EventReminder().setMethod("popup").setMinutes(10), };
    Event.Reminders reminders = new Event.Reminders().setUseDefault(false)
            .setOverrides(Arrays.asList(reminderOverrides));
    event.setReminders(reminders);

    String calendarId = "primary";
    event = service.events().insert(calendarId, event).execute();
    System.out.printf("Event created: %s\n", event.getHtmlLink());
    event.getHangoutLink();
    return event.getHtmlLink();
}

i am using my service account credentials from json file.

I am using google client library for api calling.

I have also check my dashboard and the limit for api call is 100/sec. and there is no trafic shown for the api call. Still when i am trying to create an event it is showing use limit exceeded.

full error

Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden { "code" : 403, "errors" : [ { "domain" : "usageLimits", "message" : "Calendar usage limits exceeded.", "reason" : "quotaExceeded" } ], "message" : "Calendar usage limits exceeded." }

2
whats the full error message?DaImTo
isnt GoogleAuthorizationCodeFlow.Builder for Oauth2 not service accounts.DaImTo
Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden { "code" : 403, "errors" : [ { "domain" : "usageLimits", "message" : "Calendar usage limits exceeded.", "reason" : "quotaExceeded" } ], "message" : "Calendar usage limits exceeded." } @DaImToRishabh Sharma
I am not using GoogleAuthorizationFlow as you can see that function is not call to get credentials object. @DaImToRishabh Sharma
You cannot create events with attendees with a Service Account if you're not impersonating a user. Do you want to create an event on behalf of a user?Iamblichus

2 Answers

1
votes

You are getting this error because you are trying to create an event with attendees without using account impersonation, and doing this is currently not possible, as you can see in this issue in Google Issue Tracker.

If this was possible, you could first share your calendar with the Service Account and then add the event. But because this is not possible, you should use the Service Account to impersonate yourself: it should add the event on behalf of you.

(Important note: if you use a Service Account without impersonation and set the calendarId to primary, as in the code you shared, you won't add the event to your primary calendar, but to the Service Account's primary calendar. A Service Account has its own primary Calendar, its own Drive, etc. which is not the same as your primary Calendar, your Drive, etc.).

Workflow:

If you want to use a Service Account to reach a resource on behalf of you, you have to do the following:

  • Grant domain-wide delegation to the Service Account by following the steps specified here. Add the service account ID as Client Name and https://www.googleapis.com/auth/calendar as a scope in Manage API client access.
  • Download the credentials corresponding to the Service Account (in the sample I provide below, P12 is used instead of JSON).
  • Use the Service Account to impersonate yourself by indicating your email address when building the credentials, as indicated in the sample below.

You could build your credentials the following way:

GoogleCredential credential = new GoogleCredential.Builder()
    .setTransport(httpTransport)
    .setJsonFactory(JSON_FACTORY)
    .setServiceAccountId("service-account@email-address") // Service account email
    .setServiceAccountPrivateKeyFromP12File(new File("your-credentials.p12"))
    .setServiceAccountScopes(Collections.singleton(CalendarScopes.CALENDAR))
    .setServiceAccountUser("user@email-address") // Your email address (address of the user you want to impersonate)
    .build();

Reference:

I hope this is of any help.

0
votes

You are using the Code for Oauth2 not for service accounts the Google analytics api has a very good service account tutorial for java Quickstart service account java shouldn't be to hard to swap it over to calendar.

private static Calendar initializeCalendar() throws GeneralSecurityException, IOException {

    HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    GoogleCredential credential = GoogleCredential
        .fromStream(new FileInputStream(KEY_FILE_LOCATION))
        .createScoped(CalendarScopes.CALENDAR));

    // Construct the Analytics service object.
    return new Calendar.Builder(httpTransport, JSON_FACTORY, credential)
        .setApplicationName(APPLICATION_NAME).build();
  }


public static void main(String... args) throws IOException, GeneralSecurityException {
    // Build a new authorized API client service.
    Calendar service = initializeCalendar();

    // List the next 10 events from the primary calendar.
    DateTime now = new DateTime(System.currentTimeMillis());
    Events events = service.events().list("primary")
            .setMaxResults(10)
            .setTimeMin(now)
            .setOrderBy("startTime")
            .setSingleEvents(true)
            .execute();
    List<Event> items = events.getItems();
    if (items.isEmpty()) {
        System.out.println("No upcoming events found.");
    } else {
        System.out.println("Upcoming events");
        for (Event event : items) {
            DateTime start = event.getStart().getDateTime();
            if (start == null) {
                start = event.getStart().getDate();
            }
            System.out.printf("%s (%s)\n", event.getSummary(), start);
        }
    }

This should be close but i dont have the power of a java compiler right now.