Skip to content

Commit

Permalink
add testdata
Browse files Browse the repository at this point in the history
  • Loading branch information
Skyenought committed Feb 6, 2024
1 parent 08bd994 commit 622a3e2
Show file tree
Hide file tree
Showing 29 changed files with 1,379 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmd/net/testdata/GoWeb/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
26 changes: 26 additions & 0 deletions cmd/net/testdata/GoWeb/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# GoWeb specific
env.json
logs/
*.log

# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories
vendor/

# Go workspace file
go.work

# IDE files
/.idea
9 changes: 9 additions & 0 deletions cmd/net/testdata/GoWeb/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
MIT License

Copyright (c) 2023 Maximilian Patterson

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
65 changes: 65 additions & 0 deletions cmd/net/testdata/GoWeb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# GoWeb 🌐

GoWeb is a simple Go web framework that aims to only use the standard library. The overall file structure and
development flow is inspired by larger frameworks like Laravel. It is partially ready for smaller projects if you are
fine with getting your hands dirty, but I plan on having it ready to go for more serious projects when it hits version
2.0.

<hr>

## Current features 🚀

- Routing/controllers
- Templating
- Simple database migration system
- Built in REST client
- CSRF protection
- Middleware
- Minimal user login/registration + sessions
- Config file handling
- Scheduled tasks
- Entire website compiles into a single binary (~10mb) (excluding env.json)
- Minimal dependencies (just standard library, postgres driver, and experimental package for bcrypt)

<hr>

## When to use 🙂

- You need to build a dynamic web application with persistent data
- You need to build a dynamic website using Go and need a good starting point
- You need to build an API in Go and don't know where to start
- Pretty much any use-case where you would use Laravel, Django, or Flask

## When not to use 🙃

