Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<groupId>jp.openstandia.connector</groupId>
<artifactId>connector-github</artifactId>
<version>1.2.5-SNAPSHOT</version>
<version>1.2.6-SNAPSHOT</version>
<packaging>jar</packaging>

<name>GitHub Connector</name>
Expand Down Expand Up @@ -73,6 +73,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down
19 changes: 15 additions & 4 deletions src/main/java/jp/openstandia/connector/github/GitHubClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@
import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.ResultsHandler;
import org.identityconnectors.framework.common.objects.Uid;
import org.kohsuke.github.SCIMEMUGroup;
import org.kohsuke.github.SCIMEMUUser;
import org.kohsuke.github.SCIMPatchOperations;
import org.kohsuke.github.SCIMUser;
import org.kohsuke.github.*;

import java.net.InetSocketAddress;
import java.net.Proxy;
Expand Down Expand Up @@ -205,5 +202,19 @@ default SCIMEMUGroup getEMUGroup(Uid uid, OperationOptions options, Set<String>
default SCIMEMUGroup getEMUGroup(Name name, OperationOptions options, Set<String> attributesToGet) {
throw new UnsupportedOperationException();
}

// Copilot Seats

default GitHubCopilotSeat getCopilotSeat(Uid uid, OperationOptions options, Set<String> attributesToGet) {
throw new UnsupportedOperationException();
}

default GitHubCopilotSeat getCopilotSeat(Name name, OperationOptions options, Set<String> attributesToGet) {
throw new UnsupportedOperationException();
}

default int getCopilotSeats(QueryHandler<GitHubCopilotSeat> handler, OperationOptions options, Set<String> fetchFieldsSet, int pageSize, int pageOffset) {
throw new UnsupportedOperationException();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package jp.openstandia.connector.github;

import jp.openstandia.connector.util.SchemaDefinition;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.framework.common.objects.*;
import org.kohsuke.github.GitHubCopilotSeat;
import org.kohsuke.github.SCIMPatchOperations;

import java.util.Set;

import static jp.openstandia.connector.util.Utils.toZoneDateTime;
import static jp.openstandia.connector.util.Utils.toZoneDateTimeForISO8601OffsetDateTime;
import static org.identityconnectors.framework.common.objects.AttributeInfo.Flags.*;

public class GitHubCopilotSeatHandler extends AbstractGitHubEMUHandler {

public static final ObjectClass SEAT_OBJECT_CLASS = new ObjectClass("GitHubCopilotSeat");

private static final Log LOGGER = Log.getLog(GitHubCopilotSeatHandler.class);

public GitHubCopilotSeatHandler(GitHubEMUConfiguration configuration, GitHubClient<GitHubEMUSchema> client,
GitHubEMUSchema schema, SchemaDefinition schemaDefinition) {
super(configuration, client, schema, schemaDefinition);
}

public static SchemaDefinition.Builder createSchema(AbstractGitHubConfiguration configuration, GitHubClient<GitHubEMUSchema> client) {
SchemaDefinition.Builder<GitHubCopilotSeat, SCIMPatchOperations, GitHubCopilotSeat> sb
= SchemaDefinition.newBuilder(SEAT_OBJECT_CLASS, GitHubCopilotSeat.class, SCIMPatchOperations.class, GitHubCopilotSeat.class);

// __UID__
// The id for the seat. Must be unique and unchangeable.
sb.addUid("id",
SchemaDefinition.Types.UUID,
null,
(source) -> source.assignee.id,
"id",
NOT_CREATABLE, NOT_UPDATEABLE
);

// code (__NAME__)
// The name for the seat. Must be unique and changeable.
sb.addName("displayName",
SchemaDefinition.Types.STRING_CASE_IGNORE,
(source, dest) -> dest.assignee.login = source,
(source, dest) -> dest.replace("displayName", source),
(source) -> source.assignee.login,
null,
REQUIRED
);

// Metadata (readonly)
sb.add("created_at",
SchemaDefinition.Types.DATETIME,
null,
(source) -> source.created_at != null ? toZoneDateTimeForISO8601OffsetDateTime(source.created_at) : null,
null,
NOT_CREATABLE, NOT_UPDATEABLE
);

sb.add("last_authenticated_at",
SchemaDefinition.Types.DATETIME,
null,
(source) -> source.last_authenticated_at != null ? toZoneDateTimeForISO8601OffsetDateTime(source.last_authenticated_at) : null,
null,
NOT_CREATABLE, NOT_UPDATEABLE
);

sb.add("updated_at",
SchemaDefinition.Types.DATETIME,
null,
(source) -> source.updated_at != null ? toZoneDateTimeForISO8601OffsetDateTime(source.updated_at) : null,
null,
NOT_CREATABLE, NOT_UPDATEABLE
);

sb.add("last_activity_at",
SchemaDefinition.Types.DATETIME,
null,
(source) -> source.last_activity_at != null ? toZoneDateTimeForISO8601OffsetDateTime(source.last_activity_at) : null,
null,
NOT_CREATABLE, NOT_UPDATEABLE
);

sb.add("pending_cancellation_date",
SchemaDefinition.Types.DATETIME,
null,
(source) -> source.pending_cancellation_date != null ? toZoneDateTime(source.pending_cancellation_date) : null,
null,
NOT_CREATABLE, NOT_UPDATEABLE
);

sb.add("last_activity_editor",
SchemaDefinition.Types.STRING,
(source, dest) -> {
dest.last_activity_editor = source;
},
(source, dest) -> dest.replace("last_activity_editor", source),
(source) -> source.last_activity_editor,
null
);

sb.add("plan_type",
SchemaDefinition.Types.STRING,
(source, dest) -> {
dest.plan_type = source;
},
(source, dest) -> dest.replace("plan_type", source),
(source) -> source.plan_type,
null
);

sb.add("assignee.type",
SchemaDefinition.Types.STRING,
(source, dest) -> {
dest.assignee.type = source;
},
(source, dest) -> dest.replace("assignee.type", source),
(source) -> source.assignee.type,
null
);

sb.add("assigning_team.slug",
SchemaDefinition.Types.STRING,
(source, dest) -> {
if (source != null) {
dest.assigning_team.slug = source;
}
},
(source, dest) -> dest.replace("assigning_team.slug", source),
(source) -> source != null && source.assigning_team != null ? source.assigning_team.slug : null,
null
);

LOGGER.ok("The constructed GitHub EMU Seat schema");

return sb;
}

@Override
public Uid create(Set<Attribute> attributes) {
return null;
}

@Override
public Set<AttributeDelta> updateDelta(Uid uid, Set<AttributeDelta> modifications, OperationOptions options) {
return Set.of();
}

@Override
public void delete(Uid uid, OperationOptions options) {
}

@Override
public int getByUid(Uid uid, ResultsHandler resultsHandler, OperationOptions options, Set<String> returnAttributesSet, Set<String> fetchFieldsSet, boolean allowPartialAttributeValues, int pageSize, int pageOffset) {
GitHubCopilotSeat seat = client.getCopilotSeat(uid, options, fetchFieldsSet);

if (seat != null) {
resultsHandler.handle(toConnectorObject(schemaDefinition, seat, returnAttributesSet, allowPartialAttributeValues));
return 1;
}
return 0;
}

@Override
public int getByName(Name name, ResultsHandler resultsHandler, OperationOptions options, Set<String> returnAttributesSet, Set<String> fetchFieldsSet, boolean allowPartialAttributeValues, int pageSize, int pageOffset) {
GitHubCopilotSeat seat = client.getCopilotSeat(name, options, fetchFieldsSet);

if (seat != null) {
resultsHandler.handle(toConnectorObject(schemaDefinition, seat, returnAttributesSet, allowPartialAttributeValues));
return 1;
}
return 0;
}

@Override
public int getByMembers(Attribute attribute, ResultsHandler resultsHandler, OperationOptions options, Set<String> returnAttributesSet, Set<String> fetchFieldSet, boolean allowPartialAttributeValues, int pageSize, int pageOffset) {
return super.getByMembers(attribute, resultsHandler, options, returnAttributesSet, fetchFieldSet, allowPartialAttributeValues, pageSize, pageOffset);
}

@Override
public int getAll(ResultsHandler resultsHandler, OperationOptions options, Set<String> returnAttributesSet, Set<String> fetchFieldsSet, boolean allowPartialAttributeValues, int pageSize, int pageOffset) {
return client.getCopilotSeats((s) -> resultsHandler.handle(toConnectorObject(schemaDefinition, s, returnAttributesSet, allowPartialAttributeValues)),
options, fetchFieldsSet, pageSize, pageOffset);
}

@Override
public void query(GitHubFilter filter, ResultsHandler resultsHandler, OperationOptions options) {
super.query(filter, resultsHandler, options);
}

@Override
public <T> ConnectorObject toConnectorObject(SchemaDefinition schema, T user, Set<String> returnAttributesSet, boolean allowPartialAttributeValues) {
return super.toConnectorObject(schema, user, returnAttributesSet, allowPartialAttributeValues);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ public class GitHubEMUSchema extends AbstractGitHubSchema<GitHubEMUConfiguration
public GitHubEMUSchema(GitHubEMUConfiguration configuration, GitHubClient<GitHubEMUSchema> client) {
super(configuration, client);

SchemaBuilder schemaBuilder = new SchemaBuilder(GitHubConnector.class);
SchemaBuilder schemaBuilder = new SchemaBuilder(GitHubEMUConnector.class);

buildSchema(schemaBuilder, GitHubEMUUserHandler.createSchema(configuration, client).build(),
(schema) -> new GitHubEMUUserHandler(configuration, client, this, schema));
buildSchema(schemaBuilder, GitHubEMUGroupHandler.createSchema(configuration, client).build(),
(schema) -> new GitHubEMUGroupHandler(configuration, client, this, schema));
buildSchema(schemaBuilder, GitHubCopilotSeatHandler.createSchema(configuration, client).build(),
(schema) -> new GitHubCopilotSeatHandler(configuration, client, this, schema));

// Define operation options
schemaBuilder.defineOperationOption(OperationOptionInfoBuilder.buildAttributesToGet(), SearchOp.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ public class GitHubEMURESTClient implements GitHubClient<GitHubEMUSchema> {

public GitHubEMURESTClient(GitHubEMUConfiguration configuration) {
this.configuration = configuration;

auth();
}

Expand Down Expand Up @@ -286,6 +285,53 @@ public SCIMEMUGroup getEMUGroup(Name name, OperationOptions options, Set<String>
});
}

@Override
public GitHubCopilotSeat getCopilotSeat(Uid uid, OperationOptions options, Set<String> attributesToGet) {
return withAuth(() -> {
GitHubCopilotSeat seat = enterpriseApiClient.getCopilotSeatByUid(uid.getUidValue());
return seat;
});
}

@Override
public GitHubCopilotSeat getCopilotSeat(Name name, OperationOptions options, Set<String> attributesToGet) {
return withAuth(() -> {
GitHubCopilotSeat seat = enterpriseApiClient.getCopilotSeatByDisplayName(name.getNameValue());
return seat;
});
}

@Override
public int getCopilotSeats(QueryHandler<GitHubCopilotSeat> handler, OperationOptions options, Set<String> fetchFieldsSet, int pageSize, int pageOffset) {
return withAuth(() -> {
GitHubCopilotSeatPagedSearchIterable<GitHubCopilotSeat> iterable = enterpriseApiClient.listAllSeats(pageSize, pageOffset);

// 0 means no offset (requested all data)
if (pageOffset < 1) {
for (GitHubCopilotSeat next : iterable) {
if (!handler.handle(next)) {
break;
}
}
return iterable.getTotalSeats();
}

// Pagination
int count = 0;
for (GitHubCopilotSeat next : iterable) {
count++;
if (!handler.handle(next)) {
break;
}
if (count >= pageSize) {
break;
}
}

return iterable.getTotalSeats();
});
}

@Override
public int getEMUGroups(QueryHandler<SCIMEMUGroup> handler, OperationOptions options, Set<String> fetchFieldsSet, int pageSize, int pageOffset) {
return withAuth(() -> {
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/org/kohsuke/github/GHEnterpriseExt.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,28 @@ public SCIMEMUGroup getSCIMEMUGroupByDisplayName(String scimGroupDisplayName) th
return list.get(0);
}

public GitHubCopilotSeat getCopilotSeatByDisplayName(String copilotSeatDisplayName) throws IOException {
List<GitHubCopilotSeat> allSeats = searchCopilotSeats()
.list()
.toList();

return allSeats.stream()
.filter(seat -> copilotSeatDisplayName.equals(seat.assignee.login))
.findFirst()
.orElse(null);
}

public GitHubCopilotSeat getCopilotSeatByUid(String copilotSeatUid) throws IOException {
List<GitHubCopilotSeat> allSeats = searchCopilotSeats()
.list()
.toList();

return allSeats.stream()
.filter(seat -> copilotSeatUid.equals(seat.assignee.id))
.findFirst()
.orElse(null);
}

/**
* Search groups.
*
Expand All @@ -169,6 +191,15 @@ public SCIMPagedSearchIterable<SCIMEMUGroup> listSCIMGroups(int pageSize, int pa
return searchSCIMGroups().list().withPageSize(pageSize).withPageOffset(pageOffset);
}

public GitHubCopilotSeatsSearchBuilder searchCopilotSeats() {
return new GitHubCopilotSeatsSearchBuilder(root, this);
}

public GitHubCopilotSeatPagedSearchIterable<GitHubCopilotSeat> listAllSeats(int pageSize, int pageOffset)
throws IOException {
return searchCopilotSeats().list().withPageSize(pageSize).withPageOffset(pageOffset);
}

public void deleteSCIMGroup(String scimGroupId) throws IOException {
root.createRequest()
.method("DELETE")
Expand Down
Loading