175 lines
4.1 KiB
Go
175 lines
4.1 KiB
Go
package internal
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"html/template"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/julienschmidt/httprouter"
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/vcraescu/go-paginator"
|
|
)
|
|
|
|
const (
|
|
MaxFailedLogins = 3 // By default 3 failed login attempts per 5 minutes
|
|
)
|
|
|
|
func (s *Server) NotFoundHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Header.Get("Accept") == "application/json" {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
http.Error(w, "Endpoint Not Found", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
ctx := NewContext(s.config, s.db, r)
|
|
ctx.Title = "Page Not Found"
|
|
w.WriteHeader(http.StatusNotFound)
|
|
s.render("404", w, ctx)
|
|
}
|
|
|
|
// IndexHandler ...
|
|
func (s *Server) IndexHandler() httprouter.Handle {
|
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
ctx := NewContext(s.config, s.db, r)
|
|
|
|
q := strings.TrimSpace(r.FormValue("q"))
|
|
if q != "" {
|
|
s.SearchHandler()(w, r, p)
|
|
return
|
|
}
|
|
s.render("index", w, ctx)
|
|
}
|
|
}
|
|
|
|
// AddHandler ...
|
|
func (s *Server) AddHandler() httprouter.Handle {
|
|
return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
ctx := NewContext(s.config, s.db, r)
|
|
|
|
url := NormalizeURL(strings.TrimSpace(r.FormValue("url")))
|
|
|
|
if url == "" && r.Method == http.MethodGet {
|
|
s.render("add", w, ctx)
|
|
return
|
|
}
|
|
|
|
if url == "" {
|
|
ctx.Error = true
|
|
ctx.Message = "Invalid URL"
|
|
s.render("error", w, ctx)
|
|
return
|
|
}
|
|
|
|
if err := s.crawler.Crawl(url); err != nil {
|
|
ctx.Error = true
|
|
ctx.Message = fmt.Sprintf("Error adding URL: %s", err)
|
|
s.render("error", w, ctx)
|
|
return
|
|
}
|
|
|
|
ctx.Error = false
|
|
ctx.Message = "Successfully added url"
|
|
s.render("error", w, ctx)
|
|
}
|
|
}
|
|
|
|
// CacheHandler ...
|
|
func (s *Server) CacheHandler() httprouter.Handle {
|
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
ctx := NewContext(s.config, s.db, r)
|
|
|
|
hash := p.ByName("hash")
|
|
if hash == "" {
|
|
http.Error(w, "Bad Request", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
fn := filepath.Join(s.config.Data, cacheDir, fmt.Sprintf("%s.json", hash))
|
|
if !FileExists(fn) {
|
|
ctx.Error = true
|
|
ctx.Message = "Cached page not found!"
|
|
s.render("404", w, ctx)
|
|
return
|
|
}
|
|
|
|
var entry Entry
|
|
|
|
data, err := os.ReadFile(fn)
|
|
if err != nil {
|
|
log.WithError(err).Error("error reading cached entry")
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err := json.Unmarshal(data, &entry); err != nil {
|
|
log.WithError(err).Error("error unmarshalling cached entry")
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
ctx.CachedURL = entry.URL
|
|
ctx.CachedTitle = entry.Title
|
|
ctx.CachedContent = entry.Content
|
|
|
|
s.render("cache", w, ctx)
|
|
}
|
|
}
|
|
|
|
// SearchHandler ...
|
|
func (s *Server) SearchHandler() httprouter.Handle {
|
|
return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
ctx := NewContext(s.config, s.db, r)
|
|
|
|
q := strings.TrimSpace(r.FormValue("q"))
|
|
if q == "" {
|
|
ctx.Error = true
|
|
ctx.Message = "Error empty search"
|
|
s.render("error", w, ctx)
|
|
return
|
|
}
|
|
|
|
p := SafeParseInt(r.FormValue("p"), 1)
|
|
|
|
searchResults, err := s.indexer.Search(q, p)
|
|
if err != nil {
|
|
log.WithError(err).Error("error performing search")
|
|
ctx.Error = true
|
|
ctx.Message = "Error performing search, please try again later"
|
|
s.render("error", w, ctx)
|
|
return
|
|
}
|
|
|
|
log.Debug(searchResults)
|
|
|
|
var results []Result
|
|
|
|
for _, hit := range searchResults.Hits {
|
|
result := Result{
|
|
ID: hit.ID,
|
|
Title: hit.Fields["Title"].(string),
|
|
Summary: template.HTML(strings.Join(hit.Fragments["Summary"], "")),
|
|
URL: hit.Fields["URL"].(string),
|
|
Length: int(hit.Fields["Length"].(float64)),
|
|
}
|
|
results = append(results, result)
|
|
}
|
|
|
|
pager := paginator.New(IntAdapter{N: int(searchResults.Total)}, s.config.ResultsPerPage)
|
|
pager.SetPage(p)
|
|
|
|
ctx.Pager = &pager
|
|
ctx.SearchQuery = q
|
|
ctx.Results = results
|
|
ctx.SearchTook = searchResults.Took.Truncate(time.Nanosecond)
|
|
|
|
metrics.Counter("server", "queries").Inc()
|
|
|
|
s.render("search", w, ctx)
|
|
}
|
|
}
|