summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel W <samuel.wilhelmsson@gmail.com>2024-02-25 15:53:36 +0100
committerSamuel W <samuel.wilhelmsson@gmail.com>2024-02-25 15:53:36 +0100
commit8488643e5efe4c89ee1abe6f05a8857b8ab122d1 (patch)
tree802f3e2512fa430fb2a1ef5dc370c57a229d595b
parent9a59ce82149865f059157e8a050b7a3e15ca55b2 (diff)
downloadtinygram-8488643e5efe4c89ee1abe6f05a8857b8ab122d1.tar.gz
tinygram-8488643e5efe4c89ee1abe6f05a8857b8ab122d1.zip
working thing
-rw-r--r--assets/firstpost.pngbin40747 -> 0 bytes
-rw-r--r--assets/otherstyle.css143
-rw-r--r--assets/style.css31
-rw-r--r--go.mod7
-rw-r--r--go.sum16
-rw-r--r--index.templ66
-rw-r--r--index_templ.go143
-rw-r--r--main.go144
8 files changed, 382 insertions, 168 deletions
diff --git a/assets/firstpost.png b/assets/firstpost.png
deleted file mode 100644
index 802f95d..0000000
--- a/assets/firstpost.png
+++ /dev/null
Binary files differ
diff --git a/assets/otherstyle.css b/assets/otherstyle.css
deleted file mode 100644
index 6e87aae..0000000
--- a/assets/otherstyle.css
+++ /dev/null
@@ -1,143 +0,0 @@
-
-.content {
- display: flex;
- flex-direction: column;
- padding-top: 90px;
- padding-left: 32px;
- padding-right: 32px;
- justify-content: center;
- gap: 44px;
- word-wrap:break-word;
- align-items: center;
-}
-
-.navbar {
- padding-left: 32px;
- padding-right: 32px;
- justify-content: center;
- word-wrap:break-word;
- align-items: center;
-}
-
-.main {
- max-width: 700px;
- width: 100%;
- display: flex;
- flex-direction: column;
-}
-
-.series {
- font-size: 12px;
- font-weight: 500;
- text-decoration: underline
-}
-
-.series {
- font-size: 12px;
- font-weight: 500;
- text-decoration: underline
-}
-
-.side {
- display: flex;
- flex-direction: column;
- align-items: center;
-}
-
-.profilepic {
- width: 150pt;
- border-radius: 50%;
-}
-
-.flexrow {
- display: flex;
- flex-direction: row;
- align-items: center;
-}
-
-
-time {
- font-size: 12px
-}
-
-.tag {
- background-color: #A0A0A0;
- padding: 4px;
- margin-right: 2px;
- font-size: 12px;
-}
-
-@media (max-width: 500px) {
- .tagcontainer{
- display: none;
- }
-}
-
-.posttitle {
- font-size: 19px;
- font-weight:500;
- text-decoration: underline;
-}
-
-nav {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: center;
- width: 100%;
- position: fixed;
- height: 90px;
- font-size: 30px;
- background-color: #C0C0C0;
- z-index: 1000;
-}
-
-.socials {
- font-size: 15px;
- text-decoration: none;
- font-weight: 600;
- text-decoration: underline;
- padding-right: 4px;
-}
-
-pre {
- background: #f4f4f4;
- border: 1px solid #ddd;
- color: #666;
- page-break-inside: avoid;
- font-family: monospace;
- font-size: 15px;
- line-height: 1.6;
- margin-bottom: 1.6em;
- max-width: 100%;
- overflow: auto;
- padding: 1em 1.5em;
- display: block;
- word-wrap: break-word;
-}
-
-a,a:visited{
- color: black;
- text-decoration: none;
-}
-
-p>a{
- text-decoration: underline;
- font-weight: 600;
-}
-
-code{
- font-size: 15px;
-}
-
-body {
- margin: 0;
- font-family: Arial, Helvetica, sans-serif;
- background-color: lightgray
-}
-
-
-.title {
- font-weight: 600;
-}
-
diff --git a/assets/style.css b/assets/style.css
index 1abdc8e..2994f18 100644
--- a/assets/style.css
+++ b/assets/style.css
@@ -8,6 +8,22 @@ body {
justify-content:center;
}
+.upload {
+ display: flex;
+ justify-content:center;
+ flex-direction: column;
+}
+
+#uploadlink {
+ text-decoration: none;
+ color: black;
+}
+
+.imgcontainer {
+ width: 100%;
+ padding-top: 100%;
+ position: relative;
+}
#container {
max-width: 600px;
@@ -17,8 +33,19 @@ body {
align-items:center;
}
+#posts {
+ width: 100%;
+}
+
img{
- width:100%;
+ object-fit: cover;
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ height: 100%;
+ width: 100%;
}
.description {
@@ -44,7 +71,7 @@ img{
padding-left: 10px;
padding-right: 10px;
justify-content: center;
- gap: 20px;
+ gap: 5px;
word-wrap:break-word;
align-items: center;
}
diff --git a/go.mod b/go.mod
index 8d63791..7b7ece0 100644
--- a/go.mod
+++ b/go.mod
@@ -4,17 +4,24 @@ go 1.21.6
require (
github.com/a-h/templ v0.2.513
+ github.com/gorilla/sessions v1.2.2
+ github.com/labstack/echo-contrib v0.15.0
github.com/labstack/echo/v4 v4.11.4
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55
)
require (
+ github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
+ github.com/gorilla/context v1.1.1 // indirect
+ github.com/gorilla/securecookie v1.1.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
+ golang.org/x/time v0.5.0 // indirect
)
require (
+ github.com/google/uuid v1.6.0
github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
diff --git a/go.sum b/go.sum
index 56c5742..79837ee 100644
--- a/go.sum
+++ b/go.sum
@@ -2,12 +2,26 @@ github.com/a-h/templ v0.2.513 h1:ZmwGAOx4NYllnHy+FTpusc4+c5msoMpPIYX0Oy3dNqw=
github.com/a-h/templ v0.2.513/go.mod h1:9gZxTLtRzM3gQxO8jr09Na0v8/jfliS97S9W5SScanM=
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/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
+github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
+github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
+github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
+github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/labstack/echo-contrib v0.15.0 h1:9K+oRU265y4Mu9zpRDv3X+DGTqUALY6oRHCSZZKCRVU=
+github.com/labstack/echo-contrib v0.15.0/go.mod h1:lei+qt5CLB4oa7VHTE0yEfQSEB9XTJI1LUqko9UWvo4=
github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8=
github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
@@ -37,6 +51,8 @@ golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.5.4 h1:IqXwXi8M/ZlPzH/947tn5uik3aYQslP9BVveoax0nV0=
diff --git a/index.templ b/index.templ
index 5da5272..b0faf2d 100644
--- a/index.templ
+++ b/index.templ
@@ -18,7 +18,7 @@ templ index(ps []Post) {
<body>
<div id="container">
<div id="header">
- <h2>Tinygram</h2>
+ <a id="uploadlink" href="/upload"><h2>Tinygram</h2></a>
</div>
<div id="posts">
@posts(ps)
@@ -28,10 +28,72 @@ templ index(ps []Post) {
</html>
}
+templ loginPage(csrfToken string) {
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8"/>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
+ <script src="/static/htmx.min.js"></script>
+ <link rel="preload" href="/static/style.css" as="style"/>
+ <link rel="stylesheet" href="/static/style.css"/>
+ </head>
+ <body>
+ <form
+ class="login"
+ hx-encoding="multipart/form-data"
+ hx-post="/login"
+ >
+ <input type="password" name="password"/>
+ <input type="hidden" name="_csrf" value={ csrfToken }/>
+ <button>
+ Login
+ </button>
+ </form>
+ </body>
+ </html>
+}
+
+templ uploadPage(csrfToken string) {
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8"/>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
+ <script src="/static/htmx.min.js"></script>
+ <link rel="preload" href="/static/style.css" as="style"/>
+ <link rel="stylesheet" href="/static/style.css"/>
+ </head>
+ <body>
+ <form
+ class="upload"
+ hx-encoding="multipart/form-data"
+ hx-post="/upload"
+ _="on htmx:xhr:progress(loaded, total) set #progress.value to (loaded/total)*100"
+ >
+ <input type="file" name="file" accept="image/png, image/jpeg"/>
+ <input type="hidden" name="_csrf" value={ csrfToken }/>
+ <div>
+ <span>Description:</span>
+ <input type="text" name="description"/>
+ </div>
+ <button>
+ Upload
+ </button>
+ <progress id="progress" value="0" max="100"></progress>
+ </form>
+ </body>
+ </html>
+}
+
templ posts(posts []Post) {
for _, post := range posts {
<div class="post">
- <img src="/static/firstpost.png" alt={ post.ImageID }/>
+ <div class="imgcontainer">
+ <img src={ post.ImageID } alt={ post.ImageID }/>
+ </div>
<div class="summary">
<p class="description">{ post.Description }</p>
<p class="date">{ post.CreatedAt.Format("2006-01-02 - 15:04") }</p>
diff --git a/index_templ.go b/index_templ.go
index d03d535..748e10d 100644
--- a/index_templ.go
+++ b/index_templ.go
@@ -36,7 +36,7 @@ func index(ps []Post) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</script><link rel=\"preload\" href=\"/static/style.css\" as=\"style\"><link rel=\"stylesheet\" href=\"/static/style.css\"></head><body><div id=\"container\"><div id=\"header\"><h2>")
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</script><link rel=\"preload\" href=\"/static/style.css\" as=\"style\"><link rel=\"stylesheet\" href=\"/static/style.css\"></head><body><div id=\"container\"><div id=\"header\"><a id=\"uploadlink\" href=\"/upload\"><h2>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -45,7 +45,7 @@ func index(ps []Post) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h2></div><div id=\"posts\">")
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h2></a></div><div id=\"posts\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -64,7 +64,7 @@ func index(ps []Post) templ.Component {
})
}
-func posts(posts []Post) templ.Component {
+func loginPage(csrfToken string) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
@@ -77,8 +77,125 @@ func posts(posts []Post) templ.Component {
templ_7745c5c3_Var4 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html><head><meta charset=\"utf-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\"><script src=\"/static/htmx.min.js\">")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Var5 := ``
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</script><link rel=\"preload\" href=\"/static/style.css\" as=\"style\"><link rel=\"stylesheet\" href=\"/static/style.css\"></head><body><form class=\"login\" hx-encoding=\"multipart/form-data\" hx-post=\"/login\"><input type=\"password\" name=\"password\"> <input type=\"hidden\" name=\"_csrf\" value=\"")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(csrfToken))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"> <button>")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Var6 := `Login`
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button></form></body></html>")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+func uploadPage(csrfToken string) templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var7 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var7 == nil {
+ templ_7745c5c3_Var7 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html><head><meta charset=\"utf-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\"><script src=\"/static/htmx.min.js\">")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Var8 := ``
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var8)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</script><link rel=\"preload\" href=\"/static/style.css\" as=\"style\"><link rel=\"stylesheet\" href=\"/static/style.css\"></head><body><form class=\"upload\" hx-encoding=\"multipart/form-data\" hx-post=\"/upload\" _=\"on htmx:xhr:progress(loaded, total) set #progress.value to (loaded/total)*100\"><input type=\"file\" name=\"file\" accept=\"image/png, image/jpeg\"> <input type=\"hidden\" name=\"_csrf\" value=\"")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(csrfToken))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><div><span>")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Var9 := `Description:`
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span> <input type=\"text\" name=\"description\"></div><button>")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Var10 := `Upload`
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var10)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button> <progress id=\"progress\" value=\"0\" max=\"100\"></progress></form></body></html>")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+func posts(posts []Post) templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var11 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var11 == nil {
+ templ_7745c5c3_Var11 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
for _, post := range posts {
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"post\"><img src=\"/static/firstpost.png\" alt=\"")
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"post\"><div class=\"imgcontainer\"><img src=\"")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(post.ImageID))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" alt=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -86,16 +203,16 @@ func posts(posts []Post) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><div class=\"summary\"><p class=\"description\">")
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></div><div class=\"summary\"><p class=\"description\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var5 string
- templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(post.Description)
+ var templ_7745c5c3_Var12 string
+ templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(post.Description)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 35, Col: 45}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 97, Col: 45}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -103,12 +220,12 @@ func posts(posts []Post) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var6 string
- templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(post.CreatedAt.Format("2006-01-02 - 15:04"))
+ var templ_7745c5c3_Var13 string
+ templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(post.CreatedAt.Format("2006-01-02 - 15:04"))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 36, Col: 65}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 98, Col: 65}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/main.go b/main.go
index 8bf3459..6b23ace 100644
--- a/main.go
+++ b/main.go
@@ -1,10 +1,19 @@
package main
import (
+ "bufio"
"fmt"
+ "io"
+ "net/http"
+ "os"
+ "path"
"time"
+ "github.com/google/uuid"
+ "github.com/gorilla/sessions"
+ "github.com/labstack/echo-contrib/session"
"github.com/labstack/echo/v4"
+ "github.com/labstack/echo/v4/middleware"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
@@ -16,21 +25,47 @@ type Post struct {
}
func main() {
- e := echo.New()
- db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{})
+ dbPath := os.Getenv("DB_PATH")
+ if dbPath == "" {
+ dbPath = "tinygram.db"
+ }
- post := Post{
- Description: "Test image :>",
- ImageID: "/static/firstpost.png",
+ sessionSecret := os.Getenv("SESSION_SECRET")
+ if sessionSecret == "" {
+ fmt.Println("NEED TO PROVIDE A SECRET")
+ return
}
- db.AutoMigrate(Post{})
- db.Create(&post)
+ passwordFilePath := os.Getenv("PASSWORD_FILE_PATH")
+ if passwordFilePath == "" {
+ passwordFilePath = "password.txt"
+ }
+
+ assetsPath := os.Getenv("ASSETS_PATH")
+ if assetsPath == "" {
+ assetsPath = "assets"
+ }
+
+ e := echo.New()
+ // e.Use(middleware.Logger())
+ e.Use(middleware.Recover())
+ e.Use(middleware.Secure())
+
+ e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{
+ TokenLookup: "form:_csrf",
+ }))
+
+ e.Use(session.Middleware(sessions.NewCookieStore([]byte(sessionSecret))))
+
+ db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
+
+ db.AutoMigrate(Post{})
if err != nil {
- fmt.Errorf("opening db: %w", err)
+ fmt.Printf("opening db: %v", err)
}
+
e.Static("/static", "assets")
e.GET("/", func(c echo.Context) error {
@@ -44,6 +79,99 @@ func main() {
return nil
})
+ e.GET("/login", func(c echo.Context) error {
+ component := loginPage(c.Get(middleware.DefaultCSRFConfig.ContextKey).(string))
+ err := component.Render(c.Request().Context(), c.Response().Writer)
+ if err != nil {
+ return err
+ }
+ return nil
+ })
+
+ e.POST("/login", func(c echo.Context) error {
+ // read password file, check content, add session if correct
+ file, err := os.Open(passwordFilePath)
+ if err != nil {
+ c.Response().Header().Set("HX-Redirect", "/")
+ return c.NoContent(http.StatusUnauthorized)
+ }
+
+ // check provided password against file
+ s := bufio.NewScanner(file)
+ s.Scan()
+ expected := s.Text()
+ formPass := c.FormValue("password")
+
+ if expected != formPass {
+ c.Response().Header().Set("HX-Redirect", "/")
+ return c.NoContent(http.StatusUnauthorized)
+ }
+
+ sess, _ := session.Get("session", c)
+ sess.Options = &sessions.Options{
+ Path: "/",
+ MaxAge: 86400 * 7,
+ HttpOnly: true,
+ }
+ sess.Values["user"] = "admin"
+ sess.Save(c.Request(), c.Response())
+
+ c.Response().Header().Set("HX-Redirect", "/upload")
+ return c.NoContent(http.StatusOK)
+ })
+
+ e.GET("/upload", func(c echo.Context) error {
+ sess, _ := session.Get("session", c)
+ if sess.Values["user"] != "admin" {
+ return c.Redirect(http.StatusSeeOther, "/login")
+ }
+ component := uploadPage(c.Get(middleware.DefaultCSRFConfig.ContextKey).(string))
+ err := component.Render(c.Request().Context(), c.Response().Writer)
+ if err != nil {
+ return err
+ }
+ return nil
+ })
+
+ e.POST("/upload", func(c echo.Context) error {
+ file, err := c.FormFile("file")
+ if err != nil {
+ return err
+ }
+ src, err := file.Open()
+ if err != nil {
+ return err
+ }
+ defer src.Close()
+
+ filename, err := uuid.NewRandom()
+ if err != nil {
+ return err
+ }
+
+ dst, err := os.Create(path.Join("assets", filename.String())) //RANDOMIZE
+ if err != nil {
+ return err
+ }
+ defer dst.Close()
+
+ // Copy
+ if _, err = io.Copy(dst, src); err != nil {
+ return err
+ }
+
+ description := c.FormValue("description")
+
+ post := Post{
+ Description: description,
+ ImageID: "/static/" + filename.String(),
+ }
+ db.Create(&post)
+
+ c.Response().Header().Set("HX-Redirect", "/")
+ return c.NoContent(http.StatusOK)
+ })
+
e.GET("/posts", func(c echo.Context) error {
after, err := time.Parse(time.RFC3339, c.QueryParam("after"))