init commit to reduce size
commit
510472b116
|
@ -0,0 +1,5 @@
|
||||||
|
cavepedia-data
|
||||||
|
cavepedia.bleve
|
||||||
|
cavepedia.env
|
||||||
|
**/cavepedia_*
|
||||||
|
cavepedia-*.zip
|
|
@ -0,0 +1,41 @@
|
||||||
|
# cavepedia
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- go 1.16+
|
||||||
|
|
||||||
|
|
||||||
|
## Add more documents
|
||||||
|
|
||||||
|
1. Download documents to `/bigdata/archive/cavepedia/cavepedia-data/00_files`
|
||||||
|
1. Process documents to generate json files
|
||||||
|
1. Create a new release
|
||||||
|
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
1. Download latest release
|
||||||
|
1. Run it
|
||||||
|
|
||||||
|
|
||||||
|
## Run in docker
|
||||||
|
|
||||||
|
1. Run `./docker.sh up`
|
||||||
|
|
||||||
|
|
||||||
|
## Release
|
||||||
|
|
||||||
|
On a reasonably powerful PC that can access `/bigdata`:
|
||||||
|
|
||||||
|
1. Remove `cavepedia.bleve` if it exists
|
||||||
|
1. Run `./launch.sh build release` to build linux and windows binaries
|
||||||
|
1. Run `./launch.sh run` to index documents
|
||||||
|
1. Run `./launch.sh release` to bundle the data, binaries, docker.sh script, and index data into a zip
|
||||||
|
1. Copy the zip to `/bigdata/archive/cavepedia/release/cavepedia-X.Y.zip`
|
||||||
|
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- highlight fuzzy matching
|
||||||
|
- speed up pdf loading
|
||||||
|
- Remove cavepedia-data repo eventually
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
RELEASE=2.2
|
||||||
|
|
||||||
|
build () {
|
||||||
|
echo "Building cavepedia/cavepedia:$RELEASE"
|
||||||
|
docker build -t cavepedia/cavepedia:$RELEASE ./src
|
||||||
|
}
|
||||||
|
|
||||||
|
import_data () {
|
||||||
|
echo "Importing cavepedia.bleve version $RELEASE"
|
||||||
|
if [ ! -f ./cavepedia-$RELEASE.zip ]; then
|
||||||
|
cp -r /bigdata/archive/cavepedia/release/cavepedia-$RELEASE.zip .
|
||||||
|
unzip cavepedia-$RELEASE.zip
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
up () {
|
||||||
|
build
|
||||||
|
import_data
|
||||||
|
|
||||||
|
docker network create pew-net || true
|
||||||
|
|
||||||
|
# Exposed on port 3000 on pew-net
|
||||||
|
docker run \
|
||||||
|
--detach \
|
||||||
|
--name cavepedia \
|
||||||
|
--restart unless-stopped \
|
||||||
|
--env PROXY=1 \
|
||||||
|
--env-file cavepedia.env \
|
||||||
|
--volume $PWD/cavepedia-$RELEASE/cavepedia-data:/go/src/app/cavepedia-data:ro \
|
||||||
|
--volume $PWD/cavepedia-$RELEASE/cavepedia.bleve:/go/src/app/cavepedia.bleve:rw \
|
||||||
|
--network pew-net \
|
||||||
|
cavepedia/cavepedia:$RELEASE
|
||||||
|
}
|
||||||
|
|
||||||
|
down () {
|
||||||
|
docker stop cavepedia || true
|
||||||
|
docker rm cavepedia || true
|
||||||
|
}
|
||||||
|
|
||||||
|
logs () {
|
||||||
|
docker logs --follow cavepedia
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$@
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
RELEASE=2.2
|
||||||
|
ln -sn /bigdata/archive/cavepedia/cavepedia-data ./cavepedia-data || true
|
||||||
|
|
||||||
|
build_docker () {
|
||||||
|
docker rm cavepedia-build || true
|
||||||
|
docker build -t cavepedia/cavepedia-build:latest ./src
|
||||||
|
docker create --name cavepedia-build cavepedia/cavepedia-build:latest
|
||||||
|
docker cp cavepedia-build:/go/src/app/cavepedia_linux_amd64 ./src/cavepedia_linux_amd64
|
||||||
|
docker cp cavepedia-build:/go/src/app/cavepedia_windows_amd64.exe ./src/cavepedia_windows_amd64.exe
|
||||||
|
}
|
||||||
|
|
||||||
|
build () {
|
||||||
|
pushd ./src &>/dev/null
|
||||||
|
|
||||||
|
go get honnef.co/go/tools/cmd/staticcheck
|
||||||
|
go get github.com/dgrijalva/jwt-go
|
||||||
|
go get github.com/zserge/lorca
|
||||||
|
|
||||||
|
gofmt -w .
|
||||||
|
staticcheck .
|
||||||
|
CGO_ENABLED=1 GOARCH=amd64 go build -o ./cavepedia_linux_amd64 -v .
|
||||||
|
|
||||||
|
if [[ "$1" == "release" ]]; then
|
||||||
|
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc go build -ldflags -H=windowsgui -o ./cavepedia_windows_amd64.exe -v .
|
||||||
|
fi
|
||||||
|
|
||||||
|
popd &>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default: bypass password and open in webview
|
||||||
|
run () {
|
||||||
|
./src/cavepedia_linux_amd64
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable webview, enable password
|
||||||
|
proxy () {
|
||||||
|
PROXY=1 PASSWORD=test ./src/cavepedia_linux_amd64
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable webview only
|
||||||
|
proxy_test () {
|
||||||
|
PROXY=1 ./src/cavepedia_linux_amd64
|
||||||
|
}
|
||||||
|
|
||||||
|
release () {
|
||||||
|
mkdir cavepedia-$RELEASE
|
||||||
|
mv src/{cavepedia_linux_amd64,cavepedia_windows_amd64.exe} ./cavepedia-$RELEASE/
|
||||||
|
mv cavepedia.bleve ./cavepedia-$RELEASE
|
||||||
|
mkdir cavepedia-$RELEASE/cavepedia-data/
|
||||||
|
cp -r cavepedia-data/{00_files,02_json} ./cavepedia-$RELEASE/cavepedia-data/
|
||||||
|
|
||||||
|
zip -r cavepedia-$RELEASE.zip ./cavepedia-$RELEASE
|
||||||
|
sudo cp cavepedia-$RELEASE.zip /bigdata/archive/cavepedia/release/
|
||||||
|
rm -rf cavepedia-$RELEASE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$@
|
|
@ -0,0 +1,16 @@
|
||||||
|
FROM golang:1.16-buster
|
||||||
|
|
||||||
|
LABEL org.opencontainers.image.source https://git.seaturtle.pw/pew/cavepedia
|
||||||
|
LABEL maintainer="Paul Walko <paulsw.pw@gmail.com>"
|
||||||
|
|
||||||
|
WORKDIR /go/src/app
|
||||||
|
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=1 GOARCH=amd64 go build -o ./cavepedia_linux_amd64 -v .
|
||||||
|
RUN CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc go build -ldflags -H=windowsgui -o ./cavepedia_windows_amd64.exe -v .
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["./cavepedia_linux_amd64"]
|
|
@ -0,0 +1,31 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkError(err error) bool {
|
||||||
|
if err != nil {
|
||||||
|
log.Print("ERROR! " + err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HTTP */
|
||||||
|
func checkWebError(w http.ResponseWriter, err error) bool {
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURLParam(r *http.Request, param string) string {
|
||||||
|
paramList, exists := r.URL.Query()[param]
|
||||||
|
if !exists {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return paramList[0]
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.seaturtle.pw/pew/cavepedia/utils"
|
||||||
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Key for signing JWTs
|
||||||
|
var key []byte
|
||||||
|
|
||||||
|
func deleteCookie(w http.ResponseWriter, name string, domain string) {
|
||||||
|
cookie := http.Cookie{
|
||||||
|
Domain: domain,
|
||||||
|
MaxAge: -1,
|
||||||
|
Name: name,
|
||||||
|
Path: "/",
|
||||||
|
Value: "",
|
||||||
|
}
|
||||||
|
http.SetCookie(w, &cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCookie(w http.ResponseWriter, name string, domain string, value string) {
|
||||||
|
cookie := http.Cookie{
|
||||||
|
Domain: domain,
|
||||||
|
Name: name,
|
||||||
|
Path: "/",
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
http.SetCookie(w, &cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1st -> valid auth?, 2nd bool -> any errors?
|
||||||
|
func getJWT(w http.ResponseWriter, r *http.Request) (bool, bool) {
|
||||||
|
tokenCookie, err := r.Cookie("CAVEPEDIA_SESSION")
|
||||||
|
if err != nil {
|
||||||
|
// Cookie does not exist
|
||||||
|
return false, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse Cookie
|
||||||
|
tokenStr := tokenCookie.Value
|
||||||
|
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
// Verify signing method
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||||
|
}
|
||||||
|
return key, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// Corrupt JWT
|
||||||
|
if err != nil {
|
||||||
|
deleteCookie(w, "CAVEPEDIA_SESSION", utils.GetConfig().CookieDomain)
|
||||||
|
return false, true
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, ok := token.Claims.(jwt.MapClaims)
|
||||||
|
// Issue looking up claims or invalid signature
|
||||||
|
if !ok || !token.Valid {
|
||||||
|
deleteCookie(w, "CAVEPEDIA_SESSION", utils.GetConfig().CookieDomain)
|
||||||
|
return false, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expired
|
||||||
|
err = claims.Valid()
|
||||||
|
if err != nil {
|
||||||
|
if setJWT(w) {
|
||||||
|
return true, true
|
||||||
|
} else {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func setJWT(w http.ResponseWriter) bool {
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
|
||||||
|
Subject: "CAVEPEDIA",
|
||||||
|
})
|
||||||
|
|
||||||
|
tokenStr, err := token.SignedString(key)
|
||||||
|
if !checkWebError(w, err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
setCookie(w, "CAVEPEDIA_SESSION", utils.GetConfig().CookieDomain, tokenStr)
|
||||||
|
return true
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
module git.seaturtle.pw/pew/cavepedia
|
||||||
|
|
||||||
|
go 1.16
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/blevesearch/bleve/v2 v2.0.2
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
|
github.com/kisielk/gotool v1.0.0 // indirect
|
||||||
|
github.com/zserge/lorca v0.1.10
|
||||||
|
honnef.co/go/tools v0.2.0 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,142 @@
|
||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/RoaringBitmap/roaring v0.4.23 h1:gpyfd12QohbqhFO4NVDUdoPOCXsyahYRQhINmlHxKeo=
|
||||||
|
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||||
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/blevesearch/bleve/v2 v2.0.2 h1:D93VfhOiR6wALovgjsK5XNPeDRrZQlUEIq4YWFeaiTw=
|
||||||
|
github.com/blevesearch/bleve/v2 v2.0.2/go.mod h1:ip+4iafiEq2gCY5rJXe87bT6LkF/OJMCjQEYIfTBfW8=
|
||||||
|
github.com/blevesearch/bleve_index_api v1.0.0 h1:Ds3XeuTxjXCkG6pgIwWDRyooJKNIuOKemnN0N0IkhTU=
|
||||||
|
github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
|
||||||
|
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
|
||||||
|
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
|
||||||
|
github.com/blevesearch/mmap-go v1.0.2 h1:JtMHb+FgQCTTYIhtMvimw15dJwu1Y5lrZDMOFXVWPk0=
|
||||||
|
github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA=
|
||||||
|
github.com/blevesearch/scorch_segment_api/v2 v2.0.1 h1:fd+hPtZ8GsbqPK1HslGp7Vhoik4arZteA/IsCEgOisw=
|
||||||
|
github.com/blevesearch/scorch_segment_api/v2 v2.0.1/go.mod h1:lq7yK2jQy1yQjtjTfU931aVqz7pYxEudHaDwOt1tXfU=
|
||||||
|
github.com/blevesearch/segment v0.9.0 h1:5lG7yBCx98or7gK2cHMKPukPZ/31Kag7nONpoBt22Ac=
|
||||||
|
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
|
||||||
|
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
|
||||||
|
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
|
||||||
|
github.com/blevesearch/upsidedown_store_api v1.0.1 h1:1SYRwyoFLwG3sj0ed89RLtM15amfX2pXlYbFOnF8zNU=
|
||||||
|
github.com/blevesearch/upsidedown_store_api v1.0.1/go.mod h1:MQDVGpHZrpe3Uy26zJBf/a8h0FZY6xJbthIMm8myH2Q=
|
||||||
|
github.com/blevesearch/vellum v1.0.3 h1:U86G41A7CtXNzzpIJHM8lSTUqz1Mp8U870TkcdCzZc8=
|
||||||
|
github.com/blevesearch/vellum v1.0.3/go.mod h1:2u5ax02KeDuNWu4/C+hVQMD6uLN4txH1JbtpaDNLJRo=
|
||||||
|
github.com/blevesearch/zapx/v11 v11.2.0 h1:GBkCJYsyj3eIU4+aiLPxoMz1PYvDbQZl/oXHIBZIP60=
|
||||||
|
github.com/blevesearch/zapx/v11 v11.2.0/go.mod h1:gN/a0alGw1FZt/YGTo1G6Z6XpDkeOfujX5exY9sCQQM=
|
||||||
|
github.com/blevesearch/zapx/v12 v12.2.0 h1:dyRcSoZVO1jktL4UpGkCEF1AYa3xhKPirh4/N+Va+Ww=
|
||||||
|
github.com/blevesearch/zapx/v12 v12.2.0/go.mod h1:fdjwvCwWWwJW/EYTYGtAp3gBA0geCYGLcVTtJEZnY6A=
|
||||||
|
github.com/blevesearch/zapx/v13 v13.2.0 h1:mUqbaqQABp8nBE4t4q2qMyHCCq4sykoV8r7aJk4ih3s=
|
||||||
|
github.com/blevesearch/zapx/v13 v13.2.0/go.mod h1:o5rAy/lRS5JpAbITdrOHBS/TugWYbkcYZTz6VfEinAQ=
|
||||||
|
github.com/blevesearch/zapx/v14 v14.2.0 h1:UsfRqvM9RJxKNKrkR1U7aYc1cv9MWx719fsAjbF6joI=
|
||||||
|
github.com/blevesearch/zapx/v14 v14.2.0/go.mod h1:GNgZusc1p4ot040cBQMRGEZobvwjCquiEKYh1xLFK9g=
|
||||||
|
github.com/blevesearch/zapx/v15 v15.2.0 h1:ZpibwcrrOaeslkOw3sJ7npP7KDgRHI/DkACjKTqFwyM=
|
||||||
|
github.com/blevesearch/zapx/v15 v15.2.0/go.mod h1:MmQceLpWfME4n1WrBFIwplhWmaQbQqLQARpaKUEOs/A=
|
||||||
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k=
|
||||||
|
github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs=
|
||||||
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4=
|
||||||
|
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||||
|
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw=
|
||||||
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||||
|
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
|
||||||
|
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
||||||
|
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
|
github.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM=
|
||||||
|
github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7Z4dM9/Y=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
|
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
|
||||||
|
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
|
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
|
||||||
|
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/zserge/lorca v0.1.10 h1:f/xBJ3D3ipcVRCcvN8XqZnpoKcOXV8I4vwqlFyw7ruc=
|
||||||
|
github.com/zserge/lorca v0.1.10/go.mod h1:bVmnIbIRlOcoV285KIRSe4bUABKi7R7384Ycuum6e4A=
|
||||||
|
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
|
||||||
|
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||||
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
|
||||||
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
||||||
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
honnef.co/go/tools v0.1.4 h1:SadWOkti5uVN1FAMgxn165+Mw00fuQKyk4Gyn/inxNQ=
|
||||||
|
honnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
||||||
|
honnef.co/go/tools v0.2.0 h1:ws8AfbgTX3oIczLPNPCu5166oBg9ST2vNs0rcht+mDE=
|
||||||
|
honnef.co/go/tools v0.2.0/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
|
|
@ -0,0 +1,77 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"embed"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"git.seaturtle.pw/pew/cavepedia/utils"
|
||||||
|
"github.com/blevesearch/bleve/v2"
|
||||||
|
"github.com/zserge/lorca"
|
||||||
|
)
|
||||||
|
|
||||||
|
var JSON string
|
||||||
|
var index bleve.Index
|
||||||
|
|
||||||
|
//go:embed templates
|
||||||
|
var templatesHTML embed.FS
|
||||||
|
|
||||||
|
//go:embed static
|
||||||
|
var staticFiles embed.FS
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(log.Lshortfile)
|
||||||
|
FILES := "./cavepedia-data/00_files/"
|
||||||
|
JSON = "./cavepedia-data/02_json"
|
||||||
|
INDEX := "cavepedia.bleve"
|
||||||
|
|
||||||
|
/* Setup Search */
|
||||||
|
exists, ok := openIndex(INDEX)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Web Server */
|
||||||
|
key = make([]byte, 512)
|
||||||
|
_, err := rand.Read(key)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
http.Handle("/files/", http.StripPrefix("/files/", http.FileServer(http.Dir(FILES))))
|
||||||
|
http.Handle("/static/", http.FileServer(http.FS(staticFiles)))
|
||||||
|
http.Handle("/favicon.ico", http.RedirectHandler("/static/favicon.ico", http.StatusMovedPermanently))
|
||||||
|
http.HandleFunc("/", GetHome) // Redirects to /search if auth'd
|
||||||
|
http.HandleFunc("/search", GetSearch) // Redirects to / if not auth'd
|
||||||
|
http.HandleFunc("/quiz", PostQuiz)
|
||||||
|
http.HandleFunc("/pdf", GetPDF)
|
||||||
|
|
||||||
|
/* Index data if needed */
|
||||||
|
if !exists && !indexDocuments() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if utils.GetConfig().Proxy {
|
||||||
|
log.Println("Server is running!")
|
||||||
|
log.Fatal(http.ListenAndServe(":3000", nil))
|
||||||
|
} else {
|
||||||
|
// Start in separate goroutine
|
||||||
|
go func() {
|
||||||
|
log.Println("Server is running!")
|
||||||
|
log.Fatal(http.ListenAndServe(":3000", nil))
|
||||||
|
}()
|
||||||
|
|
||||||
|
/* GUI */
|
||||||
|
args := []string{}
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
args = append(args, "--class=Lorca")
|
||||||
|
}
|
||||||
|
ui, err := lorca.New("http://localhost:3000", "", 1000, 800, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer ui.Close()
|
||||||
|
<-ui.Done()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
// "strings"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve/v2"
|
||||||
|
"github.com/blevesearch/bleve/v2/search"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pageStruct struct {
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Group string `json:"group"`
|
||||||
|
Category string `json:"category"`
|
||||||
|
Season string `json:"season"`
|
||||||
|
File string `json:"file"`
|
||||||
|
PageNum int `json:"pageNum"`
|
||||||
|
Readability float32 `json:"readability"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do search and return results
|
||||||
|
// Query reference: https://pkg.go.dev/github.com/blevesearch/bleve@v1.0.14/search/query#MatchQuery
|
||||||
|
func doSearch(term string, fuzziness int) (search.DocumentMatchCollection, error) {
|
||||||
|
// Single word
|
||||||
|
var search *bleve.SearchRequest
|
||||||
|
query := bleve.NewQueryStringQuery(term)
|
||||||
|
search = bleve.NewSearchRequestOptions(query, 100, 0, false)
|
||||||
|
|
||||||
|
search.Fields = []string{"*"}
|
||||||
|
results, err := index.Search(search)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return results.Hits, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create index if it doesn't already exist and return it
|
||||||
|
func openIndex(path string) (bool, bool) {
|
||||||
|
if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
|
||||||
|
// Index does not exist
|
||||||
|
var err error
|
||||||
|
index, err = bleve.New(path, bleve.NewIndexMapping())
|
||||||
|
if !checkError(err) {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
return false, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index already exists
|
||||||
|
var err error
|
||||||
|
index, err = bleve.Open(path)
|
||||||
|
if !checkError(err) {
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index all documents
|
||||||
|
func indexDocuments() bool {
|
||||||
|
log.Println("Indexing documents...")
|
||||||
|
|
||||||
|
GRPS, err := ioutil.ReadDir(JSON)
|
||||||
|
if !checkError(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, GRP := range GRPS {
|
||||||
|
// Iterate through groups
|
||||||
|
GRP_PATH := JSON + "/" + GRP.Name()
|
||||||
|
CATS, _ := ioutil.ReadDir(GRP_PATH)
|
||||||
|
if !checkError(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, CAT := range CATS {
|
||||||
|
// Iterate through categories
|
||||||
|
CAT_PATH := GRP_PATH + "/" + CAT.Name()
|
||||||
|
FILES, _ := ioutil.ReadDir(CAT_PATH)
|
||||||
|
if !checkError(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, FILE := range FILES {
|
||||||
|
// Iterate through files
|
||||||
|
FILE_PATH := CAT_PATH + "/" + FILE.Name()
|
||||||
|
PAGES, _ := ioutil.ReadDir(FILE_PATH)
|
||||||
|
if !checkError(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, PAGE := range PAGES {
|
||||||
|
// Iterate through pages
|
||||||
|
PAGE_PATH := FILE_PATH + "/" + PAGE.Name()
|
||||||
|
|
||||||
|
// Read file
|
||||||
|
f, _ := os.Open(PAGE_PATH)
|
||||||
|
if !checkError(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
b, _ := ioutil.ReadAll(f)
|
||||||
|
if !checkError(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = f.Close()
|
||||||
|
if !checkError(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index file
|
||||||
|
var page pageStruct
|
||||||
|
json.Unmarshal(b, &page)
|
||||||
|
|
||||||
|
ID := GRP.Name() + "-" + CAT.Name() + "-" + FILE.Name() + "-" + PAGE.Name()
|
||||||
|
err = index.Index(ID, page)
|
||||||
|
if !checkError(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
body {
|
||||||
|
background-color: darkgrey;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.6;
|
||||||
|
text-align: center;
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
body {
|
||||||
|
background-color: darkgray;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 40px auto;
|
||||||
|
max-width: 700px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
body p, #howto {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search {
|
||||||
|
height: 25px;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bat */
|
||||||
|
.bat-container {
|
||||||
|
width: 125px;
|
||||||
|
height: 170px;
|
||||||
|
margin: auto;
|
||||||
|
bottom: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pin-bottom {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bat-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
height: 170px;
|
||||||
|
width: 125px;
|
||||||
|
animation: ease-in-out wiggle 7s 0s infinite alternate both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bat {
|
||||||
|
background-size: 2250px 170px;
|
||||||
|
background-image: url('https://www.mapbox.com/bites/00279/bat.svg');
|
||||||
|
height: 170px;
|
||||||
|
width: 125px;
|
||||||
|
animation: flapping .4s steps(18) infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bat-leg-1 {
|
||||||
|
bottom: 54px;
|
||||||
|
left: 55px;
|
||||||
|
display: block;
|
||||||
|
width: 4px;
|
||||||
|
height: 15px;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #008dba;
|
||||||
|
animation: ease-in-out leg 2s 0s infinite alternate both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bat-leg-2 {
|
||||||
|
bottom: 54px;
|
||||||
|
left: 65px;
|
||||||
|
display: block;
|
||||||
|
width: 4px;
|
||||||
|
height: 15px;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #008dba;
|
||||||
|
animation: ease-in-out leg2 2s 0s infinite alternate both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bat-shadow {
|
||||||
|
position: relative;
|
||||||
|
width: 20px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #005773;
|
||||||
|
opacity: .2;
|
||||||
|
top: 180px;
|
||||||
|
left: 60px;
|
||||||
|
animation: ease-in-out bat-shadow 7s 0s infinite alternate both;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes wiggle {
|
||||||
|
0% {
|
||||||
|
transform: rotate( 0deg) translateY(-22px) scale(1.0);
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
transform: rotate( -10deg) translateY(0px) scale(1.05) translateX(-15px);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate( 0deg) translateY(7px) scale(1.0) translateX(5px);
|
||||||
|
}
|
||||||
|
66% {
|
||||||
|
transform: rotate( 5deg) translateY(15px);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: rotate( 0deg) translateY(8px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate( 10deg) translateY(0px) translateX(-15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes wiggle {
|
||||||
|
0% {
|
||||||
|
transform: rotate( 0deg) translateY(-22px) scale(1.0);
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
transform: rotate( -10deg) translateY(0px) scale(1.05) translateX(-15px);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate( 0deg) translateY(7px) scale(1.0) translateX(5px);
|
||||||
|
}
|
||||||
|
66% {
|
||||||
|
transform: rotate( 5deg) translateY(15px);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: rotate( 0deg) translateY(8px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate( 10deg) translateY(0px) translateX(-15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes flapping {
|
||||||
|
100% {
|
||||||
|
background-position: -2250px 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes flapping {
|
||||||
|
100% {
|
||||||
|
background-position: -2250px 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bat-shadow {
|
||||||
|
0% {
|
||||||
|
transform: scale(.7) translateX(0px);
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
transform: scale(1) translateX(-5px);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.1) translateX(4px);
|
||||||
|
}
|
||||||
|
66% {
|
||||||
|
transform: scale(1.3);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1.0) translateX(-5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes bat-shadow {
|
||||||
|
0% {
|
||||||
|
transform: scale(.7) translateX(0px);
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
transform: scale(1) translateX(-5px);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.1) translateX(4px);
|
||||||
|
}
|
||||||
|
66% {
|
||||||
|
transform: scale(1.3);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1.0) translateX(-5px);
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,35 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Cavepedia</title>
|
||||||
|
<link rel="stylesheet" href="/static/cavepedia.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Welcome to Cavepedia</h1>
|
||||||
|
|
||||||
|
{{if .TryAgain}}
|
||||||
|
<h3>Incorrect! Please try again!</h3>
|
||||||
|
{{else}}
|
||||||
|
<h3>Please complete this quiz to continue</h3>
|
||||||
|
{{end}}
|
||||||
|
<form action="/quiz" method="post">
|
||||||
|
A.I. <input type="text" id="answer" placeholder="Answer..." name="answer">
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- bat -->
|
||||||
|
<div class="bat-container pin-bottom">
|
||||||
|
<div class="bat-wrapper">
|
||||||
|
<div class="bat js-bat">
|
||||||
|
<div class="bat-leg-1"></div>
|
||||||
|
<div class="bat-leg-2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bat-shadow"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('answer').focus();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{{.Filename}}</title>
|
||||||
|
<link rel="stylesheet" href="/static/cavepedia-pdf.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="/search?term={{.Term}}"><-- Back to Results</a>
|
||||||
|
<br>
|
||||||
|
<strong>Term:</strong> {{.Term}} |
|
||||||
|
<strong>Category:</strong> {{.Category}} |
|
||||||
|
<strong>Filename:</strong> {{.Filename}} |
|
||||||
|
<strong>Season:</strong> {{.Season}} |
|
||||||
|
<strong>Page Number:</strong> {{.PageNum}}
|
||||||
|
<br>
|
||||||
|
<iframe src="{{.File}}#page={{.PageNum}}" style="width:100%;height:calc(100vh - 85px);"></iframe>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Cavepedia</title>
|
||||||
|
<link rel="stylesheet" href="/static/cavepedia.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="/search?placeholder={{.Term}}"><-- Back to Search</a>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
{{$numResults := .Results.Len}}
|
||||||
|
{{$term := .Term}}
|
||||||
|
|
||||||
|
<h2 id="results">{{$numResults}} results for {{$term}}</h2>
|
||||||
|
<h4>(Only exact matches are highlighted)</h4>
|
||||||
|
|
||||||
|
{{if not .Results}}
|
||||||
|
<h3>No Results :(</h3>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
|
||||||
|
{{range $i, $r := .Results}}
|
||||||
|
{{$group := index .Fields "group"}}
|
||||||
|
{{$category := index .Fields "category"}}
|
||||||
|
{{$filename := index .Fields "file"}}
|
||||||
|
{{$pageNum := index .Fields "pageNum"}}
|
||||||
|
{{$season := index .Fields "season"}}
|
||||||
|
|
||||||
|
<div id="{{$i}}">
|
||||||
|
<h3><a id="pdf_{{$i}}" href="/pdf?file=/files/{{$group}}/{{$category}}/{{$filename}}&category={{$category}}&filename={{$filename}}&season={{$season}}&pageNum={{$pageNum}}&term={{$term}}">
|
||||||
|
{{$filename}}</a>
|
||||||
|
</h3>
|
||||||
|
<strong id="id_{{$i}}">Result {{$i}} of {{$numResults}}</strong> |
|
||||||
|
<strong>Category:</strong> {{index .Fields "category"}} |
|
||||||
|
<strong>Season:</strong> {{index .Fields "season"}} |
|
||||||
|
<strong>Page Number:</strong> {{index .Fields "pageNum"}}
|
||||||
|
<p id="text_{{$i}}">{{index .Fields "text"}}<p>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const numResults = parseInt({{$numResults}});
|
||||||
|
const term = {{$term}};
|
||||||
|
const lower = term.toLowerCase();
|
||||||
|
const upper = term.toUpperCase();
|
||||||
|
const capitalize = term.charAt(0).toUpperCase() + term.slice(1);
|
||||||
|
|
||||||
|
for (i = 0; i < numResults; i++) {
|
||||||
|
// Highlight text
|
||||||
|
let newText = document.getElementById(`text_${i}`).innerHTML;
|
||||||
|
newText = newText.replace(lower, `<mark>${lower}</mark>`)
|
||||||
|
newText = newText.replace(upper, `<mark>${upper}</mark>`)
|
||||||
|
newText = newText.replace(capitalize, `<mark>${capitalize}</mark>`)
|
||||||
|
document.getElementById(`text_${i}`).innerHTML = newText;
|
||||||
|
|
||||||
|
// Set result number
|
||||||
|
document.getElementById(`id_${i}`).innerHTML = `Result ${i+1} of {{$numResults}}`;
|
||||||
|
|
||||||
|
// Link directly to PDF if mobile (doesn't support PDF natively)
|
||||||
|
if (window.matchMedia("(any-pointer: coarse)").matches) {
|
||||||
|
document.getElementById(`pdf_${i}`).href = document.getElementById(`pdf_${i}`).href.split('?')[1].split('&')[0].split('=')[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Cavepedia</title>
|
||||||
|
<link rel="stylesheet" href="/static/cavepedia.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Welcome to Cavepedia</h1>
|
||||||
|
<form action="/search" method="GET">
|
||||||
|
<input type="text" id="search" onfocus="this.setSelectionRange(1000,1001);" placeholder="Search..." name="term" value="{{.Placeholder}}">
|
||||||
|
<br>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{{if .ErrorMsg}}
|
||||||
|
<h3>{{.ErrorMsg}}</h3>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<div id="howto">
|
||||||
|
<h2>How to Search</h2>
|
||||||
|
<p>Data is organized by <strong>group</strong>, then by <strong>category</strong>:</p>
|
||||||
|
<ul>
|
||||||
|
<li>nss</li>
|
||||||
|
<ul>
|
||||||
|
<li>compasstape</li>
|
||||||
|
<li>nylonhighway</li>
|
||||||
|
<li>speleonics</li>
|
||||||
|
</ul>
|
||||||
|
<li>var</li>
|
||||||
|
<ul>
|
||||||
|
<li>fyi</li>
|
||||||
|
<li>regionrecord</li>
|
||||||
|
</ul>
|
||||||
|
<li>vpi</li>
|
||||||
|
<ul>
|
||||||
|
<li>grapevine</li>
|
||||||
|
<li>signout</li>
|
||||||
|
<li>trog</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Examples</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Tip: Multiple different searches with simple queries work better than a single complicated query</li>
|
||||||
|
<li>Bolt hanger stats</li>
|
||||||
|
<ul>
|
||||||
|
<li><code>+category:nylonhighway +bolt +hanger +stats</code> (This actually returns no results, but is a good example of being too strict).</li>
|
||||||
|
<li><code>+category:nylonhighway +hanger +strength +test</code></li>
|
||||||
|
</ul>
|
||||||
|
<li>Suunto Repair</li>
|
||||||
|
<ul>
|
||||||
|
<li><code>+category:compasstape +suunto +repair</code></li>
|
||||||
|
</ul>
|
||||||
|
<li>How to use a QAS</li>
|
||||||
|
<ul>
|
||||||
|
<li><code>+category:nylonhighway +QAS</code></li>
|
||||||
|
</ul>
|
||||||
|
<li>Newberry trips Steve Wells went on</li>
|
||||||
|
<ul>
|
||||||
|
<li><code>+category:signout +wells +newberries</code></li>
|
||||||
|
<li><code>+category:signout +wells +newberry's</code></li>
|
||||||
|
<li>Before 2000: <code>+category:signout timestamp:<"2000-01-01" +wells /(newberries|newberry's)/</code></li>
|
||||||
|
</ul>
|
||||||
|
<li>Weird spellings of things</li>
|
||||||
|
<ul>
|
||||||
|
<li><code>/Eric (landgraf|landgraff)/</code></li>
|
||||||
|
</ul>
|
||||||
|
<li>Legible Trog articles</li>
|
||||||
|
<ul>
|
||||||
|
<li><code>+category:trog +readability:>9</code></li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Search Operators</h3>
|
||||||
|
<ul>
|
||||||
|
<li>+ -- must include</li>
|
||||||
|
<li>- -- must not include</li>
|
||||||
|
<li><, >, <=, >= -- must be greater than or less than. Only works with numeric fields. Cannot use both at the same time!</li>
|
||||||
|
<li>Regular Expressions are supported</li>
|
||||||
|
<li>No operator: should include</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Available Fields</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Very useful fields</li>
|
||||||
|
<ul>
|
||||||
|
<li>group, string -- See above (nss, var, vpi, etc).</li>
|
||||||
|
<li>category, string -- See above</li>
|
||||||
|
<li>timestamp, number -- Approximate date of article. Based completely on dates in filenames (not very accurate).</li>
|
||||||
|
</ul>
|
||||||
|
<li>Not quite as useful fields</li>
|
||||||
|
<ul>
|
||||||
|
<li>season, string -- Approximate date of article. Based completely on season or date in filename (not very accurate).</li>
|
||||||
|
<li>file, string -- PDF filename</li>
|
||||||
|
<li>pageNum, number -- Article page number in the PDF.</li>
|
||||||
|
<li>readability -- Uses the Dale-Chall readability formula</li>
|
||||||
|
<li>text, string -- Actual article text</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- bat -->
|
||||||
|
<div class="bat-container pin-bottom">
|
||||||
|
<div class="bat-wrapper">
|
||||||
|
<div class="bat js-bat">
|
||||||
|
<div class="bat-leg-1"></div>
|
||||||
|
<div class="bat-leg-2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bat-shadow"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('search').focus();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,19 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
CookieDomain string
|
||||||
|
Password string
|
||||||
|
Proxy bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
CookieDomain: os.Getenv("COOKIE_DOMAIN"),
|
||||||
|
Password: os.Getenv("PASSWORD"),
|
||||||
|
Proxy: os.Getenv("PROXY") == "1",
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.seaturtle.pw/pew/cavepedia/utils"
|
||||||
|
"github.com/blevesearch/bleve/v2/search"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetHome(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Bypass auth
|
||||||
|
if utils.GetConfig().Password == "" {
|
||||||
|
http.Redirect(w, r, "/search", http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if auth'd --> redirect to /
|
||||||
|
auth, ok := getJWT(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if auth {
|
||||||
|
http.Redirect(w, r, "/search", http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// return index.html
|
||||||
|
t, err := template.ParseFS(templatesHTML, "templates/index.html.tmpl")
|
||||||
|
if !checkWebError(w, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = t.Execute(w, struct {
|
||||||
|
TryAgain bool
|
||||||
|
}{
|
||||||
|
TryAgain: false,
|
||||||
|
})
|
||||||
|
checkError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSearch(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Check auth
|
||||||
|
if utils.GetConfig().Password != "" {
|
||||||
|
// if not auth'd --> redirect to /
|
||||||
|
auth, ok := getJWT(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !auth {
|
||||||
|
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup params
|
||||||
|
_, exists := r.URL.Query()["exact"]
|
||||||
|
fuzziness := 2
|
||||||
|
if exists {
|
||||||
|
fuzziness = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
errorMsg := getURLParam(r, "error")
|
||||||
|
placeholder := getURLParam(r, "placeholder")
|
||||||
|
term := getURLParam(r, "term")
|
||||||
|
|
||||||
|
// We don't actually pass the message in, just true if there's an error
|
||||||
|
if errorMsg != "" {
|
||||||
|
errorMsg = "Invalid query syntax! Please try again."
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid query and/or show placeholder
|
||||||
|
if errorMsg != "" || term == "" {
|
||||||
|
t, err := template.ParseFS(templatesHTML, "templates/search.html.tmpl")
|
||||||
|
if !checkWebError(w, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = t.Execute(w, struct {
|
||||||
|
ErrorMsg string
|
||||||
|
Placeholder string
|
||||||
|
}{
|
||||||
|
ErrorMsg: errorMsg,
|
||||||
|
Placeholder: placeholder,
|
||||||
|
})
|
||||||
|
checkError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do search
|
||||||
|
results, err := doSearch(term, fuzziness)
|
||||||
|
if err != nil {
|
||||||
|
http.Redirect(w, r, "/search?error=true&placeholder="+term, http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := template.ParseFS(templatesHTML, "templates/results.html.tmpl")
|
||||||
|
if !checkWebError(w, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = t.Execute(w, struct {
|
||||||
|
Results search.DocumentMatchCollection
|
||||||
|
Term string
|
||||||
|
}{
|
||||||
|
Results: results,
|
||||||
|
Term: term,
|
||||||
|
})
|
||||||
|
checkError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostQuiz(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !checkWebError(w, r.ParseForm()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// valid quiz
|
||||||
|
if strings.EqualFold(r.Form.Get("answer"), utils.GetConfig().Password) {
|
||||||
|
// create JWT
|
||||||
|
if !setJWT(w) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, "/search", http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalid quiz
|
||||||
|
t, err := template.ParseFS(templatesHTML, "templates/index.html.tmpl")
|
||||||
|
if !checkWebError(w, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = t.Execute(w, struct {
|
||||||
|
TryAgain bool
|
||||||
|
}{
|
||||||
|
TryAgain: true,
|
||||||
|
})
|
||||||
|
checkError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPDF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
category := getURLParam(r, "category")
|
||||||
|
file := getURLParam(r, "file")
|
||||||
|
filename := getURLParam(r, "filename")
|
||||||
|
pageNum := getURLParam(r, "pageNum")
|
||||||
|
season := getURLParam(r, "season")
|
||||||
|
term := getURLParam(r, "term")
|
||||||
|
|
||||||
|
t, err := template.ParseFS(templatesHTML, "templates/pdf.html.tmpl")
|
||||||
|
if !checkWebError(w, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = t.Execute(w, struct {
|
||||||
|
Category string
|
||||||
|
File string
|
||||||
|
Filename string
|
||||||
|
PageNum string
|
||||||
|
Season string
|
||||||
|
Term string
|
||||||
|
}{
|
||||||
|
Category: category,
|
||||||
|
File: file,
|
||||||
|
Filename: filename,
|
||||||
|
PageNum: pageNum,
|
||||||
|
Season: season,
|
||||||
|
Term: term,
|
||||||
|
})
|
||||||
|
if !checkError(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue