Skip to content

Commit

Permalink
added middleware and update models
Browse files Browse the repository at this point in the history
  • Loading branch information
rk1165 committed Oct 5, 2024
1 parent a18480f commit bc4230f
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 38 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
run:
go run --tags "fts5" ./cmd/web/*.go
go run --tags "fts5" ./cmd/web/

init:
sqlite3 engine.db < ddl.sql
go mod tidy

build:
go build --tags "fts5" -o pse ./cmd/web/*.go
go build --tags "fts5" -o pse ./cmd/web/

clean:
sqlite3 engine.db < clean.sql
Expand Down
6 changes: 3 additions & 3 deletions cmd/web/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type indexingForm struct {
}

type PaginatedResult struct {
Results []models.SearchResult
Results []models.Post
Query string
NextPage int
PrevPage int
Expand Down Expand Up @@ -54,7 +54,7 @@ func (app *application) lookup(w http.ResponseWriter, r *http.Request) {

app.infoLog.Printf("searchTerm: %s", searchTerm)

searchResults, err := app.search.Find(searchTerm, offset)
searchResults, err := app.post.Find(searchTerm, offset)
if err != nil {
err = fmt.Errorf("searching returned error %v", err)
app.serverError(w, err)
Expand Down Expand Up @@ -108,5 +108,5 @@ func (app *application) submit(w http.ResponseWriter, r *http.Request) {
session.Save(r, w)

data := app.newTemplateData(w, r)
app.render(w, http.StatusOK, "status.tmpl", data)
app.render(w, http.StatusOK, "home.tmpl", data)
}
28 changes: 8 additions & 20 deletions cmd/web/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,9 @@ import (
"sync"
)

type Post struct {
title string
url string
content string
}

func Index(request *models.Request, app *application, ch chan<- int) {
inChannel := make(chan string)
outChannel := make(chan Post)
outChannel := make(chan models.Post)
var wg sync.WaitGroup
wg.Add(1)

Expand Down Expand Up @@ -71,23 +65,23 @@ func getAllLinks(app *application, site, selector string) ([]string, error) {
return links, nil
}

func createPost(app *application, in <-chan string, out chan<- Post, titleSelector, contentSelector string) {
func createPost(app *application, in <-chan string, out chan<- models.Post, titleSelector, contentSelector string) {
// only exits if in channel is closed
for link := range in {
app.infoLog.Printf("processing link %s", link)
c := colly.NewCollector()
var content string
post := Post{url: link}
post := models.Post{Url: link}

c.OnHTML(titleSelector, func(e *colly.HTMLElement) {
title := e.Text
post.title = clean(title)
post.Title = clean(title)
})

c.OnHTML(contentSelector, func(e *colly.HTMLElement) {
content = e.Text
content = clean(content)
post.content = content
post.Content = content
})

err := c.Visit(link)
Expand All @@ -99,22 +93,16 @@ func createPost(app *application, in <-chan string, out chan<- Post, titleSelect
}
}

func savePost(wg *sync.WaitGroup, app *application, out <-chan Post, jobs int) {
func savePost(wg *sync.WaitGroup, app *application, out <-chan models.Post, jobs int) {
defer wg.Done()
stmt, err := app.db.Prepare("INSERT INTO posts(title, url, content) values(?,?,?)")
if err != nil {
app.errorLog.Printf("error occurred when preparing statement %v", err)
return
}
defer stmt.Close()
for i := 0; i < jobs; i++ {
post := <-out
_, err = stmt.Exec(post.title, post.url, post.content)
err := app.post.Insert(post)
if err != nil {
app.errorLog.Printf("error occurred when inserting post in db %v", err)
return
}
app.infoLog.Printf("post [%v] inserted in db", post.title)
app.infoLog.Printf("post [%v] inserted in db", post.Title)
}
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/web/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
type application struct {
errorLog *log.Logger
infoLog *log.Logger
search models.SearchModelInterface
post models.PostModelInterface
request models.RequestModelInterface
templateCache map[string]*template.Template
formDecoder *form.Decoder
Expand Down Expand Up @@ -49,7 +49,7 @@ func main() {
app := &application{
errorLog: errorLog,
infoLog: infoLog,
search: &models.SearchModel{DB: db},
post: &models.PostModel{DB: db},
request: &models.RequestModel{DB: db},
templateCache: templateCache,
formDecoder: form.NewDecoder(),
Expand Down
43 changes: 43 additions & 0 deletions cmd/web/middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"fmt"
"net/http"
)

func secureHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Security-Policy",
"default-src 'self'; style-src 'self' fonts.googleapis.com; font-src fonts.gstatic.com")
w.Header().Set("Referrer-Policy", "origin-when-cross-origin")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "deny")
w.Header().Set("X-XSS-Protection", "0")
next.ServeHTTP(w, r)
})
}

func (app *application) logRequest(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
app.infoLog.Printf("%s - %s %s %s", r.RemoteAddr, r.Proto, r.Method, r.URL.RequestURI())
next.ServeHTTP(w, r)
})
}

func (app *application) recoverPanic(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Create a deferred function (which will always be run in the event of
// panic as Go unwinds the stack)
defer func() {
// Use the builtin recover function to check if there has been a
// panic or not. If there has...
if err := recover(); err != nil {
// Set a "Connection: Close" header on the response.
w.Header().Set("Connection", "close")
// Call the app.serverError helper method to return a 500 Internal Server response
app.serverError(w, fmt.Errorf("%s", err))
}
}()
next.ServeHTTP(w, r)
})
}
53 changes: 53 additions & 0 deletions cmd/web/middleware_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main

import (
"bytes"
"github.com/rk1165/pse/internal/assert"
"io"
"net/http"
"net/http/httptest"
"testing"
)

func TestSecureHeaders(t *testing.T) {
rr := httptest.NewRecorder()

r, err := http.NewRequest(http.MethodGet, "/", nil)
if err != nil {
t.Fatal(err)
}

// Create a moc http handler that we can pass to our secureHeaders
// middleware, which writes a 200 status code and an "OK" response body
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
})

// Pass the mock HTTP handler to our secureHeaders middleware.
secureHeaders(next).ServeHTTP(rr, r)
rs := rr.Result()

expectedValue := "default-src 'self'; style-src 'self' fonts.googleapis.com; font-src fonts.gstatic.com"
assert.Equal(t, rs.Header.Get("Content-Security-Policy"), expectedValue)

expectedValue = "origin-when-cross-origin"
assert.Equal(t, rs.Header.Get("Referrer-Policy"), expectedValue)

expectedValue = "nosniff"
assert.Equal(t, rs.Header.Get("X-Content-Type-Options"), expectedValue)

expectedValue = "deny"
assert.Equal(t, rs.Header.Get("X-Frame-Options"), expectedValue)

expectedValue = "0"
assert.Equal(t, rs.Header.Get("X-XSS-Protection"), expectedValue)

assert.Equal(t, rs.StatusCode, http.StatusOK)
defer rs.Body.Close()
body, err := io.ReadAll(rs.Body)
if err != nil {
t.Fatal(err)
}
bytes.TrimSpace(body)
assert.Equal(t, string(body), "OK")
}
5 changes: 4 additions & 1 deletion cmd/web/routes.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"github.com/justinas/alice"
"github.com/rk1165/pse/ui"
"io/fs"
"net/http"
Expand All @@ -17,5 +18,7 @@ func (app *application) routes() http.Handler {
mux.HandleFunc("GET /index", app.index)
mux.HandleFunc("POST /search", app.lookup)
mux.HandleFunc("POST /submit", app.submit)
return mux

standard := alice.New(app.recoverPanic, app.logRequest, secureHeaders)
return standard.Then(mux)
}
Binary file modified engine.db
Binary file not shown.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/go-playground/form/v4 v4.2.1
github.com/gocolly/colly v1.2.0
github.com/gorilla/sessions v1.4.0
github.com/justinas/alice v1.2.0
github.com/mattn/go-sqlite3 v1.14.23
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kX
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0=
Expand Down
29 changes: 29 additions & 0 deletions internal/assert/assert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package assert

import (
"strings"
"testing"
)

func Equal[T comparable](t *testing.T, actual, expected T) {
t.Helper()
if actual != expected {
t.Errorf("got: %v; want: %v", actual, expected)
}
}

func StringContains(t *testing.T, actual, expectedSubstring string) {
t.Helper()

if !strings.Contains(actual, expectedSubstring) {
t.Errorf("got: %q; expected to contain: %q", actual, expectedSubstring)
}
}

func NilError(t *testing.T, actual error) {
t.Helper()

if actual != nil {
t.Errorf("got: %v; expected: nil", actual)
}
}
20 changes: 10 additions & 10 deletions internal/models/search.go → internal/models/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,31 @@ import (
"log"
)

type SearchModelInterface interface {
Insert(title, url, content string) error
Find(term string, offset int) ([]SearchResult, error)
type PostModelInterface interface {
Insert(post Post) error
Find(term string, offset int) ([]Post, error)
}

type SearchResult struct {
type Post struct {
Title string
Url string
Content string
}

type SearchModel struct {
type PostModel struct {
DB *sql.DB
}

func (s *SearchModel) Insert(title, url, content string) error {
func (s *PostModel) Insert(post Post) error {
stmt := `INSERT INTO posts(title, url, content) VALUES (?, ?, ?)`
_, err := s.DB.Exec(stmt, title, url, content)
_, err := s.DB.Exec(stmt, post.Title, post.Url, post.Content)
if err != nil {
return err
}
return nil
}

func (s *SearchModel) Find(term string, offset int) ([]SearchResult, error) {
func (s *PostModel) Find(term string, offset int) ([]Post, error) {

stmt := `SELECT title, url, content FROM posts WHERE posts match ? order by rank limit 10 offset ?`
rows, err := s.DB.Query(stmt, term, offset)
Expand All @@ -39,10 +39,10 @@ func (s *SearchModel) Find(term string, offset int) ([]SearchResult, error) {
}
defer rows.Close()

var results []SearchResult
var results []Post

for rows.Next() {
searchResult := SearchResult{}
searchResult := Post{}
err = rows.Scan(&searchResult.Title, &searchResult.Url, &searchResult.Content)
if err != nil {
return nil, err
Expand Down

0 comments on commit bc4230f

Please sign in to comment.