Skip to content

Instantly share code, notes, and snippets.

@juanplopes
Created February 13, 2020 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save juanplopes/4f4a2bdea6d511981d322b957bc43cdc to your computer and use it in GitHub Desktop.
Save juanplopes/4f4a2bdea6d511981d322b957bc43cdc to your computer and use it in GitHub Desktop.
import net.intelie.live.*
import net.intelie.live.util.*
import net.intelie.live.queries.*
import net.intelie.live.model.*
import javax.ws.rs.*
import javax.ws.rs.core.*
import javax.servlet.http.*
import org.springframework.security.web.csrf.*
import org.springframework.web.util.*
import com.google.gson.*
@Path("/")
@Consumes("text/html")
@Produces("text/html")
@UseProxy
class SettingsResource {
String rootUrl, otherUrl;
SettingsNode root;
EntityContext entities;
boolean safe;
SettingsResource(boolean safe, String rootUrl, String otherUrl, SettingsNode root, EntityContext entities) {
this.safe = safe;
this.rootUrl = rootUrl
this.otherUrl = otherUrl
this.root = root
this.entities = entities
}
@GET
@NeedsAuthority(value = [Permission.ADMIN])
Response index() {
return Response.seeOther(URI.create("/tree/")).build();
}
@GET
@Path("/raw/{path:.*}")
@NeedsAuthority(value = [Permission.ADMIN])
@Produces("application/json")
String raw(@PathParam("path") String path) {
return root.cd(path).raw();
}
@GET
@Path("/rawlog/{id}/old")
@NeedsAuthority(value = [Permission.ADMIN])
@Produces("application/json")
String rawOld(@PathParam("id") int id) {
return entities.get(SettingLog.class, id).oldValue;
}
@GET
@Path("/rawlog/{id}/new")
@NeedsAuthority(value = [Permission.ADMIN])
@Produces("application/json")
String rawNew(@PathParam("id") int id) {
return entities.get(SettingLog.class, id).newValue;
}
@GET
@Path("/log/{path:.*}")
@NeedsAuthority(value = [Permission.ADMIN])
String fulllog(@PathParam("path") String path, @QueryParam("children") @DefaultValue("false") boolean children, @Context HttpServletRequest request) {
def dir = root.cd(path)
def level = PathUtils.level(dir.path())
def list = entities.find(new AllSettingLogs().byIdPrefixAndLevel(dir.path(), level, children?Integer.MAX_VALUE:level)
.orderByDescending("dateCreated")
.page(1)
.pageSize(100))
def builder = new StringBuilder()
header(builder, dir, request)
builder.append("<p><it>Showing at most 100 recent operations</it></p>")
builder.append("<table border=1>")
builder.append("<tr>");
builder.append("<th>id</th>");
builder.append("<th>date</th>");
builder.append("<th>user</th>");
builder.append("<th>op</th>");
builder.append("<th>path</th>");
builder.append("<th>new</th>");
builder.append("<th>old</th>");
builder.append("</tr>");
list.each {
builder.append("<tr>");
builder.append("<td>${it.id}</td>");
builder.append("<td>${new Date(it.dateCreated)}</td>");
if (it.author != null)
builder.append("<td><a href='${LiveUrls.user(it.author.id)}'>${it.author.displayName}</a></td>");
else
builder.append("<td>&lt;system&gt;</td>");
builder.append("<td>${it.operation}</td>");
builder.append("<td><a href='${rootUrl}/tree${it.settingId}'>${it.settingId}</a></td>");
builder.append("<td><a href='${rootUrl}/rawlog/${it.id}/new'>[raw]</a> ${truncate(it.newValue, 32)}</td>");
builder.append("<td><a href='${rootUrl}/rawlog/${it.id}/old'>[raw]</a> ${truncate(it.oldValue, 32)}</td>");
builder.append("</tr>");
}
builder.append("</table>")
return builder.toString()
}
@POST
@Path("/delete/{path:.*}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@NeedsAuthority(value = [Permission.ADMIN])
Response delete(@PathParam("path") String path) {
def dir = root.cd(path)
dir.delete()
String returl = "/tree" + PathUtils.parents(dir.path()).stream().findFirst().orElse('/')
return Response.seeOther(new URI(returl)).build();
}
@GET
@Path("/tree/{path:.*}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@NeedsAuthority(value = [Permission.ADMIN])
String tree(@PathParam("path") String path, @Context HttpServletRequest request) {
def dir = root.cd(path)
def builder = new StringBuilder()
header(builder, dir, request)
builder.append("<b>Value:</b><br/>${truncate(dir.raw(), 1024)}<br/>");
builder.append("<hr/>");
def children = dir.children()
if (children.size() > 0) {
builder.append("<b>Children:</b><br/>");
builder.append("<table>")
children.each {
builder.append("<tr>");
builder.append("<td><a href='${rootUrl}/log${it.path()}'>[log]</a></td>");
builder.append("<td><a href='${rootUrl}/log${it.path()}?children=true'>[full log]</a></td>");
builder.append("<td><a href='${it.name()}/'>${it.name()}/</a><td>");
builder.append("<td>(${truncate(it.raw(), 80)} <a href='${rootUrl}/raw${it.path()}'>[raw]</a>)</td>");
builder.append("</tr>");
}
builder.append("</table>")
}
return builder.toString()
}
@GET
@Path("/new/{path:.*}")
@NeedsAuthority(value = [Permission.ADMIN])
String newChild(@PathParam("path") String path, @Context HttpServletRequest request) {
def dir = root.cd(path)
def builder = new StringBuilder()
header(builder, dir, request)
builder.append("<form method='post'>");
builder.append(csrfInput(request))
builder.append("<b>New node name:</b><br><input type='text' name='name' size=80 /><br/>");
builder.append("<b>Value:</b><br/><textarea name='raw' rows='20' cols='120'></textarea><br/>");
builder.append("""
<input type='submit' value='ARE YOU SURE YOU WANT TO SUBMIT? OF COURSE I WILL CONFIRM AGAIN IF YOU CLICK.' onclick='return confirm("ARE YOU REALLY SURE?\\nnew child at: ${dir.path()}");'>
""");
builder.append("</form>");
return builder.toString()
}
@POST
@Path("/new/{path:.*}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@NeedsAuthority(value = [Permission.ADMIN])
Response newChildPost(@PathParam("path") String path, @FormParam("name") String name, @FormParam("raw") String raw) {
if (name.isEmpty()) throw new IllegalArgumentException("Must have name")
def dir = root.cd(path).cd(name)
dir.set(LiveJson.create().fromJson(raw, JsonElement.class))
String returl = "/tree${dir.path()}"
return Response.seeOther(new URI(returl)).build();
}
@GET
@Path("/edit/{path:.*}")
@NeedsAuthority(value = [Permission.ADMIN])
String edit(@PathParam("path") String path, @Context HttpServletRequest request) {
def dir = root.cd(path)
def builder = new StringBuilder()
header(builder, dir, request)
builder.append("<form method='post'>");
builder.append(csrfInput(request))
builder.append("<b>Value:</b><br/><textarea name='raw' rows='20' cols='120'>${HtmlUtils.htmlEscape(dir.raw())}</textarea><br/>");
builder.append("""
<input type='submit' value='ARE YOU SURE YOU WANT TO SUBMIT? OF COURSE I WILL CONFIRM AGAIN IF YOU CLICK.' onclick='return confirm("ARE YOU REALLY SURE?\\nediting: ${dir.path()}");'>
""");
builder.append("</form>");
return builder.toString()
}
@POST
@Path("/edit/{path:.*}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@NeedsAuthority(value = [Permission.ADMIN])
Response editPost(@PathParam("path") String path, @FormParam("raw") String raw) {
def dir = root.cd(path)
dir.set(LiveJson.create().fromJson(raw, JsonElement.class))
String returl = "/tree${dir.path()}"
return Response.seeOther(new URI(returl)).build();
}
CsrfToken getCsrf(HttpServletRequest request) {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
CsrfToken token = repository.loadToken(request);
if (token == null) {
token = repository.generateToken(request);
repository.saveToken(token, request, null);
}
return token;
}
def deleteButton(String path, HttpServletRequest request) {
}
def csrfInput(HttpServletRequest request) {
def csrf = getCsrf(request)
return "<input type='hidden' name='${csrf.parameterName}' value='${csrf.token}'/>"
}
def truncate(String s, int size) {
if (s == null) return null;
if (s.length() > size) return HtmlUtils.htmlEscape(s.substring(0, size)) + "...";
return s
}
def header(StringBuilder builder, SettingsNode dir, HttpServletRequest request) {
builder.append("<h1>")
builder.append("<a href='${rootUrl}/tree/'>&lt;root&gt;</a>");
PathUtils.parents(dir.path()).reverse().each {
builder.append(" / <a href='${rootUrl}/tree${it}'>${PathUtils.last(it)}</a>");
}
if (dir.path() != "/")
builder.append(" / <a href='${rootUrl}/tree${dir.path()}'>${PathUtils.last(dir.path())}</a>");
builder.append("</h1>")
builder.append("<a href='${rootUrl}/tree${dir.path()}'>[tree]</a>");
builder.append(" <a href='${rootUrl}/log${dir.path()}'>[log]</a>");
builder.append(" <a href='${rootUrl}/log${dir.path()}?children=true'>[full log]</a>");
builder.append(" <a href='${rootUrl}/raw${dir.path()}'>[raw]</a>");
if (!safe) {
builder.append("""<hr/>
<form method='post' action='${rootUrl}/delete${dir.path()}'>
${csrfInput(request)}
UNSAFE:
<a href='${otherUrl}${request.getPathInfo()}'>[BACK TO SAFETY]</a>
<a href='${rootUrl}/edit${dir.path()}'>[edit]</a>
<a href='${rootUrl}/new${dir.path()}'>[new child]</a>
<input type='submit' value='DELETE (OF COURSE I WILL CONFIRM AGAIN IF YOU CLICK)' onclick='return confirm("ARE YOU REALLY SURE?\\ndeleting: ${dir.path()}");'>
</form>
""");
} else {
builder.append("""<hr/>
<a href='${otherUrl}${request.getPathInfo()}'>[ENABLE UNSAFE CONTROLS]</a>
""");
}
builder.append("<hr/>");
}
}
def root = live.settings().root()
def entities = live.data().getContext()
def safeUrl = live.web().resolveService('settings')
def unsafeUrl = live.web().resolveService('settings/unsafe')
live.web().addService('settings', new SettingsResource(
true, safeUrl, unsafeUrl, root, entities));
live.web().addService('settings/unsafe', new SettingsResource(
false, unsafeUrl, safeUrl, root, entities));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment