|
|
@ -1,7 +1,7 @@
|
|
|
|
## Personal Issue Tracker API Interface
|
|
|
|
## Personal Issue Tracker API Interface
|
|
|
|
## ====================================
|
|
|
|
## ====================================
|
|
|
|
|
|
|
|
|
|
|
|
import asyncdispatch, cliutils, docopt, jester, json, logging, sequtils, strutils
|
|
|
|
import asyncdispatch, cliutils, docopt, jester, json, logging, options, sequtils, strutils
|
|
|
|
import nre except toSeq
|
|
|
|
import nre except toSeq
|
|
|
|
|
|
|
|
|
|
|
|
import pitpkg/private/libpit
|
|
|
|
import pitpkg/private/libpit
|
|
|
@ -18,6 +18,20 @@ const TXT = "text/plain"
|
|
|
|
|
|
|
|
|
|
|
|
proc raiseEx(reason: string): void = raise newException(Exception, reason)
|
|
|
|
proc raiseEx(reason: string): void = raise newException(Exception, reason)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template halt(code: HttpCode,
|
|
|
|
|
|
|
|
headers: RawHeaders,
|
|
|
|
|
|
|
|
content: string): typed =
|
|
|
|
|
|
|
|
## Immediately replies with the specified request. This means any further
|
|
|
|
|
|
|
|
## code will not be executed after calling this template in the current
|
|
|
|
|
|
|
|
## route.
|
|
|
|
|
|
|
|
bind TCActionSend, newHttpHeaders
|
|
|
|
|
|
|
|
result[0] = CallbackAction.TCActionSend
|
|
|
|
|
|
|
|
result[1] = code
|
|
|
|
|
|
|
|
result[2] = some(headers)
|
|
|
|
|
|
|
|
result[3] = content
|
|
|
|
|
|
|
|
result.matched = true
|
|
|
|
|
|
|
|
break allRoutes
|
|
|
|
|
|
|
|
|
|
|
|
template checkAuth(cfg: PitApiCfg) =
|
|
|
|
template checkAuth(cfg: PitApiCfg) =
|
|
|
|
## Check this request for authentication and authorization information.
|
|
|
|
## Check this request for authentication and authorization information.
|
|
|
|
## If the request is not authorized, this template sets up the 401 response
|
|
|
|
## If the request is not authorized, this template sets up the 401 response
|
|
|
@ -40,30 +54,10 @@ template checkAuth(cfg: PitApiCfg) =
|
|
|
|
|
|
|
|
|
|
|
|
except:
|
|
|
|
except:
|
|
|
|
stderr.writeLine "Auth failed: " & getCurrentExceptionMsg()
|
|
|
|
stderr.writeLine "Auth failed: " & getCurrentExceptionMsg()
|
|
|
|
response.data[0] = CallbackAction.TCActionSend
|
|
|
|
halt(
|
|
|
|
response.data[1] = Http401
|
|
|
|
Http401,
|
|
|
|
response.data[2]["WWW-Authenticate"] = "Bearer"
|
|
|
|
@{"Content-Type": TXT},
|
|
|
|
response.data[2]["Content-Type"] = TXT
|
|
|
|
getCurrentExceptionMsg())
|
|
|
|
response.data[3] = getCurrentExceptionMsg()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc paramsToArgs(params: StringTableRef): tuple[stripAnsi: bool, args: seq[string]] =
|
|
|
|
|
|
|
|
result = (false, @[])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if params.hasKey("color"):
|
|
|
|
|
|
|
|
if params["color"] != "true":
|
|
|
|
|
|
|
|
result[0] = true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for k,v in params:
|
|
|
|
|
|
|
|
if k == "color": continue
|
|
|
|
|
|
|
|
elif k.startsWith("arg"): result[1].add(v) # support ?arg1=val1&arg2=val2 -> cmd val1 val2
|
|
|
|
|
|
|
|
else :
|
|
|
|
|
|
|
|
result[1].add("--" & k)
|
|
|
|
|
|
|
|
if v != "true": result[1].add(v) # support things like ?verbose=true -> cmd --verbose
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let STRIP_ANSI_REGEX = re"\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc stripAnsi(str: string): string =
|
|
|
|
|
|
|
|
return str.replace(STRIP_ANSI_REGEX, "")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc start*(cfg: PitApiCfg) =
|
|
|
|
proc start*(cfg: PitApiCfg) =
|
|
|
|
|
|
|
|
|
|
|
@ -79,20 +73,29 @@ proc start*(cfg: PitApiCfg) =
|
|
|
|
resp("pong", TXT)
|
|
|
|
resp("pong", TXT)
|
|
|
|
|
|
|
|
|
|
|
|
get "/issues":
|
|
|
|
get "/issues":
|
|
|
|
checkAuth(cfg); if not authed: return true
|
|
|
|
checkAuth(cfg)
|
|
|
|
|
|
|
|
|
|
|
|
var (stripAnsi, args) = paramsToArgs(request.params)
|
|
|
|
var args = queryParamsToCliArgs(request.params)
|
|
|
|
args = @["list"] & args
|
|
|
|
args = @["list"] & args
|
|
|
|
|
|
|
|
|
|
|
|
info "args: \n" & args.join(" ")
|
|
|
|
info "args: \n" & args.join(" ")
|
|
|
|
let execResult = execWithOutput("pit", ".", args)
|
|
|
|
let execResult = execWithOutput("pit", ".", args)
|
|
|
|
if execResult[2] != 0: resp(Http500, stripAnsi($execResult[0] & "\n" & $execResult[1]), TXT)
|
|
|
|
if execResult[2] != 0: resp(Http500, stripAnsi($execResult[0] & "\n" & $execResult[1]), TXT)
|
|
|
|
else:
|
|
|
|
else: resp(stripAnsi(execResult[0]), TXT)
|
|
|
|
if stripAnsi: resp(stripAnsi(execResult[0]), TXT)
|
|
|
|
|
|
|
|
else: resp(execResult[0], TXT)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
post "/issues":
|
|
|
|
post "/issues":
|
|
|
|
checkAuth(cfg); if not authed: return true
|
|
|
|
checkAuth(cfg)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get "/issue/@issueId":
|
|
|
|
|
|
|
|
checkAuth(cfg)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var args = queryParamsToCliArgs(request.params)
|
|
|
|
|
|
|
|
args = @["list", @"issueId"] & args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
info "args: \n" & args.join(" ")
|
|
|
|
|
|
|
|
let execResult = execWithOutput("pit", ".", args)
|
|
|
|
|
|
|
|
if execResult[2] != 0: resp(Http500, stripAnsi($execResult[0] & "\n" & $execResult[1]), TXT)
|
|
|
|
|
|
|
|
else: resp(stripAnsi(execResult[0]), TXT)
|
|
|
|
|
|
|
|
|
|
|
|
waitFor(stopFuture)
|
|
|
|
waitFor(stopFuture)
|
|
|
|
|
|
|
|
|
|
|
|