Skip to content

Commit

Permalink
Design HTML + REST/JPA + model for the credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
Sgitario committed Nov 10, 2022
1 parent 00c3e66 commit bdab1e0
Show file tree
Hide file tree
Showing 17 changed files with 522 additions and 16 deletions.
9 changes: 9 additions & 0 deletions servicebox-app/src/main/java/io/halkyon/Templates.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ public static class Services {
public static native TemplateInstance form();
}

@CheckedTemplate(basePath = "credentials", requireTypeSafeExpressions = false)
public static class Credentials {
public static native TemplateInstance list(List<io.halkyon.model.Credential> credentials);

public static native TemplateInstance item(io.halkyon.model.Credential credential);

public static native TemplateInstance form();
}

@CheckedTemplate(basePath = "clusters")
public static class Clusters {
public static native TemplateInstance list(List<io.halkyon.model.Cluster> clusters);
Expand Down
46 changes: 46 additions & 0 deletions servicebox-app/src/main/java/io/halkyon/model/Credential.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.halkyon.model;

import java.sql.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;

import com.fasterxml.jackson.annotation.JsonBackReference;

import io.quarkus.hibernate.orm.panache.PanacheEntityBase;

@Entity
public class Credential extends PanacheEntityBase {

@Id
@SequenceGenerator(name = "creSeq", sequenceName = "cre_id_seq", allocationSize = 1, initialValue = 5)
@GeneratedValue(generator = "creSeq")
public Long id;

public String name;

@JsonBackReference
@ManyToOne
@JoinColumn(name = "service_id", nullable = false)
public Service service;

public String username;

public String password;

@OneToMany(mappedBy = "credential", cascade = CascadeType.ALL)
public List<CredentialParameter> params;
public Date created;

public static Credential findByName(String name) {
return find("name", name).firstResult();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.halkyon.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;

import com.fasterxml.jackson.annotation.JsonIgnore;

import io.quarkus.hibernate.orm.panache.PanacheEntityBase;

@Entity
public class CredentialParameter extends PanacheEntityBase {

@Id
@SequenceGenerator(name = "creParamSeq", sequenceName = "cre_param_id_seq", allocationSize = 1, initialValue = 5)
@GeneratedValue(generator = "creParamSeq")
public Long id;
public String paramName;
public String paramValue;

@JsonIgnore
@ManyToOne
@JoinColumn(name = "credential_id", nullable = false)
public Credential credential;
}
8 changes: 8 additions & 0 deletions servicebox-app/src/main/java/io/halkyon/model/Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
import org.jboss.resteasy.annotations.jaxrs.FormParam;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import java.sql.Date;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonManagedReference;

@Entity
@Table(indexes = @Index(columnList = "name,version", unique = true))
public class Service extends PanacheEntityBase {
Expand All @@ -36,6 +40,10 @@ public class Service extends PanacheEntityBase {
@FormParam
public Boolean deployed;

@JsonManagedReference
@OneToMany(mappedBy = "service", fetch = FetchType.LAZY)
public List<Credential> credentials;

@FormParam
public Date created;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.halkyon.resource;

import io.halkyon.model.Cluster;
import io.halkyon.model.Credential;
import io.quarkus.hibernate.orm.rest.data.panache.PanacheEntityResource;
import io.quarkus.rest.data.panache.ResourceProperties;

/***
* REST Data with Panache extension generates JAX-RS resources based on the presence of this interface.
* The @ResourceProperties annotation is used to customize the path of the resource.
* More information is available within the quarkus documentation: <a href="https://quarkus.io/guides/rest-data-panache">https://quarkus.io/guides/rest-data-panache</a>
* The endpoints generated support as HTTP request/response, the `application/json` content type.
*/
@ResourceProperties(path = "/credentials")
public interface CredentialResource extends PanacheEntityResource<Credential, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package io.halkyon.resource.page;

import java.sql.Date;
import java.util.ArrayList;
import java.util.List;

import javax.transaction.Transactional;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.jboss.resteasy.annotations.Form;

import io.halkyon.Templates;
import io.halkyon.model.Credential;
import io.halkyon.model.CredentialParameter;
import io.halkyon.model.Service;
import io.halkyon.resource.requests.NewCredentialRequest;
import io.halkyon.utils.AcceptedResponseBuilder;
import io.quarkus.qute.TemplateInstance;

@Path("/credentials")
public class CredentialResource {
@GET
@Path("/new")
@Produces(MediaType.TEXT_HTML)
public TemplateInstance newCredential() {
return Templates.Credentials.form()
.data("services", Service.listAll())
.data("title","Credential form");
}

@POST
@Transactional
@Consumes("application/x-www-form-urlencoded")
@Produces(MediaType.TEXT_HTML)
public Response add(@Form NewCredentialRequest request, @HeaderParam("HX-Request") boolean hxRequest) {
AcceptedResponseBuilder response = AcceptedResponseBuilder.withLocation("/credentials");
Credential credential = new Credential();
credential.name = request.name;
credential.username = request.username;
credential.password = request.password;
credential.service = Service.findById(request.serviceId);
credential.params = new ArrayList<>();
if (request.params != null) {
for (String param : request.params) {
String[] nameValue = param.split("=");
if (nameValue.length == 2) {
CredentialParameter paramEntity = new CredentialParameter();
paramEntity.credential = credential;
paramEntity.paramName = nameValue[0];
paramEntity.paramValue = nameValue[1];
credential.params.add(paramEntity);
}
}
}

if (credential.created == null) {
credential.created = new Date(System.currentTimeMillis());
}

credential.persist();
response.withSuccessMessage(credential.id);
// Return as HTML the template rendering the item for HTMX
return response.build();
}

@GET
@Produces(MediaType.TEXT_HTML)
@Consumes(MediaType.APPLICATION_JSON)
public TemplateInstance list() {
return showList(Credential.listAll()).data("all", true);
}

private TemplateInstance showList(List<Credential> credentials) {
return Templates.Credentials.list(credentials).data("items", Credential.count());
}


@GET
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/name/{name}")
public Credential findByName(@PathParam("name") String name) {
return Credential.findByName(name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.halkyon.resource.requests;

import java.util.List;

import org.jboss.resteasy.annotations.jaxrs.FormParam;

public class NewCredentialRequest {
@FormParam
public String name;

@FormParam
public Long serviceId;

@FormParam
public String username;

@FormParam
public String password;

@FormParam
public List<String> params;
}
3 changes: 3 additions & 0 deletions servicebox-app/src/main/resources/templates/app/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ <h1>Welcome to Primaza</h1>
<div class="col-2">
<div class="p-4 btn btn-primary" ><a id="home-clusters-btn-id" href="/clusters" class="text-white">Clusters</a></div>
</div>
<div class="col-2">
<div class="p-4 btn btn-primary" ><a id="home-credentials-btn-id" href="/credentials" class="text-white">Credentials</a></div>
</div>
</div>
</div>
</div>
Expand Down
114 changes: 114 additions & 0 deletions servicebox-app/src/main/resources/templates/credentials/form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
{@java.lang.Integer items}
{#include base}
{#title}Credential{/title}
{#body}
<div class="container" id="form">
<h1>New Credential</h1>
<form class="form-horizontal" action="/credentials" hx-post="/credentials" hx-target="#response" method="POST" hx-swap="innerHTML">
<div class="form-group">
<label class="control-label col-sm-2" for="credential_service">Service:</label>
<div class="col-sm-5">
<select id="credential_service" class="form-control new-credential" name="serviceId" required placeholder="Select the service for the credential">
{#for service in services}
<option value="{service.id}">{service.name}</option>
{/for}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="credential_name">Name:</label>
<div class="col-sm-5">
<input id="credential_name" class="form-control new-credential" type="text" name="name" placeholder="Credential name">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="credential_username">Username:</label>
<div class="col-sm-5">
<input id="credential_username" class="form-control new-credential" type="text" name="username" placeholder="Credential username">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="credential_password">Password:</label>
<div class="col-sm-5">
<input id="credential_password" class="form-control new-credential" type="password" name="password" placeholder="Credential password">
</div>
</div>
<div class="form-group table-responsive">
<label class="control-label col-sm-2">Parameters:</label>
<table class="table">
<thead>
<tr>
<th aria-valuetext="left">Name</th>
<th aria-valuetext="left">Value</th>
<th></th>
</tr>
</thead>
<tbody id="credential-params">
<tr>
<td>
<input id="new-param-name" class="form-control new-credential" name="params" type="text" placeholder="Param Name">
</td>
<td>
<input id="new-param-value" class="form-control new-credential" type="text" placeholder="Param Value">
</td>
<td>
<button id="add-param-to-credential-button" type="button" class="btn btn-secondary" onclick="addParameterRow()">Add</button>
</td>
</tr>
</tbody>
</table>
</div>
</br>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button id="new-credential-button" type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
<div style="height: 10px;"></div>
<div class="container">
<div id="response"/>
</div>
<hr>
<a href="/credentials">Back</a>
</div>
<hr>
<script >
function addParameterRow() {
var nameInput = document.getElementById("new-param-name");
var valueInput = document.getElementById("new-param-value");
var table = document.getElementById("credential-params");

// hidden input for form
var formInput = document.createElement("input");
formInput.type = "hidden";
formInput.name = "params";
formInput.value = nameInput.value + "=" + valueInput.value;

// delete button
var button = document.createElement("button");
button.class = "btn btn-secondary";
button.type = "button";
button.innerHTML = "Delete";
button.setAttribute("onclick", "deleteParameterRow(this)");

var newRow = table.insertRow(-1);
var cell1 = newRow.insertCell(0);
var cell2 = newRow.insertCell(1);
var cell3 = newRow.insertCell(2);
cell1.innerHTML = nameInput.value;
cell2.innerHTML = valueInput.value;
cell3.appendChild( button );
cell3.appendChild( formInput );

nameInput.value = "";
valueInput.value = "";
}

function deleteParameterRow(row) {
var i = row.parentNode.parentNode.rowIndex;
document.getElementById("credential-params").deleteRow(i - 1);
}
</script>
{/body}
{/include}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{@io.halkyon.model.Credential credential}
<tr>
<td>{credential.service.name}</td>
<td>{credential.name}</td>
<td>{credential.username}</td>
<td>{credential.password}</td>
</tr>
Loading

0 comments on commit bdab1e0

Please sign in to comment.