Skip to content

Commit

Permalink
Merge branch 'open-dev' into open
Browse files Browse the repository at this point in the history
  • Loading branch information
StJudeWasHere committed Sep 30, 2024
2 parents 540f929 + 3f87fe7 commit 0633ac0
Show file tree
Hide file tree
Showing 36 changed files with 815 additions and 659 deletions.
15 changes: 7 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.23
require (
github.com/antchfx/htmlquery v1.3.2
github.com/go-sql-driver/mysql v1.8.1
github.com/golang-migrate/migrate/v4 v4.17.1
github.com/golang-migrate/migrate/v4 v4.18.1
github.com/google/uuid v1.6.0
github.com/gorilla/securecookie v1.1.2
github.com/gorilla/sessions v1.4.0
Expand All @@ -15,9 +15,9 @@ require (
github.com/spf13/viper v1.19.0
github.com/temoto/robotstxt v1.1.2
github.com/turk/go-sitemap v0.0.0-20210912154218-82ad01095e30
golang.org/x/crypto v0.26.0
golang.org/x/net v0.28.0
golang.org/x/text v0.17.0
golang.org/x/crypto v0.27.0
golang.org/x/net v0.29.0
golang.org/x/text v0.18.0
gopkg.in/yaml.v3 v3.0.1
)

Expand All @@ -33,8 +33,7 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
Expand All @@ -44,7 +43,7 @@ require (
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/sys v0.25.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)
85 changes: 44 additions & 41 deletions go.sum

Large diffs are not rendered by default.

61 changes: 34 additions & 27 deletions internal/routes/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,56 +21,63 @@ type PageView struct {
func NewServer(container *services.Container) {
// Handle static files
fileServer := http.FileServer(http.Dir("./web/static"))
http.Handle("/resources/", http.StripPrefix("/resources", fileServer))
http.Handle("/robots.txt", fileServer)
http.Handle("/favicon.ico", fileServer)
http.Handle("GET /resources/", http.StripPrefix("/resources", fileServer))
http.Handle("GET /robots.txt", fileServer)
http.Handle("GET /favicon.ico", fileServer)

// Crawler routes
crawlHandler := crawlHandler{container}
http.HandleFunc("/crawl", container.CookieSession.Auth(crawlHandler.handleCrawl))
http.HandleFunc("/crawl/stop", container.CookieSession.Auth(crawlHandler.handleStopCrawl))
http.HandleFunc("/crawl/live", container.CookieSession.Auth(crawlHandler.handleCrawlLive))
http.HandleFunc("/crawl/auth", container.CookieSession.Auth(crawlHandler.handleCrawlAuth))
http.HandleFunc("/crawl/ws", container.CookieSession.Auth(crawlHandler.handleCrawlWs))
http.HandleFunc("GET /crawl/start", container.CookieSession.Auth(crawlHandler.startHandler))
http.HandleFunc("GET /crawl/stop", container.CookieSession.Auth(crawlHandler.stopHandler))
http.HandleFunc("GET /crawl/live", container.CookieSession.Auth(crawlHandler.liveCrawlHandler))
http.HandleFunc("GET /crawl/auth", container.CookieSession.Auth(crawlHandler.authGetHandler))
http.HandleFunc("POST /crawl/auth", container.CookieSession.Auth(crawlHandler.authPostHandler))
http.HandleFunc("GET /crawl/ws", container.CookieSession.Auth(crawlHandler.wsHandler))

// Dashboard route
dashboardHandler := dashboardHandler{container}
http.HandleFunc("/dashboard", container.CookieSession.Auth(dashboardHandler.handleDashboard))
http.HandleFunc("GET /dashboard", container.CookieSession.Auth(dashboardHandler.indexHandler))

// URL explorer route
explorerHandler := explorerHandler{container}
http.HandleFunc("/explorer", container.CookieSession.Auth(explorerHandler.handleExplorer))
http.HandleFunc("GET /explorer", container.CookieSession.Auth(explorerHandler.indexHandler))

// Data export routes
exportHandler := exportHandler{container}
http.HandleFunc("/download", container.CookieSession.Auth(exportHandler.handleDownloadCSV))
http.HandleFunc("/sitemap", container.CookieSession.Auth(exportHandler.handleSitemap))
http.HandleFunc("/export", container.CookieSession.Auth(exportHandler.handleExport))
http.HandleFunc("/export/download", container.CookieSession.Auth(exportHandler.handleExportResources))
http.HandleFunc("GET /export", container.CookieSession.Auth(exportHandler.indexHandler))
http.HandleFunc("GET /export/csv", container.CookieSession.Auth(exportHandler.csvHandler))
http.HandleFunc("GET /export/sitemap", container.CookieSession.Auth(exportHandler.sitemapHandler))
http.HandleFunc("GET /export/resources", container.CookieSession.Auth(exportHandler.resourcesHandler))

// Issues routes
issueHandler := issueHandler{container}
http.HandleFunc("/issues", container.CookieSession.Auth(issueHandler.handleIssues))
http.HandleFunc("/issues/view", container.CookieSession.Auth(issueHandler.handleIssuesView))
http.HandleFunc("GET /issues", container.CookieSession.Auth(issueHandler.indexHandler))
http.HandleFunc("GET /issues/view", container.CookieSession.Auth(issueHandler.viewHandler))

// Project routes
projectHandler := projectHandler{container}
http.HandleFunc("/", container.CookieSession.Auth(projectHandler.handleHome))
http.HandleFunc("/project/add", container.CookieSession.Auth(projectHandler.handleProjectAdd))
http.HandleFunc("/project/edit", container.CookieSession.Auth(projectHandler.handleProjectEdit))
http.HandleFunc("/project/delete", container.CookieSession.Auth(projectHandler.handleDeleteProject))
http.HandleFunc("GET /", container.CookieSession.Auth(projectHandler.indexHandler))
http.HandleFunc("GET /project/add", container.CookieSession.Auth(projectHandler.addGetHandler))
http.HandleFunc("POST /project/add", container.CookieSession.Auth(projectHandler.addPostHandler))
http.HandleFunc("GET /project/edit", container.CookieSession.Auth(projectHandler.editGetHandler))
http.HandleFunc("POST /project/edit", container.CookieSession.Auth(projectHandler.editPostHandler))
http.HandleFunc("GET /project/delete", container.CookieSession.Auth(projectHandler.deleteHandler))

// Resource route
resourceHandler := resourceHandler{container}
http.HandleFunc("/resources", container.CookieSession.Auth(resourceHandler.handleResourcesView))
http.HandleFunc("GET /resources", container.CookieSession.Auth(resourceHandler.indexHandler))

// User routes
userHandle := userHandler{container}
http.HandleFunc("/signup", userHandle.handleSignup)
http.HandleFunc("/signin", userHandle.handleSignin)
http.HandleFunc("/signout", container.CookieSession.Auth(userHandle.handleSignout))
http.HandleFunc("/account", container.CookieSession.Auth(userHandle.handleAccount))
http.HandleFunc("/account/delete", container.CookieSession.Auth((userHandle.handleDeleteUser)))
userHandler := userHandler{container}
http.HandleFunc("GET /signup", userHandler.signupGetHandler)
http.HandleFunc("POST /signup", userHandler.signupPostHandler)
http.HandleFunc("GET /signin", userHandler.signinGetHandler)
http.HandleFunc("POST /signin", userHandler.signinPostHandler)
http.HandleFunc("GET /account", container.CookieSession.Auth(userHandler.editGetHandler))
http.HandleFunc("POST /account", container.CookieSession.Auth(userHandler.editPostHandler))
http.HandleFunc("GET /account/delete", container.CookieSession.Auth((userHandler.deleteGetHandler)))
http.HandleFunc("POST /account/delete", container.CookieSession.Auth((userHandler.deletePostHandler)))
http.HandleFunc("GET /signout", container.CookieSession.Auth(userHandler.signoutHandler))

fmt.Printf("Starting server at %s on port %d...\n", container.Config.HTTPServer.Server, container.Config.HTTPServer.Port)
err := http.ListenAndServe(fmt.Sprintf("%s:%d", container.Config.HTTPServer.Server, container.Config.HTTPServer.Port), nil)
Expand Down
87 changes: 53 additions & 34 deletions internal/routes/crawl.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ type crawlHandler struct {
*services.Container
}

// handleCrawl handles the crawling of a project.
// startHandler handles the crawling of a project.
// It expects a query parameter "pid" containing the project id to be crawled.
// In case the project requieres BasicAuth it will redirect the user to the BasicAuth
// credentials URL. Otherwise, it starts a new crawler.
func (h *crawlHandler) handleCrawl(w http.ResponseWriter, r *http.Request) {
func (h *crawlHandler) startHandler(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.URL.Query().Get("pid"))
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
Expand Down Expand Up @@ -64,12 +64,12 @@ func (h *crawlHandler) handleCrawl(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/crawl/live?pid="+strconv.Itoa(pid), http.StatusSeeOther)
}

// handleStopCrawl handles the crawler stopping.
// stopHandler handles the crawler stopping.
// It expects a query paramater "pid" containinng the project id that is being crawled.
// Aftar making sure the user owns the project it is stopped.
// In case the request is made via ajax with the X-Requested-With header it will return
// a json response, otherwise it will redirect the user back to the live crawl page.
func (h *crawlHandler) handleStopCrawl(w http.ResponseWriter, r *http.Request) {
func (h *crawlHandler) stopHandler(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.URL.Query().Get("pid"))
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
Expand Down Expand Up @@ -103,12 +103,9 @@ func (h *crawlHandler) handleStopCrawl(w http.ResponseWriter, r *http.Request) {

// handleCrawlAuth handles the crawling of a project with BasicAuth.
// It expects a query parameter "pid" containing the project id to be crawled.
// A form will be presented to the user to input the BasicAuth credentials, once the
// form is submitted a crawler with BasicAuth is started.
// The function handles both GET and POST HTTP methods.
// GET: Renders the auth form.
// POST: Processes the auth form data and starts the crawler.
func (h *crawlHandler) handleCrawlAuth(w http.ResponseWriter, r *http.Request) {
// A form will be presented to the user to input the BasicAuth credentials.
// This handler handles the GET request.
func (h *crawlHandler) authGetHandler(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.URL.Query().Get("pid"))
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
Expand All @@ -127,40 +124,62 @@ func (h *crawlHandler) handleCrawlAuth(w http.ResponseWriter, r *http.Request) {
return
}

if r.Method == http.MethodPost {
err := r.ParseForm()
if err != nil {
http.Redirect(w, r, "/crawl/auth", http.StatusSeeOther)
return
}
pageView := &PageView{
PageTitle: "CRAWL_AUTH_VIEW",
Data: struct{ Project models.Project }{Project: p},
}

basicAuth := models.BasicAuth{
AuthUser: r.FormValue("username"),
AuthPass: r.FormValue("password"),
}
h.Renderer.RenderTemplate(w, "crawl_auth", pageView)
}

err = h.CrawlerService.StartCrawler(p, basicAuth)
if err != nil {
log.Printf("StartCrawler: %s %v\n", p.URL, err)
return
}
// Handle the BasicAuth form. Once it is submitted a crawler with BasicAuth is started.
// It Processes the auth form data and starts the crawler.
// This handler handles the POST request.
func (h *crawlHandler) authPostHandler(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.URL.Query().Get("pid"))
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}

http.Redirect(w, r, "/crawl/live?pid="+strconv.Itoa(pid), http.StatusSeeOther)
user, ok := h.CookieSession.GetUser(r.Context())
if !ok {
http.Redirect(w, r, "/signout", http.StatusSeeOther)
return
}

pageView := &PageView{
PageTitle: "CRAWL_AUTH_VIEW",
Data: struct{ Project models.Project }{Project: p},
p, err := h.ProjectService.FindProject(pid, user.Id)
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}

h.Renderer.RenderTemplate(w, "crawl_auth", pageView)
err = r.ParseForm()
if err != nil {
http.Redirect(w, r, "/crawl/auth", http.StatusSeeOther)
return
}

basicAuth := models.BasicAuth{
AuthUser: r.FormValue("username"),
AuthPass: r.FormValue("password"),
}

err = h.CrawlerService.StartCrawler(p, basicAuth)
if err != nil {
log.Printf("StartCrawler: %s %v\n", p.URL, err)
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}

http.Redirect(w, r, "/crawl/live?pid="+strconv.Itoa(pid), http.StatusSeeOther)
}

// handleCrawlLive handles the request for the live crawling of a project.
// liveCrawlHandler handles the request for the live crawling of a project.
// It expects a query parameter "pid" containing the project id to be crawled.
// This handler renders a page that will connect via websockets to display the progress
// of the crawl.
func (h *crawlHandler) handleCrawlLive(w http.ResponseWriter, r *http.Request) {
func (h *crawlHandler) liveCrawlHandler(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.URL.Query().Get("pid"))
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
Expand Down Expand Up @@ -205,10 +224,10 @@ func (h *crawlHandler) handleCrawlLive(w http.ResponseWriter, r *http.Request) {
h.Renderer.RenderTemplate(w, "crawl_live", v)
}

// handleCrawlWs handles the live crawling of a project using websockets.
// wsHandler handles the live crawling of a project using websockets.
// It expects a query parameter "pid" containing the project id.
// It upgrades the connection to websockets and sends the crawler messages through it.
func (h *crawlHandler) handleCrawlWs(w http.ResponseWriter, r *http.Request) {
func (h *crawlHandler) wsHandler(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.URL.Query().Get("pid"))
if err != nil {
w.WriteHeader(http.StatusBadRequest)
Expand Down
4 changes: 2 additions & 2 deletions internal/routes/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ type dashboardHandler struct {
*services.Container
}

// handleDashboard handles the dashboard of a project with all the needed data to render
// indexHandler handles the dashboard of a project with all the needed data to render
// the charts. It expects a query parameter "pid" containing the project id.
func (h *dashboardHandler) handleDashboard(w http.ResponseWriter, r *http.Request) {
func (h *dashboardHandler) indexHandler(w http.ResponseWriter, r *http.Request) {
user, ok := h.CookieSession.GetUser(r.Context())
if !ok {
http.Redirect(w, r, "/signout", http.StatusSeeOther)
Expand Down
4 changes: 2 additions & 2 deletions internal/routes/explorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ type explorerHandler struct {
*services.Container
}

// handleExplorer handles the URL explorer request.
// indexHandler handles the URL explorer request.
// It performas a search of pagereports based on the "term" parameter. In case the "term" parameter
// is empty, it loads all the pagereports.
// It expects a query parameter "pid" containing the project id, the "p" parameter containing the current
// page in the paginator, and the "term" parameter used to perform the pagereport search.
func (h *explorerHandler) handleExplorer(w http.ResponseWriter, r *http.Request) {
func (h *explorerHandler) indexHandler(w http.ResponseWriter, r *http.Request) {
// Get user from the request's context
user, ok := h.CookieSession.GetUser(r.Context())
if !ok {
Expand Down
16 changes: 8 additions & 8 deletions internal/routes/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ type exportHandler struct {
*services.Container
}

// handleExport handles the export request and renders the the export template.
// indexHandler handles the export request and renders the the export template.
// It expects a "pid" query parameter with the project's id.
func (h *exportHandler) handleExport(w http.ResponseWriter, r *http.Request) {
func (h *exportHandler) indexHandler(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.URL.Query().Get("pid"))
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
Expand Down Expand Up @@ -50,9 +50,9 @@ func (h *exportHandler) handleExport(w http.ResponseWriter, r *http.Request) {
})
}

// handleDownloadCSV exports the pagereports of a specific project as a CSV file by issue type.
// csvHandler exports the pagereports of a specific project as a CSV file by issue type.
// It expects a "pid" query parameter with the project's id.
func (h *exportHandler) handleDownloadCSV(w http.ResponseWriter, r *http.Request) {
func (h *exportHandler) csvHandler(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.URL.Query().Get("pid"))
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
Expand Down Expand Up @@ -87,9 +87,9 @@ func (h *exportHandler) handleDownloadCSV(w http.ResponseWriter, r *http.Request
}
}

// handleSitemap exports the crawled urls of a specific project as a sitemap.xml file.
// sitemapHandler exports the crawled urls of a specific project as a sitemap.xml file.
// It expects a "pid" query parameter with the project's id.
func (h *exportHandler) handleSitemap(w http.ResponseWriter, r *http.Request) {
func (h *exportHandler) sitemapHandler(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.URL.Query().Get("pid"))
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
Expand Down Expand Up @@ -122,10 +122,10 @@ func (h *exportHandler) handleSitemap(w http.ResponseWriter, r *http.Request) {
s.Write()
}

// handleExportResources exports the resources of a specific project.
// resourcesHandler exports the resources of a specific project.
// It expects a "pid" query parameter with the project's id as well as a query
// parameter "t" specifys the type of resources to be exported.
func (h *exportHandler) handleExportResources(w http.ResponseWriter, r *http.Request) {
func (h *exportHandler) resourcesHandler(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.URL.Query().Get("pid"))
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
Expand Down
8 changes: 4 additions & 4 deletions internal/routes/issues.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ type issueHandler struct {
*services.Container
}

// handleIssues handles the issues view of a project.
// indexHandler handles the issues view of a project.
// It expects a query parameter "pid" containing the project id.
func (h *issueHandler) handleIssues(w http.ResponseWriter, r *http.Request) {
func (h *issueHandler) indexHandler(w http.ResponseWriter, r *http.Request) {
user, ok := h.CookieSession.GetUser(r.Context())
if !ok {
http.Redirect(w, r, "/signout", http.StatusSeeOther)
Expand Down Expand Up @@ -52,10 +52,10 @@ func (h *issueHandler) handleIssues(w http.ResponseWriter, r *http.Request) {
h.Renderer.RenderTemplate(w, "issues", v)
}

// handleIssuesView handles the view of project's specific issue type.
// viewHandler handles the view of project's specific issue type.
// It expects a query parameter "pid" containing the project id and an "eid" parameter
// containing the issue type.
func (h *issueHandler) handleIssuesView(w http.ResponseWriter, r *http.Request) {
func (h *issueHandler) viewHandler(w http.ResponseWriter, r *http.Request) {
user, ok := h.CookieSession.GetUser(r.Context())
if !ok {
http.Redirect(w, r, "/signout", http.StatusSeeOther)
Expand Down
Loading

0 comments on commit 0633ac0

Please sign in to comment.