Skip to content

Fix #858: Added missing TopicsApi #1012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 19, 2023
Merged
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
22 changes: 21 additions & 1 deletion src/main/java/org/gitlab4j/api/GitLabApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public String getApiNamespace() {
private SystemHooksApi systemHooksApi;
private TagsApi tagsApi;
private TodosApi todosApi;
private TopicsApi topicsApi;
private UserApi userApi;
private UncyclosApi wikisApi;
private KeysApi keysApi;
Expand Down Expand Up @@ -1463,7 +1464,7 @@ public ReleaseLinksApi getReleaseLinksApi() {

return releaseLinksApi;
}

/**
* Gets the ReleasesApi instance owned by this GitLabApi instance. The ReleasesApi is used
* to perform all release related API calls.
Expand Down Expand Up @@ -1654,6 +1655,25 @@ public TagsApi getTagsApi() {
return (tagsApi);
}

/**
* Gets the TagsApi instance owned by this GitLabApi instance. The TagsApi is used
* to perform all tag and release related API calls.
*
* @return the TagsApi instance owned by this GitLabApi instance
*/
public TopicsApi getTopicsApi() {

if (topicsApi == null) {
synchronized (this) {
if (topicsApi == null) {
topicsApi = new TopicsApi(this);
}
}
}

return (topicsApi);
}

/**
* Gets the SnippetsApi instance owned by this GitLabApi instance. The SnippetsApi is used
* to perform all snippet related API calls.
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/org/gitlab4j/api/GitLabApiClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.BodyPart;
import org.glassfish.jersey.media.multipart.Boundary;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.media.multipart.MultiPart;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
Expand Down Expand Up @@ -264,7 +265,7 @@ public void close() {
*
* @param logger the Logger instance to log to
* @param level the logging level (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
* @param maxEntitySize maximum number of entity bytes to be logged. When logging if the maxEntitySize
* @param maxEntityLength maximum number of entity bytes to be logged. When logging if the maxEntitySize
* is reached, the entity logging will be truncated at maxEntitySize and "...more..." will be added at
* the end of the log entry. If maxEntitySize is <= 0, entity logging will be disabled
* @param maskedHeaderNames a list of header names that should have the values masked
Expand Down Expand Up @@ -691,7 +692,11 @@ protected Response putUpload(String name, File fileToUpload, Object... pathArgs)
protected Response putUpload(String name, File fileToUpload, URL url) throws IOException {

try (MultiPart multiPart = new FormDataMultiPart()) {
multiPart.bodyPart(new FileDataBodyPart(name, fileToUpload, MediaType.APPLICATION_OCTET_STREAM_TYPE));
if(fileToUpload == null) {
multiPart.bodyPart(new FormDataBodyPart(name, "", MediaType.APPLICATION_OCTET_STREAM_TYPE));
} else {
multiPart.bodyPart(new FileDataBodyPart(name, fileToUpload, MediaType.APPLICATION_OCTET_STREAM_TYPE));
}
final Entity<?> entity = Entity.entity(multiPart, Boundary.addBoundary(multiPart.getMediaType()));
return (invocation(url, null).put(entity));
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/org/gitlab4j/api/ProjectApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,10 @@ public Project createProject(Project project, String importUrl) throws GitLabApi
if (project.getTagList() != null && !project.getTagList().isEmpty()) {
throw new IllegalArgumentException("GitLab API v3 does not support tag lists when creating projects");
}

if (project.getTopics() != null && !project.getTopics().isEmpty()) {
throw new IllegalArgumentException("GitLab API v3 does not support topics when creating projects");
}
} else {
Visibility visibility = (project.getVisibility() != null ? project.getVisibility() :
project.getPublic() == Boolean.TRUE ? Visibility.PUBLIC : null);
Expand All @@ -1051,6 +1055,10 @@ public Project createProject(Project project, String importUrl) throws GitLabApi
if (project.getTagList() != null && !project.getTagList().isEmpty()) {
formData.withParam("tag_list", String.join(",", project.getTagList()));
}

if (project.getTopics() != null && !project.getTopics().isEmpty()) {
formData.withParam("topics", String.join(",", project.getTopics()));
}
}

Response response = post(Response.Status.CREATED, formData, "projects");
Expand Down Expand Up @@ -1314,6 +1322,10 @@ public Project updateProject(Project project) throws GitLabApiException {
if (project.getTagList() != null && !project.getTagList().isEmpty()) {
throw new IllegalArgumentException("GitLab API v3 does not support tag lists when updating projects");
}

if (project.getTopics() != null && !project.getTopics().isEmpty()) {
throw new IllegalArgumentException("GitLab API v3 does not support topics when updating projects");
}
} else {
Visibility visibility = (project.getVisibility() != null ? project.getVisibility() :
project.getPublic() == Boolean.TRUE ? Visibility.PUBLIC : null);
Expand All @@ -1322,6 +1334,10 @@ public Project updateProject(Project project) throws GitLabApiException {
if (project.getTagList() != null && !project.getTagList().isEmpty()) {
formData.withParam("tag_list", String.join(",", project.getTagList()));
}

if (project.getTopics() != null && !project.getTopics().isEmpty()) {
formData.withParam("topics", String.join(",", project.getTopics()));
}
}

Response response = putWithFormData(Response.Status.OK, formData, "projects", projectIdentifier);
Expand Down
193 changes: 193 additions & 0 deletions src/main/java/org/gitlab4j/api/TopicsApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package org.gitlab4j.api;

import org.gitlab4j.api.models.Topic;
import org.gitlab4j.api.models.TopicParams;

import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
import java.io.File;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class TopicsApi extends AbstractApi{

public TopicsApi(GitLabApi gitLabApi) {
super(gitLabApi);
}

/**
* <p>Get a list of Topics. </p>
*
* <strong>WARNING:</strong> Do not use this method to fetch Topics from https://gitlab.com,
* gitlab.com has many 1,000's of public topics and it will a long time to fetch all of them.
* Instead use {@link #getTopics(int itemsPerPage)} which will return a Pager of Topic instances.
*
* <pre><code>GitLab Endpoint: GET /topics</code></pre>
*
* @return the list of topics viewable by the authenticated user
* @throws GitLabApiException if any exception occurs
*/
public List<Topic> getTopics() throws GitLabApiException {
return (getTopics(getDefaultPerPage()).all());
}

/**
* Get a list of topics in the specified page range.
*
* <pre><code>GitLab Endpoint: GET /topics</code></pre>
*
* @param page the page to get
* @param perPage the number of Topic instances per page
* @return the list of topics
* @throws GitLabApiException if any exception occurs
*/
public List<Topic> getTopics(int page, int perPage) throws GitLabApiException {
Response response = get(Response.Status.OK, getPageQueryParams(page, perPage), "topics");
return (response.readEntity(new GenericType<List<Topic>>() {}));
}

/**
* Get a Pager of topics.
*
* <pre><code>GitLab Endpoint: GET /topics</code></pre>
*
* @param itemsPerPage the number of Topic instances that will be fetched per page
* @return the pager of topics
* @throws GitLabApiException if any exception occurs
*/
public Pager<Topic> getTopics(int itemsPerPage) throws GitLabApiException {
return (new Pager<Topic>(this, Topic.class, itemsPerPage, null, "topics"));
}

/**
* Get a Stream of topics.
*
* <pre><code>GitLab Endpoint: GET /topics</code></pre>
*
* @return the stream of topics
* @throws GitLabApiException if any exception occurs
*/
public Stream<Topic> getTopicsStream() throws GitLabApiException {
return (getTopics(getDefaultPerPage()).stream());
}

/**
* Get all details of a topic.
*
* <pre><code>GitLab Endpoint: GET /topics/:id</code></pre>
*
* @param id the topic ID
* @return the topic for the specified topic id
* @throws GitLabApiException if any exception occurs
*/
public Topic getTopic(Integer id) throws GitLabApiException {
Response response = get(Response.Status.OK, null, "topics", id);
return (response.readEntity(Topic.class));
}

/**
* Get all details of a topic as an Optional instance.
*
* <pre><code>GitLab Endpoint: GET /topics/:id</code></pre>
*
* @param id the topic ID
* @return the Topic for the specified topic id as an Optional instance
*/
public Optional<Topic> getOptionalTopic(Integer id) {
try {
return (Optional.ofNullable(getTopic(id)));
} catch (GitLabApiException glae) {
return (GitLabApi.createOptionalFromException(glae));
}
}

/**
* Creates a new Topic. Available only for users who can create topics.
*
* <pre><code>GitLab Endpoint: POST /topics</code></pre>
*
* @param params a TopicParams instance holding the parameters for the topic creation
* @return the created Topic instance
* @throws GitLabApiException if any exception occurs
*/
public Topic createTopic(TopicParams params) throws GitLabApiException {
Response response = post(Response.Status.CREATED, params.getForm(true), "topics");
return (response.readEntity(Topic.class));
}

/**
* Update a project topic.
*
* <pre><code>GitLab Endpoint: PUT /topics/:id</code></pre>
*
* @param id the topic id
* @param params a TopicParams instance holding the properties to Update
* @return the updated Topic instance
* @throws GitLabApiException at any exception
*/
public Topic updateTopic(Integer id, TopicParams params) throws GitLabApiException {
Response response = putWithFormData(Response.Status.OK,
params.getForm(false), "topics", id);
return (response.readEntity(Topic.class));
}

/**
* Uploads and sets the topic's avatar for the specified topic.
*
* <pre><code>GitLab Endpoint: PUT /topics/:id</code></pre>
*
* @param id the topic in the form of an Integer
* @param avatarFile the File instance of the avatar file to upload
* @return the updated Topic instance
* @throws GitLabApiException if any exception occurs
*/
public Topic updateTopicAvatar(final Integer id, File avatarFile) throws GitLabApiException {
Response response = putUpload(Response.Status.OK, "avatar", avatarFile, "topics", id);
return (response.readEntity(Topic.class));
}

/**
* Delete the topic's avatar for the specified topic.
*
* <pre><code>GitLab Endpoint: PUT /topics/:id</code></pre>
*
* @param id the topic in the form of an Integer
* @return the updated Topic instance
* @throws GitLabApiException if any exception occurs
*/
public Topic deleteTopicAvatar(final Integer id) throws GitLabApiException {
Response response = putUpload(Response.Status.OK, "avatar", null, "topics", id);
return (response.readEntity(Topic.class));
}

/**
* Delete a topic. You must be an administrator to delete a project topic. When you delete a project topic, you also delete the topic assignment for projects.
*
* <pre><code>GitLab Endpoint: DELETE /topics/:id</code></pre>
*
* @param id the topic to deleted in the form of an Integer
* @throws GitLabApiException if any exception occurs
*/
public void deleteTopic(Integer id) throws GitLabApiException {
if(isApiVersion(GitLabApi.ApiVersion.V3)){
throw new GitLabApiException("Topics need api v4+");
}
delete(Response.Status.NO_CONTENT,null, "topics", id);
}

/**
* Merge two topics together. You must be an administrator to merge a source topic into a target topic. When you merge topics, you delete the source topic and move all assigned projects to the target topic.
*
* <pre><code>GitLab Endpoint: POST /topics/merge</code></pre>
*
* @param sourceTopicId ID of source project topic
* @param targetTopicId ID of target project topic
* @return the merged Topic instance
* @throws GitLabApiException if any exception occurs
*/
public Topic mergeTopics(Integer sourceTopicId, Integer targetTopicId) throws GitLabApiException {
Response response = post(Response.Status.OK,new GitLabApiForm().withParam("source_topic_id",sourceTopicId).withParam("target_topic_id",targetTopicId),"topics/merge");
return (response.readEntity(Topic.class));
}
}
29 changes: 28 additions & 1 deletion src/main/java/org/gitlab4j/api/models/Project.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ public String toString() {
private Boolean snippetsEnabled;
private String sshUrlToRepo;
private Integer starCount;

private List<String> tagList;
private List<String> topics;
private Integer visibilityLevel;
private Visibility visibility;
private Boolean wallEnabled;
Expand Down Expand Up @@ -542,19 +544,44 @@ public void setStarCount(Integer starCount) {
this.starCount = starCount;
}

/**
* Tags will be removed in API v5
*/
@Deprecated
public List<String> getTagList() {
return tagList;
}

/**
* Tags will be removed in API v5
*/
@Deprecated
public void setTagList(List<String> tagList) {
this.tagList = tagList;
}

/**
* Tags will be removed in API v5
*/
@Deprecated
public Project withTagList(List<String> tagList) {
this.tagList = tagList;
return (this);
}

public List<String> getTopics() {
return topics;
}

public void setTopics(List<String> topics) {
this.topics = topics;
}

public Project withTopics(List<String> topics) {
this.topics = topics;
return (this);
}

public Visibility getVisibility() {
return visibility;
}
Expand Down Expand Up @@ -733,7 +760,7 @@ public String toString() {
* Formats a fully qualified project path based on the provided namespace and project path.
*
* @param namespace the namespace, either a user name or group name
* @param path the project path
* @param path the project path
* @return a fully qualified project path based on the provided namespace and project path
*/
public static final String getPathWithNammespace(String namespace, String path) {
Expand Down
Loading