- You need a static website (see [Hugo](https://gohugo.io/))
- You need a simple blog (see [Hugo](https://gohugo.io/))
- You need a simple site for your projects' documentation (see [Hugo](https://gohugo.io/))

## How to use 🤔

1. Clone
2. Delete the git folder, so you can start tracking in your own repo
3. Run `go get` to install dependencies
4. Copy env_example.json to env.json and fill in the values
5. Run `go run main.go` to start the server
6. Rename the occurences of "GoWeb" to your app name
7. Start building your app!
8. When you see useful changes to GoWeb you'd like in your project copy them over

## How to contribute 👨‍💻

- Open an issue on GitHub if you find a bug or have a feature request.
- [Email](mailto:[email protected]) me a patch if you want to contribute code.
- Please include a good description of what the patch does and why it is needed, also include how you want to be
credited in the commit message.

<hr>

### License and disclaimer 😤

- You are free to use this project under the terms of the MIT license. See LICENSE for more details.
- You and you alone are responsible for the security and everything else regarding your application.
- It is not required, but I ask that when you use this project you give me credit by linking to this repository.
- I also ask that when releasing self-hosted or other end-user applications that you release it under
the [GPLv3](https://www.gnu.org/licenses/gpl-3.0.html) license. This too is not required, but I would appreciate it.
15 changes: 15 additions & 0 deletions cmd/net/testdata/GoWeb/app/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package app

import (
"database/sql"
"embed"
"github.com/hertz-contrib/migrate/cmd/net/testdata/GoWeb/config"
)

// App contains and supplies available configurations and connections
type App struct {
Config config.Configuration // Configuration file
Db *sql.DB // Database connection
Res *embed.FS // Resources from the embedded filesystem
ScheduledTasks Scheduled // Scheduled contains a struct of all scheduled functions
}
71 changes: 71 additions & 0 deletions cmd/net/testdata/GoWeb/app/schedule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package app

import (
"sync"
"time"
)

type Scheduled struct {
EveryReboot []func(app *App)
EverySecond []func(app *App)
EveryMinute []func(app *App)
EveryHour []func(app *App)
EveryDay []func(app *App)
EveryWeek []func(app *App)
EveryMonth []func(app *App)
EveryYear []func(app *App)
}

type Task struct {
Funcs []func(app *App)
Interval time.Duration
}

func RunScheduledTasks(app *App, poolSize int, stop <-chan struct{}) {
for _, f := range app.ScheduledTasks.EveryReboot {
f(app)
}

tasks := []Task{
{Funcs: app.ScheduledTasks.EverySecond, Interval: time.Second},
{Funcs: app.ScheduledTasks.EveryMinute, Interval: time.Minute},
{Funcs: app.ScheduledTasks.EveryHour, Interval: time.Hour},
{Funcs: app.ScheduledTasks.EveryDay, Interval: 24 * time.Hour},
{Funcs: app.ScheduledTasks.EveryWeek, Interval: 7 * 24 * time.Hour},
{Funcs: app.ScheduledTasks.EveryMonth, Interval: 30 * 24 * time.Hour},
{Funcs: app.ScheduledTasks.EveryYear, Interval: 365 * 24 * time.Hour},
}

var wg sync.WaitGroup
runners := make([]chan bool, len(tasks))
for i, task := range tasks {
runner := make(chan bool, poolSize)
runners[i] = runner
wg.Add(1)
go func(task Task, runner chan bool) {
defer wg.Done()
ticker := time.NewTicker(task.Interval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
for _, f := range task.Funcs {
runner <- true
go func(f func(app *App)) {
defer func() { <-runner }()
f(app)
}(f)
}
case <-stop:
return
}
}
}(task, runner)
}

wg.Wait()

for _, runner := range runners {
close(runner)
}
}
55 changes: 55 additions & 0 deletions cmd/net/testdata/GoWeb/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package config

import (
"encoding/json"
"flag"
"log/slog"
"os"
)

type Configuration struct {
Db struct {
Ip string `json:"DbIp"`
Port string `json:"DbPort"`
Name string `json:"DbName"`
User string `json:"DbUser"`
Password string `json:"DbPassword"`
AutoMigrate bool `json:"DbAutoMigrate"`
}

Listen struct {
Ip string `json:"HttpIp"`
Port string `json:"HttpPort"`
}

Template struct {
BaseName string `json:"BaseTemplateName"`
ContentPath string `json:"ContentPath"`
}
}

// LoadConfig loads and returns a configuration struct
func LoadConfig() Configuration {
c := flag.String("c", "env.json", "Path to the json configuration file")
flag.Parse()
file, err := os.Open(*c)
if err != nil {
panic("unable to open JSON config file: " + err.Error())
}

defer func(file *os.File) {
err := file.Close()
if err != nil {
slog.Error("unable to close JSON config file: ", err)
}
}(file)

decoder := json.NewDecoder(file)
Config := Configuration{}
err = decoder.Decode(&Config)
if err != nil {
panic("unable to decode JSON config file: " + err.Error())
}

return Config
}
65 changes: 65 additions & 0 deletions cmd/net/testdata/GoWeb/controllers/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package controllers

import (
"github.com/hertz-contrib/migrate/cmd/net/testdata/GoWeb/app"
"github.com/hertz-contrib/migrate/cmd/net/testdata/GoWeb/models"
"github.com/hertz-contrib/migrate/cmd/net/testdata/GoWeb/security"
"github.com/hertz-contrib/migrate/cmd/net/testdata/GoWeb/templating"
"net/http"
)

// Get is a wrapper struct for the App struct
type Get struct {
App *app.App
}

func (g *Get) ShowHome(w http.ResponseWriter, _ *http.Request) {
type dataStruct struct {
Test string
}

data := dataStruct{
Test: "Hello World!",
}

templating.RenderTemplate(w, "templates/pages/home.html", data)
}

func (g *Get) ShowRegister(w http.ResponseWriter, r *http.Request) {
type dataStruct struct {
CsrfToken string
}

CsrfToken, err := security.GenerateCsrfToken(w, r)
if err != nil {
return
}

data := dataStruct{
CsrfToken: CsrfToken,
}

templating.RenderTemplate(w, "templates/pages/register.html", data)
}

func (g *Get) ShowLogin(w http.ResponseWriter, r *http.Request) {
type dataStruct struct {
CsrfToken string
}

CsrfToken, err := security.GenerateCsrfToken(w, r)
if err != nil {
return
}

data := dataStruct{
CsrfToken: CsrfToken,
}

templating.RenderTemplate(w, "templates/pages/login.html", data)
}

func (g *Get) Logout(w http.ResponseWriter, r *http.Request) {
models.LogoutUser(g.App, w, r)
http.Redirect(w, r, "/", http.StatusFound)
}
52 changes: 52 additions & 0 deletions cmd/net/testdata/GoWeb/controllers/post.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package controllers

import (
"github.com/hertz-contrib/migrate/cmd/net/testdata/GoWeb/app"
"github.com/hertz-contrib/migrate/cmd/net/testdata/GoWeb/models"
"log/slog"
"net/http"
"time"
)

// Post is a wrapper struct for the App struct
type Post struct {
App *app.App
}

func (p *Post) Login(w http.ResponseWriter, r *http.Request) {
username := r.FormValue("username")
password := r.FormValue("password")
remember := r.FormValue("remember") == "on"

if username == "" || password == "" {
http.Redirect(w, r, "/login", http.StatusUnauthorized)
}

_, err := models.AuthenticateUser(p.App, w, username, password, remember)
if err != nil {
http.Redirect(w, r, "/login", http.StatusUnauthorized)
return
}

http.Redirect(w, r, "/", http.StatusFound)
}

func (p *Post) Register(w http.ResponseWriter, r *http.Request) {
username := r.FormValue("username")
password := r.FormValue("password")
createdAt := time.Now()
updatedAt := time.Now()

if username == "" || password == "" {
http.Redirect(w, r, "/register", http.StatusUnauthorized)
}

_, err := models.CreateUser(p.App, username, password, createdAt, updatedAt)
if err != nil {
// TODO: if err == bcrypt.ErrPasswordTooLong display error to user, this will require a flash message system with cookies
slog.Error("error creating user: " + err.Error())
http.Redirect(w, r, "/register", http.StatusInternalServerError)
}

http.Redirect(w, r, "/login", http.StatusFound)
}
30 changes: 30 additions & 0 deletions cmd/net/testdata/GoWeb/database/connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package database

import (
"database/sql"
"fmt"
"github.com/hertz-contrib/migrate/cmd/net/testdata/GoWeb/app"
_ "github.com/lib/pq"
"log/slog"
)

// Connect returns a new database connection
func Connect(app *app.App) *sql.DB {
postgresConfig := fmt.Sprintf("host=%s port=%s user=%s "+
"password=%s dbname=%s sslmode=disable",
app.Config.Db.Ip, app.Config.Db.Port, app.Config.Db.User, app.Config.Db.Password, app.Config.Db.Name)

db, err := sql.Open("postgres", postgresConfig)
if err != nil {
panic(err)
}

err = db.Ping()
if err != nil {
panic(err)
}

slog.Info("connected to database successfully on " + app.Config.Db.Ip + ":" + app.Config.Db.Port + " using database " + app.Config.Db.Name)

return db
}
Loading

0 comments on commit 622a3e2

Please sign in to comment.