basic navigation and basic forms

This commit is contained in:
Florian Hoss 2022-03-30 14:54:01 +02:00
parent 9c6ddf6c60
commit faf460470e
27 changed files with 284 additions and 30 deletions

View file

@ -5,5 +5,6 @@
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="bootstrap" level="application" />
</component> </component>
</module> </module>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="sqlite" uuid="90df965d-ff21-4af2-b1e2-02d2ad7754f1">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:C:\Users\FlorianHoss\Documents\GitHub\SWB6-ITSec\Lab01\app\sqlite.db</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="PROJECT" libraries="{bootstrap}" />
</component>
</project>

View file

@ -1,26 +0,0 @@
package api
import (
"app/database"
"github.com/gin-gonic/gin"
)
func (api *Api) defineRoutes() {
api.Router.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
}
func (api *Api) initialize() {
api.Database = database.Database{Location: "sqlite.db"}
api.Database.Initialize()
}
func (api *Api) Run() {
api.initialize()
api.Router = gin.Default()
api.defineRoutes()
api.Router.Run()
}

View file

@ -8,6 +8,7 @@ type Database struct {
} }
type User struct { type User struct {
ID int
Username string Username string
Password string Password string
} }

View file

@ -3,6 +3,7 @@ module app
go 1.18 go 1.18
require ( require (
github.com/gin-contrib/static v0.0.1
github.com/gin-gonic/gin v1.7.7 github.com/gin-gonic/gin v1.7.7
gorm.io/driver/sqlite v1.3.1 gorm.io/driver/sqlite v1.3.1
gorm.io/gorm v1.23.3 gorm.io/gorm v1.23.3

View file

@ -3,6 +3,9 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-contrib/static v0.0.1 h1:JVxuvHPuUfkoul12N7dtQw7KRn/pSMq7Ue1Va9Swm1U=
github.com/gin-contrib/static v0.0.1/go.mod h1:CSxeF+wep05e0kCOsqWdAWbSszmc31zTIbD8TvWl7Hs=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
@ -11,6 +14,7 @@ github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8c
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=

View file

@ -1,8 +1,8 @@
package main package main
import "app/api" import "app/webpage"
func main() { func main() {
backend := api.Api{} backend := webpage.Webpage{}
backend.Run() backend.Run()
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,35 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.14, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M3397 6124 c-1 -1 -42 -5 -91 -8 -49 -4 -91 -8 -95 -10 -3 -2 -28 -6
-56 -10 -136 -16 -361 -80 -505 -143 -340 -147 -645 -380 -862 -657 -26 -33
-51 -65 -56 -71 -20 -26 -103 -156 -132 -207 -33 -59 -44 -71 -70 -75 -8 -1
-35 -5 -60 -8 -25 -4 -72 -13 -105 -22 -33 -8 -70 -17 -82 -19 -38 -7 -195
-65 -269 -99 -318 -146 -601 -404 -780 -713 -80 -138 -162 -346 -188 -476 -3
-11 -10 -46 -16 -76 -26 -128 -34 -391 -17 -540 57 -491 356 -968 780 -1245
193 -126 460 -232 652 -260 23 -3 52 -7 65 -10 14 -3 56 -7 95 -11 93 -8 2464
-8 2472 0 4 3 7 97 8 209 2 153 6 218 19 267 46 177 108 291 221 411 l48 51 3
92 c4 127 16 223 41 316 128 487 506 846 1005 956 84 19 366 28 443 14 125
-21 181 -35 266 -66 421 -151 743 -517 838 -952 10 -48 20 -65 20 -36 0 11 2
82 4 159 6 169 -3 249 -43 407 -82 319 -305 633 -584 823 -184 125 -448 225
-636 242 -36 3 -70 10 -77 15 -6 5 -17 32 -23 60 -63 295 -225 628 -428 879
-333 412 -850 713 -1347 785 -16 2 -39 6 -51 8 -56 11 -398 28 -407 20z"/>
<path d="M5595 3205 c-5 -2 -43 -11 -83 -20 -92 -21 -149 -46 -233 -101 -130
-86 -237 -227 -283 -374 -34 -105 -38 -151 -38 -425 l-1 -243 -39 -6 c-91 -15
-182 -89 -225 -183 l-26 -57 -1 -605 c-1 -423 2 -622 10 -659 17 -80 78 -162
147 -199 79 -42 69 -42 881 -40 l781 2 45 24 c66 35 134 110 158 172 20 52 21
75 21 666 1 453 -2 624 -11 657 -25 95 -120 188 -219 216 l-62 17 -2 269 c-2
148 -6 280 -9 294 -3 14 -9 38 -12 54 -7 41 -56 154 -90 207 -105 168 -263
276 -475 325 -26 6 -217 13 -234 9z m220 -310 c28 -8 77 -33 109 -55 67 -47
70 -50 111 -105 81 -109 88 -140 89 -441 l2 -251 -438 0 -439 0 1 248 c1 136
6 265 11 286 43 160 193 302 349 332 57 10 141 5 205 -14z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ .title }}</title>
{{template "head" .}}
</head>
<body>
{{template "navbar" .}}
<div class="position-absolute top-50 start-50 translate-middle">
<div>Welcome</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
</body>
</html>
{{define "head"}}
<link rel="apple-touch-icon" sizes="180x180" href="../static/icons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../static/icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../static/icons/favicon-16x16.png">
<link rel="manifest" href="../static/icons/site.webmanifest">
<link rel="mask-icon" href="../static/icons/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
{{end}}
{{define "navbar"}}
<nav class="navbar navbar-expand-md navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="/">SuperSave</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="ms-auto navbar-nav mb-2 mb-lg-0">
<li class="nav-item">
<a class="btn btn-primary" href="/login">Login</a>
</li>
<li class="nav-item">
<a class="btn btn-secondary" href="/register">Register</a>
</li>
</ul>
</div>
</div>
</nav>
{{end}}

View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ .title }}</title>
{{template "head" .}}
</head>
<body>
{{template "navbar" .}}
<div class="position-absolute top-50 start-50 translate-middle">
<form action="http://localhost:8080/register" method="POST">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" aria-describedby="emailHelp">
<div id="emailHelp" class="form-text">The username needs to be unique</div>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" aria-describedby="passwordHelp">
<div id="passwordHelp" class="form-text">The password needs to be different from the username</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
</body>
</html>

