From 8488643e5efe4c89ee1abe6f05a8857b8ab122d1 Mon Sep 17 00:00:00 2001 From: Samuel W Date: Sun, 25 Feb 2024 15:53:36 +0100 Subject: working thing --- assets/firstpost.png | Bin 40747 -> 0 bytes assets/otherstyle.css | 143 ------------------------------------------------- assets/style.css | 31 ++++++++++- go.mod | 7 +++ go.sum | 16 ++++++ index.templ | 66 ++++++++++++++++++++++- index_templ.go | 143 ++++++++++++++++++++++++++++++++++++++++++++----- main.go | 144 +++++++++++++++++++++++++++++++++++++++++++++++--- 8 files changed, 382 insertions(+), 168 deletions(-) delete mode 100644 assets/firstpost.png delete mode 100644 assets/otherstyle.css diff --git a/assets/firstpost.png b/assets/firstpost.png deleted file mode 100644 index 802f95d..0000000 Binary files a/assets/firstpost.png and /dev/null 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) {
@posts(ps) @@ -28,10 +28,72 @@ templ index(ps []Post) { } +templ loginPage(csrfToken string) { + + + + + + + + + + + + + + +} + +templ uploadPage(csrfToken string) { + + + + + + + + + + + +
+ + +
+ Description: + +
+ + +
+ + +} + templ posts(posts []Post) { for _, post := range posts {
- { +
+ { +

{ post.Description }

{ post.CreatedAt.Format("2006-01-02 - 15:04") }

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("
") 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("
") + 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("
") + 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("
") + 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("
\"")
\"")

") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">

") 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")) -- cgit v1.2.3