Skip to content
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

164 165 216 Support for HTTP PUT/DELETE and parameters in URLs #217

Merged
merged 7 commits into from
Sep 28, 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
4 changes: 0 additions & 4 deletions .env

This file was deleted.

86 changes: 71 additions & 15 deletions .github/workflows/ci-build-publish-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,85 @@ name: Build and publish Ruuter
on:
push:
branches: [ main ]
paths-ignore:
- '**.md'
paths:
- '.env'

jobs:
PackageDeploy:
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2

- name: Docker Setup BuildX
uses: docker/setup-buildx-action@v2
- name: Docker Setup BuildX
uses: docker/setup-buildx-action@v2

- name: Set image tag
run: |
LOWER_CASE_GITHUB_REPOSITORY=$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')
echo "DOCKER_TAG_CUSTOM=ghcr.io/${LOWER_CASE_GITHUB_REPOSITORY}:${m-beta-2.0.$(date +'%y%m%d%H%M%S')}" >> $GITHUB_ENV
- name: Docker Build
run: docker image build --tag $DOCKER_TAG_CUSTOM .
- name: Load environment variables and set them
run: |
if [ -f .env ]; then
export $(cat .env | grep -v '^#' | xargs)
fi
echo "RELEASE=$RELEASE" >> $GITHUB_ENV
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "BUILD=$BUILD" >> $GITHUB_ENV
echo "FIX=$FIX" >> $GITHUB_ENV
- name: Set repo
run: |
LOWER_CASE_GITHUB_REPOSITORY=$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')
echo "DOCKER_TAG_CUSTOM=ghcr.io/${LOWER_CASE_GITHUB_REPOSITORY}:$RELEASE-$VERSION.$BUILD.$FIX" >> $GITHUB_ENV
echo "$GITHUB_ENV"
- name: Docker Build
run: docker image build --tag $DOCKER_TAG_CUSTOM .

- name: Log in to GitHub container registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin

- name: Log in to GitHub container registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
- name: Push Docker image to ghcr
run: docker push $DOCKER_TAG_CUSTOM

- name: Check if changelog.md exists
id: check_file
run: |
if [ -f changelog.md ]; then
echo "::set-output name=file_exists::true"
else
echo "::set-output name=file_exists::false"
fi

- name: Generate changelog.md
run: |
if [ "${{ steps.check_file.outputs.file_exists }}" = "false" ]; then

echo "## Changelog" >> changelog.md
echo "" >> image_update.md
echo "The Docker image has been successfully built and pushed." >> changelog.md
echo "" >> image_update.md
echo "You can pull the updated image using the following command:" >> changelog.md
echo "" >> changelog.md
# echo "```" >> changelog.md
echo "<code>docker pull $DOCKER_TAG_CUSTOM</code>" >> changelog.md
# echo "```" >> changelog.md
echo "" >> changelog.md
echo "Enjoy the Ruuter!" >> changelog.md
else
> changelog.md
echo "## Docker Image Update" >> changelog.md
echo "" >> image_update.md
echo "The Docker image has been successfully built and pushed." >> changelog.md
echo "" >> changelog.md
echo "You can pull the updated image using the following command:" >> changelog.md
echo "" >> changelog.md
# echo "```" >> changelog.md
echo "<code>docker pull $DOCKER_TAG_CUSTOM</code>" >> changelog.md
# echo "```" >> changelog.md
echo "" >> changelog.md
echo "Enjoy the Ruuter!" >> changelog.md
fi

- name: Push Docker image to ghcr
run: docker push $DOCKER_TAG_CUSTOM
- name: Commit and push updated changelog.md
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git add image_update.md
git commit -m "Update image_update.md with Docker image info"
git push
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ee.buerokratt.ruuter.domain.steps.http;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.http.HttpMethod;

