diff --git a/src/main/java/org/gitlab4j/api/GitLabApi.java b/src/main/java/org/gitlab4j/api/GitLabApi.java index 410f5315f..a9cc3f924 100644 --- a/src/main/java/org/gitlab4j/api/GitLabApi.java +++ b/src/main/java/org/gitlab4j/api/GitLabApi.java @@ -81,6 +81,7 @@ public String getApiNamespace() { private NotesApi notesApi; private NotificationSettingsApi notificationSettingsApi; private PackagesApi packagesApi; + private PersonalAccessTokenApi personalAccessTokenApi; private PipelineApi pipelineApi; private ProjectApi projectApi; private ProtectedBranchesApi protectedBranchesApi; @@ -1405,6 +1406,25 @@ public PackagesApi getPackagesApi() { return (packagesApi); } + /** + * Gets the PersonalAccessTokenApi instance owned by this GitLabApi instance. The PersonalAccessTokenApi is used + * to perform all personalAccessToken related API calls. + * + * @return the PersonalAccessTokenApi instance owned by this GitLabApi instance + */ + public PersonalAccessTokenApi getPersonalAccessTokenApi() { + + if (personalAccessTokenApi == null) { + synchronized (this) { + if (personalAccessTokenApi == null) { + personalAccessTokenApi = new PersonalAccessTokenApi(this); + } + } + } + + return (personalAccessTokenApi); + } + /** * Gets the PipelineApi instance owned by this GitLabApi instance. The PipelineApi is used * to perform all pipeline related API calls. diff --git a/src/main/java/org/gitlab4j/api/PersonalAccessTokenApi.java b/src/main/java/org/gitlab4j/api/PersonalAccessTokenApi.java new file mode 100644 index 000000000..45b9502b9 --- /dev/null +++ b/src/main/java/org/gitlab4j/api/PersonalAccessTokenApi.java @@ -0,0 +1,67 @@ +package org.gitlab4j.api; + +import javax.ws.rs.core.Response; +import org.gitlab4j.api.models.PersonalAccessToken; +import org.gitlab4j.api.utils.ISO8601; + +import java.util.Date; + +/** + * This class provides an entry point to all the GitLab API personal access token calls. + * + * @see Personal access token API at GitLab + */ +public class PersonalAccessTokenApi extends AbstractApi { + + public PersonalAccessTokenApi(GitLabApi gitLabApi) { + super(gitLabApi); + } + + /** + * Rotates the given personal access token. + * The token is revoked and a new one which will expire in one week is created to replace it. + * Only working with GitLab 16.0 and above. + * + *
GitLab Endpoint: POST /personal_access_tokens/self/rotate
+ * + * @return the newly created PersonalAccessToken. + * @throws GitLabApiException if any exception occurs + */ + public PersonalAccessToken rotatePersonalAccessToken() throws GitLabApiException { + return rotatePersonalAccessToken(null); + } + + /** + * Rotates the given personal access token. + * The token is revoked and a new one which will expire in one week is created to replace it. + * Only working with GitLab 16.0 and above. + * + *
GitLab Endpoint: POST /personal_access_tokens/self/rotate
+ * + * @param expiresAt Expiration date of the access token + * @return the newly created PersonalAccessToken. + * @throws GitLabApiException if any exception occurs + */ + public PersonalAccessToken rotatePersonalAccessToken(Date expiresAt) throws GitLabApiException { + return rotatePersonalAccessToken("self", expiresAt); + } + + /** + * Rotates the given personal access token. + * The token is revoked and a new one which will expire in one week is created to replace it. + * Only working with GitLab 16.0 and above. + * + *
GitLab Endpoint: POST /personal_access_tokens/:id/rotate
+ * + * @param expiresAt Expiration date of the access token + * @return the newly created PersonalAccessToken. + * @throws GitLabApiException if any exception occurs + */ + public PersonalAccessToken rotatePersonalAccessToken(String id, Date expiresAt) throws GitLabApiException { + GitLabApiForm formData = new GitLabApiForm() + .withParam("expires_at", ISO8601.dateOnly(expiresAt)); + + Response response = post(Response.Status.OK, formData, "personal_access_tokens", id, "rotate"); + return (response.readEntity(PersonalAccessToken.class)); + } +} diff --git a/src/main/java/org/gitlab4j/api/models/PersonalAccessToken.java b/src/main/java/org/gitlab4j/api/models/PersonalAccessToken.java new file mode 100644 index 000000000..a4f6f940c --- /dev/null +++ b/src/main/java/org/gitlab4j/api/models/PersonalAccessToken.java @@ -0,0 +1,111 @@ +package org.gitlab4j.api.models; + +import org.gitlab4j.api.Constants; +import org.gitlab4j.api.utils.JacksonJson; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +public class PersonalAccessToken implements Serializable { + private static final long serialVersionUID = 1L; + + private Long userId; + private List scopes; + private String name; + @JsonSerialize(using = JacksonJson.DateOnlySerializer.class) + private Date expiresAt; + private Long id; + private Boolean active; + private Date createdAt; + private Boolean revoked; + private Date lastUsedAt; + private String token; + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public List getScopes() { + return scopes; + } + + public void setScopes(List scopes) { + this.scopes = scopes; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getExpiresAt() { + return expiresAt; + } + + public void setExpiresAt(Date expiredAt) { + this.expiresAt = expiredAt; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Boolean isActive() { + return active; + } + + public void setActive(Boolean active) { + this.active = active; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Boolean isRevoked() { + return revoked; + } + + public void setRevoked(Boolean revoked) { + this.revoked = revoked; + } + + public Date getLastUsedAt() { + return lastUsedAt; + } + + public void setLastUsedAt(Date lastUsedAt) { + this.lastUsedAt = lastUsedAt; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public String toString() { + return JacksonJson.toJsonString(this); + } +} diff --git a/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java b/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java index 025f7eeab..78b9f4fe3 100644 --- a/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java +++ b/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java @@ -99,6 +99,7 @@ import org.gitlab4j.api.models.OauthTokenResponse; import org.gitlab4j.api.models.Package; import org.gitlab4j.api.models.PackageFile; +import org.gitlab4j.api.models.PersonalAccessToken; import org.gitlab4j.api.models.Pipeline; import org.gitlab4j.api.models.PipelineSchedule; import org.gitlab4j.api.models.Project; @@ -721,6 +722,12 @@ public void testNotificationSettings() throws Exception { assertTrue(compareJson(settings, "notification-settings.json")); } + @Test + public void testPersonalAccessToken() throws Exception { + PersonalAccessToken project = unmarshalResource(PersonalAccessToken.class, "personal-access-token.json"); + assertTrue(compareJson(project, "personal-access-token.json")); + } + @Test public void testProject() throws Exception { Project project = unmarshalResource(Project.class, "project.json"); diff --git a/src/test/resources/org/gitlab4j/api/personal-access-token.json b/src/test/resources/org/gitlab4j/api/personal-access-token.json new file mode 100644 index 000000000..0ef66efa2 --- /dev/null +++ b/src/test/resources/org/gitlab4j/api/personal-access-token.json @@ -0,0 +1,12 @@ +{ + "id": 42, + "name": "Rotated Token", + "revoked": false, + "created_at": "2023-08-01T15:00:00Z", + "scopes": ["api"], + "user_id": 1337, + "last_used_at": "2021-10-06T17:58:37Z", + "active": true, + "expires_at": "2023-08-15", + "token": "s3cr3t" +} \ No newline at end of file