View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ .title }}</title>
{{template "head" .}}
</head>
<body>
{{template "navbar" .}}
<div class="position-absolute top-50 start-50 translate-middle">
<form action="http://localhost:8080/register" method="POST">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" aria-describedby="emailHelp">
<div id="emailHelp" class="form-text">The username needs to be unique</div>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" aria-describedby="passwordHelp">
<div id="passwordHelp" class="form-text">The password needs to be different from the username</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script>
let formData = new FormData();
formData.append("username", "Florian");
formData.append("password", "SuperSafe");
let requestOptions = {
method: 'POST',
body: formData,
redirect: 'follow'
};
fetch("http://localhost:8080/register", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
</script>
</body>
</html>

View file

@ -1,11 +1,11 @@
package api package webpage
import ( import (
"app/database" "app/database"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
type Api struct { type Webpage struct {
Database database.Database Database database.Database
Router *gin.Engine Router *gin.Engine
} }

View file

@ -0,0 +1,69 @@
package webpage
import (
"app/database"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func (wp *Webpage) defineRoutes() {
wp.Router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "Register",
})
})
wp.Router.GET("/login", func(c *gin.Context) {
c.HTML(http.StatusOK, "login.tmpl", gin.H{
"title": "Login",
})
})
wp.Router.GET("/register", func(c *gin.Context) {
c.HTML(http.StatusOK, "register.tmpl", gin.H{
"title": "Register",
})
})
wp.Router.GET("/health", func(c *gin.Context) {
currentTime := time.Now().UnixMilli()
c.JSON(http.StatusOK, gin.H{
"timestamp": currentTime,
})
})
wp.Router.NoRoute(func(c *gin.Context) {
c.Redirect(http.StatusTemporaryRedirect, "/")
})
wp.Router.POST("/register", func(c *gin.Context) {
username, err := c.GetPostForm("username")
password, err := c.GetPostForm("password")
if err == false {
c.JSON(400, gin.H{"message": "bad post form"})
return
}
user := database.User{Username: username, Password: password}
result := wp.Database.ORM.Create(&user)
if result.Error != nil {
c.JSON(200, gin.H{"message": "cannot create user"})
}
c.JSON(200, gin.H{"message": "user registered"})
})
}
func (wp *Webpage) initialize() {
wp.Database = database.Database{Location: "sqlite.db"}
wp.Database.Initialize()
}
func (wp *Webpage) Run() {
wp.initialize()
wp.Router = gin.New()
wp.Router.Use(gin.Recovery())
wp.Router.Use(gin.Logger())
wp.Router.SetTrustedProxies(nil)
wp.Router.Use(static.Serve("/static", static.LocalFile("./static", false)))
wp.Router.LoadHTMLGlob("templates/*")
wp.defineRoutes()
wp.Router.Run()
}