├── .gitignore
├── web
├── assets
│ ├── images
│ │ ├── 01.png
│ │ ├── bg.jpg
│ │ ├── favicon.ico
│ │ └── github.png
│ ├── css
│ │ ├── error.css
│ │ ├── login.css
│ │ ├── navbar.css
│ │ ├── app.css
│ │ └── post.css
│ └── js
│ │ └── index.js
└── templates
│ ├── error.html
│ ├── login.html
│ ├── register.html
│ ├── partials
│ ├── footer.html
│ ├── header.html
│ └── navbar.html
│ ├── post-form.html
│ ├── post.html
│ └── home.html
├── server
├── config
│ ├── path_config.go
│ ├── session_config.go
│ ├── db_config.go
│ └── db_setup.go.go
├── controllers
│ ├── assets_controller.go
│ ├── register_controller.go
│ ├── login_controller.go
│ ├── comment_controller.go
│ └── post_controller.go
├── utils
│ ├── strings.go
│ ├── flags.go
│ └── templates.go
├── models
│ ├── user.go
│ ├── session.go
│ ├── category.go
│ ├── comment.go
│ └── post.go
├── validators
│ ├── login_request_validator.go
│ ├── comment_request_validator.go
│ ├── react_request_validators.go
│ ├── register_validator_requests.go
│ └── post_request_validator.go
├── routes
│ └── routes.go
└── database
│ └── sql
│ ├── schema.sql
│ └── seed.sql
├── go.mod
├── go.sum
├── .dockerignore
├── commands.sh
├── dockerfile
├── cmd
└── main.go
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 | server/database/database.db
--------------------------------------------------------------------------------
/web/assets/images/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hmaach/forum/HEAD/web/assets/images/01.png
--------------------------------------------------------------------------------
/web/assets/images/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hmaach/forum/HEAD/web/assets/images/bg.jpg
--------------------------------------------------------------------------------
/web/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hmaach/forum/HEAD/web/assets/images/favicon.ico
--------------------------------------------------------------------------------
/web/assets/images/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hmaach/forum/HEAD/web/assets/images/github.png
--------------------------------------------------------------------------------
/server/config/path_config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | // Define a base path for templates
4 | var BasePath = "../"
5 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module forum
2 |
3 | go 1.22.3
4 |
5 | require (
6 | github.com/mattn/go-sqlite3 v1.14.24
7 | golang.org/x/crypto v0.29.0
8 | )
9 |
--------------------------------------------------------------------------------
/server/config/session_config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "crypto/rand"
5 | "encoding/hex"
6 | )
7 |
8 | func GenerateSessionID() (string, error) {
9 | bytes := make([]byte, 16)
10 | if _, err := rand.Read(bytes); err != nil {
11 | return "", err
12 | }
13 | return hex.EncodeToString(bytes), nil
14 | }
15 |
--------------------------------------------------------------------------------
/web/templates/error.html:
--------------------------------------------------------------------------------
1 | {{template "header.html" .}}
2 |
3 |
4 |
Log in
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
New to 01Forum? Register
13 |
14 |
15 | {{template "footer.html"}}
--------------------------------------------------------------------------------
/server/utils/strings.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import "unicode"
4 |
5 | // Helper function to check if a string is alphanumeric
6 | func IsAlphanumeric(s string) bool {
7 | for _, char := range s {
8 | if !unicode.IsLetter(char) && !unicode.IsDigit(char) {
9 | return false
10 | }
11 | }
12 | return true
13 | }
14 |
15 | // Helper function to check if a string contains at least one uppercase letter
16 | func ContainsUppercase(s string) bool {
17 | for _, char := range s {
18 | if unicode.IsUpper(char) {
19 | return true
20 | }
21 | }
22 | return false
23 | }
24 |
25 | // Helper function to check if a string contains at least one digit
26 | func ContainsDigit(s string) bool {
27 | for _, char := range s {
28 | if unicode.IsDigit(char) {
29 | return true
30 | }
31 | }
32 | return false
33 | }
34 |
--------------------------------------------------------------------------------
/server/utils/flags.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "slices"
7 |
8 | "forum/server/config"
9 | )
10 |
11 | var ValidFlags = []string{"--migrate", "--seed", "--drop"}
12 |
13 | func HandleFlags(flags []string, db *sql.DB) error {
14 | if len(flags) != 1 {
15 | return fmt.Errorf("expected a single flag, got %d", len(flags))
16 | }
17 |
18 | flag := flags[0]
19 | if !slices.Contains(ValidFlags, flag) {
20 | return fmt.Errorf("invalid flag: '%s'", flag)
21 | }
22 |
23 | switch flag {
24 | case "--migrate":
25 | return config.CreateTables(db)
26 | case "--seed":
27 | return config.CreateDemoData(db)
28 | case "--drop":
29 | return config.Drop()
30 | }
31 | return nil
32 | }
33 |
34 | func Usage() {
35 | fmt.Println(`Usage: go run main.go [option]
36 | Options:
37 | --migrate Create database tables
38 | --seed Insert demo data into the database
39 | --drop Drop all tables`)
40 | }
41 |
--------------------------------------------------------------------------------
/server/models/user.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 |
7 | "golang.org/x/crypto/bcrypt"
8 | )
9 |
10 | func GetUserInfo(db *sql.DB, username string) (int, string, error) {
11 | var user_id int
12 | var hashedPassword string
13 | err := db.QueryRow("SELECT id,password FROM users WHERE username = ?", username).Scan(&user_id, &hashedPassword)
14 | if err != nil {
15 | return 0, "", err
16 | }
17 | return user_id, hashedPassword, nil
18 | }
19 |
20 | func StoreUser(db *sql.DB, email, username, password string) (int64, error) {
21 | hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
22 | if err != nil {
23 | return -1, err
24 | }
25 |
26 | query := `INSERT INTO users (email,username,password) VALUES (?,?,?)`
27 | result, err := db.Exec(query, email, username, hashedPassword)
28 | if err != nil {
29 | return -1, fmt.Errorf("%v", err)
30 | }
31 |
32 | userID, _ := result.LastInsertId()
33 |
34 | return userID, nil
35 | }
36 |
--------------------------------------------------------------------------------
/web/templates/register.html:
--------------------------------------------------------------------------------
1 | {{template "header.html" .}}
2 |
3 |
4 |
Register
5 |
13 |
14 |
Already registered? Log in
15 |
16 |
17 | {{template "footer.html"}}
--------------------------------------------------------------------------------
/web/templates/partials/footer.html:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
24 |