added prototype web interface written in nim
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "nim/htmlutils"]
|
||||
path = nim/htmlutils
|
||||
url = ssh://git@nuc/mnt/git/htmlutils
|
5
nim/build.nims
Executable file
5
nim/build.nims
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env nim
|
||||
|
||||
task build, "builds an example":
|
||||
setCommand "js"
|
||||
#os.copyfile("")
|
4
nim/build.sh
Executable file
4
nim/build.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
nim js jpacrepo.nim
|
||||
cp nimcache/jpacrepo.js static
|
1
nim/htmlutils
Submodule
1
nim/htmlutils
Submodule
Submodule nim/htmlutils added at 37365137d3
269
nim/jpacrepo.nim
Normal file
269
nim/jpacrepo.nim
Normal file
@@ -0,0 +1,269 @@
|
||||
import dom
|
||||
import htmlutils.utils
|
||||
import json
|
||||
import streams
|
||||
import tables
|
||||
import strutils
|
||||
import sets
|
||||
from sequtils import map, apply
|
||||
|
||||
var pkgMap : OrderedTable[string, JsonNode]
|
||||
|
||||
type DownloadPanel = ref object
|
||||
badge : Node
|
||||
listgroup : Node
|
||||
pkgs : HashSet[string]
|
||||
body : Node
|
||||
|
||||
proc newDownloadPanel(parent : Node) : DownloadPanel =
|
||||
let dp = DownloadPanel()
|
||||
dp.pkgs = initSet[string]()
|
||||
htmlDocument(document, parent):
|
||||
"div":
|
||||
class ["panel", "panel-default"]
|
||||
"div":
|
||||
class ["panel-heading"]
|
||||
"h3":
|
||||
class ["panel-title"]
|
||||
"a":
|
||||
#attrs {"data-toggle": "collapse", "href": "#dlist"}
|
||||
text "Package list "
|
||||
"span":
|
||||
class ["badge", "pull-right"]
|
||||
style {"display" :"none"}
|
||||
cb:
|
||||
dp.badge = node
|
||||
|
||||
"ul":
|
||||
class ["list-group"]
|
||||
cb:
|
||||
dp.listgroup = node
|
||||
"div":
|
||||
class ["panel-body"]
|
||||
style {
|
||||
"text-align" : "right",
|
||||
"display" :"none"
|
||||
}
|
||||
"button":
|
||||
class ["btn", "btn-primary"]
|
||||
attrs {"type" : "button"}
|
||||
"span":
|
||||
class ["glyphicon", "glyphicon-download"]
|
||||
cb:
|
||||
node.appendChild(document.createTextNode(" Download"))
|
||||
cb:
|
||||
dp.body = node
|
||||
dp
|
||||
|
||||
|
||||
proc updateBadge(dp : DownloadPanel) =
|
||||
let st = if dp.pkgs.len() > 0: "block" else: "none"
|
||||
dp.body.style.display = st
|
||||
dp.badge.style.display = st
|
||||
dp.badge.textContent = $dp.pkgs.len()
|
||||
|
||||
proc addPkg(dp : DownloadPanel, pkgfile : string) =
|
||||
if not dp.pkgs.contains(pkgfile):
|
||||
dp.pkgs.incl(pkgfile)
|
||||
htmlDocument(document, dp.listgroup):
|
||||
"li":
|
||||
var listElement : Node
|
||||
class ["list-group-item"]
|
||||
text pkgfile
|
||||
"span":
|
||||
class ["glyphicon", "glyphicon-remove", "pull-right"]
|
||||
cb:
|
||||
let fn = proc(e : Event) =
|
||||
dp.pkgs.excl(pkgfile)
|
||||
listElement.remove()
|
||||
dp.updateBadge
|
||||
node.addEventListener("click", fn)
|
||||
cb:
|
||||
listElement = node
|
||||
|
||||
dp.updateBadge
|
||||
|
||||
proc createDropdown(parent : Node, data :seq[string], onchange : proc(value : string)) =
|
||||
htmlDocument(document, parent):
|
||||
"div":
|
||||
var button : Node
|
||||
class ["dropdown"]
|
||||
"button":
|
||||
class ["btn", "btn-default", "dropdown-toggle"]
|
||||
attrs {"data-toggle": "dropdown", "type": "button"}
|
||||
cb:
|
||||
for line in data:
|
||||
node.textContent = line
|
||||
break
|
||||
button = node
|
||||
"ul":
|
||||
class ["dropdown-menu"]
|
||||
cb:
|
||||
for line in data:
|
||||
htmlDocument(document, node):
|
||||
"li":
|
||||
"a":
|
||||
text line
|
||||
cb:
|
||||
let fn = proc(e: Event) =
|
||||
button.textContent = node.textContent
|
||||
onchange($node.textContent)
|
||||
node.addEventListener("click", fn)
|
||||
|
||||
type PkgTable = ref object
|
||||
addButton : Node
|
||||
|
||||
proc newPkgTable(parent: Node, searchString : string) : PkgTable =
|
||||
var pkgtable = PkgTable()
|
||||
var fragments = newSeq[string]()
|
||||
for fragment in searchString.splitWhitespace():
|
||||
fragments.add(fragment)
|
||||
var searchResult = newOrderedTable[string,JsonNode]()
|
||||
for key, value in pkgMap:
|
||||
for fragment in fragments:
|
||||
if fragment in key:
|
||||
searchResult.add(key,value)
|
||||
for table in document.querySelectorAll("table.pkgtable"):
|
||||
table.parentNode.removeChild(table)
|
||||
htmlDocument(document, parent):
|
||||
"table":
|
||||
class ["table", "table-striped","pkgtable"]
|
||||
"thead":
|
||||
"tr":
|
||||
"th":
|
||||
"button":
|
||||
class ["btn", "btn-default"]
|
||||
attrs {"type": "button"}
|
||||
"span":
|
||||
class ["glyphicon", "glyphicon-plus"]
|
||||
cb:
|
||||
let txt = document.createTextNode(" Add")
|
||||
node.appendChild(txt)
|
||||
pkgtable.addButton = node
|
||||
"th":
|
||||
text "Name"
|
||||
"th":
|
||||
text "Version"
|
||||
"th":
|
||||
text "Arch"
|
||||
"tbody":
|
||||
cb:
|
||||
var i = 0
|
||||
for name, versions in searchResult:
|
||||
closureScope:
|
||||
htmlDocument(document, node):
|
||||
"tr":
|
||||
var archCell : Node
|
||||
"td":
|
||||
"div":
|
||||
class ["checkbox"]
|
||||
"label":
|
||||
"input":
|
||||
attrs {"type" : "checkbox"}
|
||||
"td":
|
||||
text $name
|
||||
"td":
|
||||
cb:
|
||||
var data = newSeq[string]()
|
||||
for version, arches in versions:
|
||||
data.add(version)
|
||||
let vs = versions
|
||||
let change_callback = proc(newValue : string) =
|
||||
archCell.removeChildren()
|
||||
var newdata = newSeq[string]()
|
||||
for arch, pkgname in vs[newValue]:
|
||||
newdata.add(arch)
|
||||
createDropdown(archCell, newdata, proc(s : string) = discard)
|
||||
createDropdown(node, data, change_callback)
|
||||
"td":
|
||||
cb:
|
||||
archCell = node
|
||||
var data = newSeq[string]()
|
||||
var arches : JsonNode
|
||||
for v, a in versions:
|
||||
arches = a
|
||||
for arch, pkgname in arches:
|
||||
data.add(arch)
|
||||
createDropdown(node, data, proc(s : string) = discard)
|
||||
pkgtable
|
||||
|
||||
var dp : DownloadPanel
|
||||
# var pkgTable : PkgTable
|
||||
htmlDocument document, document.body:
|
||||
# "img":
|
||||
# attrs {"src" : "img/background.bpg"}
|
||||
# style {
|
||||
# "width" : "100%",
|
||||
# "position" : "fixed",
|
||||
# "bottom" : "0",
|
||||
# "left" : "0",
|
||||
# "z-index" : "-10"
|
||||
# }
|
||||
"div":
|
||||
var table : Node
|
||||
style {"background-color" : "rgba(255, 255, 255, 0.25)"}
|
||||
class ["container"]
|
||||
"div":
|
||||
style {
|
||||
"margin-top" : "20px",
|
||||
"background-color" : "rgba(224, 224, 224, 0.5)"
|
||||
}
|
||||
class ["jumbotron"]
|
||||
"h1":
|
||||
text "Jpacrepo"
|
||||
"p":
|
||||
text "Personal archlinux package repository"
|
||||
"div":
|
||||
"form":
|
||||
class ["form-horizontal"]
|
||||
"div":
|
||||
class ["form-group"]
|
||||
"label":
|
||||
class ["control-label", "col-sm-2"]
|
||||
text " Search package"
|
||||
"div":
|
||||
class ["col-sm-10"]
|
||||
"input":
|
||||
class ["form-control"]
|
||||
attrs {"type" : "text"}
|
||||
cb :
|
||||
proc add2DownloadList(e : Event) =
|
||||
let rows = table.querySelectorAll("tbody tr")
|
||||
for row in rows:
|
||||
let cbox = row.querySelector("td:first-child input")
|
||||
if cbox.checked:
|
||||
let pkgname = $row.querySelector("td:nth-child(2)").textContent
|
||||
let version = $row.querySelector("td:nth-child(3) button").textContent
|
||||
let arch = $row.querySelector("td:nth-child(4) button").textContent
|
||||
dp.addPkg(pkgMap[pkgname][version][arch].getStr)
|
||||
proc oninput(e : Event) =
|
||||
if pkgMap.len == 0 or node.value.len < 2: return
|
||||
let pkgtable = newPkgTable(table, $node.value)
|
||||
pkgtable.addButton.addEventListener("click", add2DownloadList)
|
||||
node.addEventListener("input", oninput)
|
||||
"div":
|
||||
class ["row"]
|
||||
"div":
|
||||
class ["col-sm-3"]
|
||||
cb:
|
||||
dp = newDownloadPanel(node)
|
||||
"div":
|
||||
class ["col-sm-9"]
|
||||
cb:
|
||||
table = node
|
||||
|
||||
|
||||
|
||||
|
||||
let r = newXMLHTTPRequest()
|
||||
let load_cb = proc(e : Event) =
|
||||
let response = parseJson($r.responseText)
|
||||
pkgMap = response.getFields()
|
||||
# var keys = newSeq[string]()
|
||||
# for key in response.getFields().keys():
|
||||
# keys.add(key)
|
||||
# echo keys
|
||||
r.addEventListener("load", load_cb)
|
||||
r.open("get", "http://oggio88.soon.it/jpacrepo/rest/pkg/map")
|
||||
r.setRequestHeader("Accept", "application/json")
|
||||
r.send()
|
13
nim/static/index.html
Normal file
13
nim/static/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="jpacrepo.css" type="text/css">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
|
||||
<script src="jpacrepo.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
@@ -0,0 +1,11 @@
|
||||
package com.oggio88.jpacrepo.annotation;
|
||||
|
||||
import javax.ws.rs.NameBinding;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@NameBinding
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CORSManaged
|
||||
{
|
||||
}
|
@@ -33,6 +33,8 @@ public class ApplicationContext
|
||||
|
||||
public boolean invalidateCache = true;
|
||||
|
||||
public boolean cors_enabled;
|
||||
|
||||
public ApplicationContext(String propertyFile)
|
||||
{
|
||||
systemProperties = new Properties();
|
||||
@@ -65,6 +67,10 @@ public class ApplicationContext
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String prop = System.getProperty("org.oggio88.jpacrepo.cors");
|
||||
if (prop != null)
|
||||
cors_enabled = Boolean.parseBoolean(prop);
|
||||
}
|
||||
|
||||
public Properties getSystemProperties()
|
||||
|
@@ -24,6 +24,7 @@ public class ApplicationConfig extends Application
|
||||
{
|
||||
HashSet<Class<?>> c = new HashSet<>();
|
||||
c.add(PacmanWebService.class);
|
||||
c.add(CORSFilter.class);
|
||||
classes = Collections.unmodifiableSet(c);
|
||||
}
|
||||
|
||||
|
35
src/main/java/com/oggio88/jpacrepo/service/CORSFilter.java
Normal file
35
src/main/java/com/oggio88/jpacrepo/service/CORSFilter.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.oggio88.jpacrepo.service;
|
||||
|
||||
import com.oggio88.jpacrepo.annotation.CORSManaged;
|
||||
import com.oggio88.jpacrepo.context.ApplicationContext;
|
||||
import com.oggio88.jpacrepo.context.DefaultConfiguration;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.container.ContainerRequestContext;
|
||||
import javax.ws.rs.container.ContainerResponseContext;
|
||||
import javax.ws.rs.container.ContainerResponseFilter;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Provider
|
||||
@CORSManaged
|
||||
public class CORSFilter implements ContainerResponseFilter
|
||||
{
|
||||
private final Logger log = Logger.getLogger(CORSFilter.class.getName());
|
||||
|
||||
@Inject
|
||||
@DefaultConfiguration
|
||||
ApplicationContext ctx;
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext containerRequestContext,
|
||||
ContainerResponseContext containerResponseContext) throws IOException
|
||||
{
|
||||
if (!ctx.cors_enabled)
|
||||
{
|
||||
containerResponseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.oggio88.jpacrepo.service;
|
||||
|
||||
import com.oggio88.jpacrepo.annotation.CORSManaged;
|
||||
import com.oggio88.jpacrepo.context.ApplicationContext;
|
||||
import com.oggio88.jpacrepo.context.DefaultConfiguration;
|
||||
import com.oggio88.jpacrepo.model.PkgData;
|
||||
@@ -8,6 +9,7 @@ import com.oggio88.jpacrepo.model.PkgName;
|
||||
import com.oggio88.jpacrepo.model.StringList;
|
||||
import com.oggio88.jpacrepo.pacbase.Parser;
|
||||
import com.oggio88.jpacrepo.persistence.QueryEngine;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.ejb.*;
|
||||
@@ -30,6 +32,7 @@ import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@CORSManaged
|
||||
@Singleton
|
||||
@Path("/pkg")
|
||||
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
|
||||
@@ -59,35 +62,6 @@ public class PacmanWebService
|
||||
@DefaultConfiguration
|
||||
private ApplicationContext ctx;
|
||||
|
||||
@GET
|
||||
@Path("search")
|
||||
public Response getPackage(@QueryParam("name") String name,
|
||||
@QueryParam("version") String version,
|
||||
@QueryParam("arch") String arch,
|
||||
@QueryParam("filename") String filename,
|
||||
@QueryParam("md5sum") String md5sum)
|
||||
{
|
||||
if (md5sum != null)
|
||||
{
|
||||
return getPackageByHash(md5sum);
|
||||
}
|
||||
else if (filename != null)
|
||||
{
|
||||
return getPackageByFileName(filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
QueryEngine qe = new QueryEngine(PkgData.class);
|
||||
qe.select();
|
||||
if (name != null) qe.where("name", "=", name);
|
||||
if (version != null) qe.where("version", "=", version);
|
||||
if (arch != null) qe.where("arch", "=", arch);
|
||||
String query = qe.build();
|
||||
return manageQueryResult(em.createQuery(query).getResultList());
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("searchByName/{name}")
|
||||
public Response searchByName(@PathParam("name") String name)
|
||||
@@ -139,6 +113,7 @@ public class PacmanWebService
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("map")
|
||||
public Response getPackageMap()
|
||||
{
|
||||
@@ -317,6 +292,7 @@ public class PacmanWebService
|
||||
}
|
||||
|
||||
@GET
|
||||
@CORSManaged
|
||||
@Path("/search")
|
||||
public List<PkgData> searchPackage(
|
||||
@QueryParam("name") String name,
|
||||
@@ -377,6 +353,12 @@ public class PacmanWebService
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
@POST
|
||||
public Response foo()
|
||||
{
|
||||
TarArchiveouputStream tais = new TarArchiveOutputStream();
|
||||
}
|
||||
|
||||
private Response manageQueryResult(List<PkgData> list)
|
||||
{
|
||||
return manageQueryResult(list, false);
|
||||
|
Reference in New Issue
Block a user