@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@NoArgsConstructor
public class HttpDeleteStep extends HttpPostStep{

@Override
public String getType() {
return "http.delete";
}

@Override
public HttpMethod getMethod() {
return HttpMethod.DELETE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;

import java.util.Map;
Expand All @@ -17,10 +18,11 @@ public class HttpGetStep extends HttpStep {

@Override
public ResponseEntity<Object> getRequestResponse(DslInstance di) {
String evaluatedURL = di.getScriptingHelper().evaluateScripts(args.getUrl(),di.getContext(), di.getRequestBody(), di.getRequestQuery(), di.getRequestHeaders()).toString();
Map<String, Object> evaluatedQuery = di.getScriptingHelper().evaluateScripts(args.getQuery(), di.getContext(), di.getRequestBody(), di.getRequestQuery(), di.getRequestHeaders());
Map<String, Object> evaluatedHeaders = di.getScriptingHelper().evaluateScripts(args.getHeaders(), di.getContext(), di.getRequestBody(), di.getRequestQuery(), di.getRequestHeaders());
Map<String, String> mappedHeaders = di.getMappingHelper().convertMapObjectValuesToString(evaluatedHeaders);
return di.getHttpHelper().doGet(args.getUrl(), evaluatedQuery, mappedHeaders);
return di.getHttpHelper().doMethod(HttpMethod.GET, evaluatedURL, evaluatedQuery, null, mappedHeaders, null, null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;

import java.util.Map;
Expand All @@ -20,20 +21,24 @@ protected ResponseEntity<Object> getRequestResponse(DslInstance di) {
Map<String, Object> defaultHeaders = di.getProperties().getHttpPost().getHeaders();
if (defaultHeaders != null && !defaultHeaders.isEmpty())
args.addHeaders(di.getProperties().getHttpPost().getHeaders());
String evaluatedURL = di.getScriptingHelper().evaluateScripts(args.getUrl(),di.getContext(), di.getRequestBody(), di.getRequestQuery(), di.getRequestHeaders()).toString();
Map<String, Object> evaluatedBody = di.getScriptingHelper().evaluateScripts(args.getBody(), di.getContext(), di.getRequestBody(), di.getRequestQuery(), di.getRequestHeaders());
Map<String, Object> evaluatedQuery = di.getScriptingHelper().evaluateScripts(args.getQuery(), di.getContext(), di.getRequestBody(), di.getRequestQuery(), di.getRequestHeaders());
Map<String, Object> evaluatedHeaders = di.getScriptingHelper().evaluateScripts(args.getHeaders(), di.getContext(), di.getRequestBody(), di.getRequestQuery(), di.getRequestHeaders());
Map<String, String> mappedHeaders = di.getMappingHelper().convertMapObjectValuesToString(evaluatedHeaders);

if ("plaintext".equals(args.getContentType()))
return di.getHttpHelper().doPostPlaintext(args.getUrl(), evaluatedBody, evaluatedQuery, mappedHeaders, args.getPlaintext());
else
return di.getHttpHelper().doPost(args.getUrl(), evaluatedBody, evaluatedQuery, mappedHeaders);

return di.getHttpHelper().doMethod(getMethod(), evaluatedURL,
evaluatedQuery, evaluatedBody, mappedHeaders,
"plaintext".equals(args.getContentType()) ? "plaintext" : null,
"plaintext".equals(args.getContentType()) ? args.getPlaintext() : null);
}

@Override
public String getType() {
return "http.post";
}

public HttpMethod getMethod() {
return HttpMethod.POST;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ee.buerokratt.ruuter.domain.steps.http;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.http.HttpMethod;

@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@NoArgsConstructor
public class HttpPutStep extends HttpPostStep {
@Override
public String getType() {
return "http.put";
}

@Override
public HttpMethod getMethod() {
return HttpMethod.PUT;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
@JsonSubTypes({
@JsonSubTypes.Type(value = HttpGetStep.class, name = "http.get"),
@JsonSubTypes.Type(value = HttpPostStep.class, name = "http.post"),
@JsonSubTypes.Type(value = HttpPutStep.class, name = "http.put"),
@JsonSubTypes.Type(value = HttpDeleteStep.class, name = "http.delete"),
})
@NoArgsConstructor
public abstract class HttpStep extends DslStep {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ public ResponseEntity<Object> forwardRequest(String dsl, Map<String, Object> req
.toUriString();

if (methodType.equals(HttpMethod.POST.name())) {
return httpHelper.doPost(forwardingUrl, body, query, headers, contentType);
return httpHelper.doMethod(HttpMethod.POST,forwardingUrl, query, body, headers, contentType, null);
}
if (methodType.equals(HttpMethod.GET.name())) {
return httpHelper.doGet(forwardingUrl, query, headers);
return httpHelper.doMethod(HttpMethod.GET, forwardingUrl, query,null, headers, null, null);
}
throw new InvalidHttpMethodTypeException(methodType);
}
Expand Down
84 changes: 33 additions & 51 deletions src/main/java/ee/buerokratt/ruuter/helper/HttpHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,22 @@
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;

import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

import reactor.netty.http.client.HttpClient;

import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
Expand All @@ -34,72 +33,55 @@ public ResponseEntity<Object> doPost(String url, Map<String, Object> body, Map<S
return doPost(url, body, query, headers, this.getClass().getName());
}
public ResponseEntity<Object> doPost(String url, Map<String, Object> body, Map<String, Object> query, Map<String, String> headers, String contentType) {

WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(getHttpClient()))
.baseUrl(url)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultUriVariables(query)
.build();

try {
return client.post()
.headers(httpHeaders -> addHeadersIfNotNull(headers, httpHeaders))
.bodyValue(body)
.retrieve()
.toEntity(Object.class)
.block();
} catch (WebClientResponseException e) {
return new ResponseEntity<>(e.getStatusText(), e.getStatusCode());
}
return doMethod(HttpMethod.POST, url, query, body,headers, contentType, null);
}

public ResponseEntity<Object> doPostPlaintext(String url, Map<String, Object> body, Map<String, Object> query, Map<String, String> headers, String plaintext) {
WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(getHttpClient()))
.baseUrl(url)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE)
.defaultUriVariables(query)
.build();

BodyInserter sendable;
if (body.isEmpty()) {
sendable = BodyInserters.fromPublisher(Mono.just(plaintext), String.class);
}
else {
MultiValueMap<String, String> multibody = new LinkedMultiValueMap<>();
body.forEach((s, o) -> multibody.add(s, (String) o));
sendable = BodyInserters.fromFormData(multibody);
}
return doMethod(HttpMethod.POST, url, body, query, headers, "plaintext", plaintext);
}

try {
return client.post()
.headers(httpHeaders -> addHeadersIfNotNull(headers, httpHeaders))
.body(sendable)
.retrieve()
.toEntity(Object.class)
.block();
public ResponseEntity<Object> doGet(String url, Map<String, Object> query, Map<String, String> headers) {
return doMethod(HttpMethod.GET, url, query, null, headers, null, null);
}

} catch (WebClientResponseException e) {
return new ResponseEntity<>(e.getStatusText(), e.getStatusCode());
}
public ResponseEntity<Object> doPut(String url, Map<String, Object> body, Map<String, Object> query, Map<String, String> headers, String contentType) {
return doMethod(HttpMethod.PUT, url, query, body,headers, contentType, null);
}

public ResponseEntity<Object> doDelete(String url, Map<String, Object> body, Map<String, Object> query, Map<String, String> headers, String contentType) {
return doMethod(HttpMethod.DELETE, url, query, body,headers, contentType, null);
}

public ResponseEntity<Object> doGet(String url, Map<String, Object> query, Map<String, String> headers) {
public ResponseEntity<Object> doMethod(HttpMethod method,
String url,
Map<String, Object> query,
Map<String, Object> body,
Map<String, String> headers,
String contentType,
String plaintextValue) {
try {
MultiValueMap<String, String> qp = new LinkedMultiValueMap<>(
query.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e-> Arrays.asList(e.getValue().toString()))));

Object bodyValue;
if (method == HttpMethod.POST &&
"plaintext".equals(contentType) && plaintextValue != null)
bodyValue = plaintextValue;
else if (body == null)
bodyValue = new HashMap<>();
else
bodyValue = body;

return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(getHttpClient())).build()
.get()
.method(method)
.uri(url, uriBuilder -> uriBuilder.queryParams(qp).build())
.bodyValue(bodyValue)
.headers(httpHeaders -> addHeadersIfNotNull(headers, httpHeaders))
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.retrieve()
.toEntity(Object.class)
.block();

} catch (WebClientResponseException e) {
return new ResponseEntity<>(e.getStatusText(), e.getStatusCode());
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/ee/buerokratt/ruuter/service/DslService.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ private boolean allowedToExecuteDSLFrom(DslInstance dsl, String origin, String r
}

private Map<String, DslStep> getGuard(String method, String dslPath) {
if (dslPath.length()<=1 || dslPath.lastIndexOf('/') < 0)
if (dslPath.length()<=1)
return null;
String path = dslPath.substring(0, dslPath.lastIndexOf('/'));
String path = dslPath.contains("/") ? dslPath.substring(0, dslPath.lastIndexOf('/')) : "";
return guards.get(method).containsKey(path) ? guards.get(method).get(path) : getGuard(method, path);
}
}
3 changes: 2 additions & 1 deletion src/main/java/ee/buerokratt/ruuter/util/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public static String getFileNameWithPathWithoutSuffix(Path path) {

public static String getGuardWithPath(Path path) {
String fullPath = getFileNameWithPathWithoutSuffix(path);
return fullPath.substring(0, fullPath.lastIndexOf("/"));
String guard = fullPath.contains("/") ? fullPath.substring(0, fullPath.lastIndexOf("/")) : fullPath;
return guard;
}

public static Map<String, Map<String, String>> parseIniFile(File fileToParse) throws IOException {
Expand Down
Loading