1 Commits

Author SHA1 Message Date
7730257cce Merge branch 'main' into login 2023-10-25 20:19:43 +02:00
22 changed files with 76 additions and 279 deletions

1
.gitignore vendored
View File

@ -1,5 +1,4 @@
/.vscode
/__debug*
/build
/tmp
/config.yaml

View File

@ -1,8 +1,2 @@
EXEC=iris-test
run:
@air
.PHONY: build
build:
@go build -ldflags "-s -w" -o ./build/${EXEC} ./app/main.go

View File

@ -11,48 +11,3 @@
- [Source](https://github.com/CloudyKit/jet)
- [Syntax reference](https://github.com/CloudyKit/jet/blob/master/docs/syntax.md)
## Howto
- [Password Hashing (bcrypt)](https://gowebexamples.com/password-hashing/)
## Bombardier benchmark
Pandora - Jet templating engine
```
eden@pandora:[~/apps/sandbox/golang/iris-web-framework]: bombardier -c 100 -d 10s -l http://localhost:8000 ±[A1][main]
Bombarding http://localhost:8000 for 10s using 100 connection(s)
Done!
Statistics Avg Stdev Max
Reqs/sec 10542.16 2631.23 17296.86
Latency 9.50ms 3.22ms 42.93ms
Latency Distribution
50% 8.77ms
75% 11.86ms
90% 15.31ms
95% 17.86ms
99% 23.90ms
HTTP codes:
1xx - 0, 2xx - 105258, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 28.08MB/s
```
```
eden@pandora:[~/apps/sandbox/golang/iris-web-framework]: bombardier -c 100 -d 10s -l http://localhost:8000/users ±[A1][main]
Bombarding http://localhost:8000/users for 10s using 100 connection(s)
Done!
Statistics Avg Stdev Max
Reqs/sec 1096.26 427.09 3211.54
Latency 91.08ms 80.06ms 471.41ms
Latency Distribution
50% 78.37ms
75% 156.58ms
90% 191.60ms
95% 223.49ms
99% 309.59ms
HTTP codes:
1xx - 0, 2xx - 11060, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 19.91MB/s
```

View File

@ -1,4 +1,4 @@
package common
package main
import (
"fmt"

View File

@ -1,4 +1,4 @@
package common
package main
import (
"fmt"

View File

@ -1,4 +1,4 @@
package common
package main
import (
"encoding/json"

View File

@ -2,7 +2,6 @@ package main
import (
"fmt"
"iris-test/app/common"
"iris-test/app/views"
"os"
"time"
@ -16,32 +15,32 @@ import (
var redisDB *redis.Database
func createSessionEngine() *sessions.Sessions {
redisAddr := fmt.Sprintf("%s:%d", common.Config.Redis.Host, common.Config.Redis.Port)
redisAddr := fmt.Sprintf("%s:%d", Config.Redis.Host, Config.Redis.Port)
redisDB = redis.New(redis.Config{
Network: "tcp",
Addr: redisAddr,
Timeout: time.Duration(30) * time.Second,
MaxActive: 10,
Username: common.Config.Redis.Username,
Password: common.Config.Redis.Password,
Database: common.Config.Redis.Database,
Prefix: common.Config.Redis.Prefix,
Username: Config.Redis.Username,
Password: Config.Redis.Password,
Database: Config.Redis.Database,
Prefix: Config.Redis.Prefix,
Driver: redis.GoRedis(), // defaults to this driver.
// To set a custom, existing go-redis client, use the "SetClient" method:
// Driver: redis.GoRedis().SetClient(customGoRedisClient)
})
sessionsEngine := sessions.New(sessions.Config{
sessions_engine := sessions.New(sessions.Config{
Cookie: "_session_id",
Expires: 0, // defaults to 0: unlimited life. Another good value is: 45 * time.Minute,
AllowReclaim: true,
CookieSecureTLS: true,
})
sessionsEngine.UseDatabase(redisDB)
sessions_engine.UseDatabase(redisDB)
return sessionsEngine
return sessions_engine
}
func createAccessLog() *accesslog.AccessLog {
@ -84,18 +83,18 @@ func createApp() *iris.Application {
accessLog := createAccessLog()
app := iris.New()
app.Logger().SetLevel(common.Config.Application.LogLevel)
app.Logger().SetLevel(Config.Application.LogLevel)
app.Use(sessionsEngine.Handler())
app.UseRouter(accessLog.Handler)
app.RegisterView(iris.Django("./app/templates", ".html").Reload(true))
app.RegisterView(iris.Jet("./app/templates", ".jet").Reload(true))
views.CreateRouter(app)
return app
}
func main() {
common.InitCfg()
common.InitLogging()
common.InitDB()
InitCfg()
InitLogging()
InitDB()
app := createApp()
defer redisDB.Close()

View File

@ -1,8 +1,6 @@
package models
import (
"time"
)
import "time"
type User struct {
Id string `gorm:"type(uuid);unique"`
@ -18,9 +16,3 @@ type User struct {
func (u *User) TableName() string {
return "users"
}
// func (u *User) SetPassword(password string) (string, error) {
// secretKey := Config.Application.SecretKey
// bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
// return string(bytes), err
// }

View File

@ -12,7 +12,6 @@ type UsersRepository struct {
}
type UserFilter struct {
Id *string
IsActive *bool
}
@ -23,14 +22,9 @@ func CreateUsersRepository(db *gorm.DB) *UsersRepository {
func applyFilter(db *gorm.DB, filter *UserFilter) *gorm.DB {
query := db
if filter.Id != nil {
query = query.Where("id = ?", filter.Id)
}
if filter.IsActive != nil {
query = query.Where(map[string]interface{}{"is_active": filter.IsActive})
}
// if filter.State != "" {
// query = query.Where("state = ?", filter.State)
// }
// if filter.SendAt_lt != nil {
// query = query.Where("send_at < ?", filter.SendAt_lt)
// }
@ -75,18 +69,3 @@ func (repository *UsersRepository) List(filter *UserFilter, pagination *Paginati
return &users
}
func (repository *UsersRepository) Get(filter *UserFilter) *models.User {
var user models.User
query := repository.db.Model(&models.User{})
query = applyFilter(query, filter)
query.First(&user)
return &user
}
func (repository *UsersRepository) Save(user *models.User) *models.User {
repository.db.Save(user)
return user
}

View File

@ -1,33 +0,0 @@
{% set title = "Hello world" %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-3">
<h1>{{ title }}</h1>
<ul class="nav">
<li class="nav-item">
<a href="/" class="nav-link">Frontpage</a>
</li>
<li class="nav-item">
<a href="/users" class="nav-link">Users</a>
</li>
<li class="nav-item">
<a href="/about" class="nav-link">About</a>
</li>
</ul>
<main>
{% block mainContent %}{% endblock %}
</main>
</div>
</body>
</html>

View File

@ -0,0 +1,27 @@
{{ title := "Hello world" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>{{ title }}</h1>
<p>
<a href="/">Frontpage</a>
<a href="/users">Users</a>
<a href="/about">About</a>
</p>
<main>
{{ yield mainContent() }}
</main>
</div>
</body>
</html>

View File

@ -1,24 +0,0 @@
{% macro usersTable(users) %}
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>First name</th>
<th>Last name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>
<a href="/users/{{ user.Id }}">{{ user.Id }}</a>
</td>
<td>{{ user.FirstName }}</td>
<td>{{ user.LastName }}</td>
<td>{{ user.Email }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endmacro %}

View File

@ -0,0 +1,15 @@
{{ block usersTable(users) }}
<p>blablabla</p>
<table class="table">
<tbody>
{{ range users }}
<tr>
<td>{{ .FirstName }}</td>
<td>{{ .LastName }}</td>
<td>{{ .Email }}</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}

View File

@ -1,28 +0,0 @@
{% extends "/base/base.html" %}
{% block mainContent %}
<div class="row">
<form class="mb-5 col-4 ms-auto me-auto" method="post" action="/">
<div class="mb-3">
<label class="form-label">Email address</label>
<input type="email" name="email" class="form-control" value="edkirin@gmail.com">
</div>
<div class="mb-3">
<label class="form-label">Password</label>
<input type="text" name="password" class="form-control" value="tralala">
</div>
<button type="submit" class="btn btn-success">
Submit
</button>
</form>
</div>
<div class="lead">
<p>Bacon ipsum dolor amet leberkas kevin meatball pork loin beef ribs prosciutto, turducken bacon bresaola tri-tip. Strip steak flank shankle, sirloin short ribs shoulder meatball pork chop kevin ribeye jowl ham pork belly turducken jerky. Flank tongue short loin ham hock brisket turducken tail filet mignon cupim. Pork capicola buffalo kevin jowl chicken. Filet mignon brisket pig, landjaeger sausage cow fatback drumstick chicken buffalo tenderloin spare ribs.</p>
<p>Swine shankle porchetta pancetta. Buffalo chicken turducken ground round kevin shoulder, salami pig t-bone beef ribs tri-tip tongue pork belly doner. Landjaeger meatloaf short loin biltong. Alcatra tongue shankle, tri-tip pancetta porchetta tenderloin corned beef pastrami rump. Bresaola chislic beef kielbasa sausage, ball tip burgdoggen boudin capicola short loin tenderloin buffalo landjaeger.</p>
</div>
{% endblock %}

View File

@ -1,5 +1,5 @@
{{ extends "/base/base.html" }}
{{ import "/components/table_component.html" }}
{{ extends "/base/base.jet" }}
{{ import "/components/table_component.jet" }}
{{ block mainContent() }}

View File

@ -1,35 +0,0 @@
{{ extends "/base/base.jet" }}
{{ import "/components/table_component.jet" }}
{{ block mainContent() }}
<h3>Edit user</h3>
<div class="row">
<form class="mb-5 col-4 ms-auto me-auto" method="post" action="{{ .currentPath }}">
<div class="mb-3">
<label class="form-label">First name</label>
<input type="text" name="first-name" class="form-control" value="{{ user.FirstName }}" required>
</div>
<div class="mb-3">
<label class="form-label">Last name</label>
<input type="text" name="last-name" class="form-control" value="{{ user.LastName }}" required>
</div>
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" name="email" class="form-control" value="{{ user.Email }}" required>
</div>
<div class="d-flex">
<a href="/users" class="btn btn-outline-secondary ms-auto me-2">
Cancel
</a>
<button type="submit" class="btn btn-success">
Save
</button>
</div>
</form>
</div>
{{ end }}

View File

@ -3,7 +3,13 @@
{{ block mainContent() }}
<h3>Users</h3>
<ul>
{{ range params1 }}
<li>{{ . }}</li>
{{ end }}
</ul>
<h3>{{ title }}</h3>
{{ yield usersTable(users=users) }}
{{ end }}

View File

@ -7,7 +7,7 @@ import (
)
func GetIndexPage(ctx iris.Context) {
if err := ctx.View("pages/index.html"); err != nil {
if err := ctx.View("pages/index.jet"); err != nil {
showError(ctx, err)
return
}

View File

@ -7,8 +7,5 @@ func CreateRouter(app *iris.Application) {
app.Post("/", PostIndexPage)
app.Get("/users", GetUsersPage)
app.Get("/users/{userId:uuid}", EditUserPage)
app.Post("/users/{userId:uuid}", SaveUserPage)
app.Get("/about", GetAboutPage)
}

View File

@ -6,13 +6,10 @@ import (
"github.com/kataras/iris/v12"
)
type editUserForm struct {
FirstName string `form:"first-name"`
LastName string `form:"last-name"`
Email string `form:"email"`
}
func GetUsersPage(ctx iris.Context) {
params1 := []string{"param 1", "param 2", "param 3"}
ctx.ViewData("params1", params1)
userRepository := repository.Dao.UsersRepository
pagination := repository.NewPagination()
@ -21,8 +18,7 @@ func GetUsersPage(ctx iris.Context) {
repository.NewOrdering("last_name", repository.ORDERING_ASC),
}
isActive := true
users := userRepository.List(&repository.UserFilter{IsActive: &isActive}, &pagination, &ordering)
users := userRepository.List(&repository.UserFilter{}, &pagination, &ordering)
ctx.ViewData("users", users)
@ -31,42 +27,3 @@ func GetUsersPage(ctx iris.Context) {
return
}
}
func EditUserPage(ctx iris.Context) {
userId := ctx.Params().Get("userId")
userRepository := repository.Dao.UsersRepository
filter := repository.UserFilter{Id: &userId}
user := userRepository.Get(&filter)
ctx.ViewData("user", user)
ctx.ViewData("currentPath", ctx.Path())
if err := ctx.View("pages/user-edit.jet"); err != nil {
showError(ctx, err)
return
}
}
func SaveUserPage(ctx iris.Context) {
var form editUserForm
err := ctx.ReadForm(&form)
if err != nil {
ctx.StopWithError(iris.StatusBadRequest, err)
return
}
userId := ctx.Params().Get("userId")
userRepository := repository.Dao.UsersRepository
filter := repository.UserFilter{Id: &userId}
user := userRepository.Get(&filter)
user.FirstName = form.FirstName
user.LastName = form.LastName
user.Email = form.Email
userRepository.Save(user)
ctx.Redirect("/users")
}

1
go.mod
View File

@ -23,7 +23,6 @@ require (
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/flosch/pongo2/v4 v4.0.2 // indirect
github.com/flosch/pongo2/v6 v6.0.0 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 // indirect
github.com/google/uuid v1.3.1 // indirect

2
go.sum
View File

@ -30,8 +30,6 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
github.com/flosch/pongo2/v6 v6.0.0 h1:lsGru8IAzHgIAw6H2m4PCyleO58I40ow6apih0WprMU=
github.com/flosch/pongo2/v6 v6.0.0/go.mod h1:CuDpFm47R0uGGE7z13/tTlt1Y6zdxvr2RLT5LJhsHEU=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=