diff --git a/.air.toml b/.air.toml
index 3651e65..4c9eee1 100644
--- a/.air.toml
+++ b/.air.toml
@@ -4,7 +4,7 @@ tmp_dir = "tmp"
[build]
args_bin = []
- bin = "tmp\\main.exe"
+ bin = "tmp\\main.exe --log true"
cmd = "go build -o ./tmp/main.exe ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata", "uploads"]
diff --git a/app/app.go b/app/app.go
index 7be9975..bc1a906 100644
--- a/app/app.go
+++ b/app/app.go
@@ -8,22 +8,36 @@ import (
)
var Server App
+var Admin App
type App struct {
http.Server
- DB *db.Database
- Logger *logger.AggregatedLogger
- Mail *email.SmtpServer
+ Database db.Database
+ Logger *logger.AggregatedLogger
+ Mail *email.SmtpServer
}
-func NewServer(addr string, handler http.Handler, logger logger.AggregatedLogger, database db.Database, mail email.SmtpServer) App {
+func NewClientServer(addr string, handler http.Handler, logger logger.AggregatedLogger, database db.Database, mail email.SmtpServer) App {
return App{
Server: http.Server{
Addr: addr,
Handler: handler,
},
- Logger: &logger,
- DB: &database,
- Mail: &mail,
+ Logger: &logger,
+ Database: database,
+ Mail: &mail,
+ }
+}
+
+func NewAdminServer(addr string, handler http.Handler, database db.Database) App {
+ return App{
+ Server: http.Server{
+ Addr: addr,
+ Handler: handler,
+ },
+ // TODO: Remove the dummy struct
+ Logger: &logger.AggregatedLogger{},
+ Database: database,
+ Mail: &email.SmtpServer{},
}
}
diff --git a/cache/cache.go b/cache/cache.go
index b769c3d..cc4dee5 100644
--- a/cache/cache.go
+++ b/cache/cache.go
@@ -3,7 +3,6 @@ package cache
import (
"fmt"
"github.com/fossyy/filekeeper/app"
- "github.com/fossyy/filekeeper/db"
"github.com/fossyy/filekeeper/utils"
"github.com/google/uuid"
"sync"
@@ -74,8 +73,8 @@ func init() {
for _, file := range fileCache {
file.mu.Lock()
if currentTime.Sub(file.AccessAt) > time.Minute*1 {
- db.DB.UpdateUploadedByte(file.UploadedByte, file.ID.String())
- db.DB.UpdateUploadedChunk(file.UploadedChunk, file.ID.String())
+ app.Server.Database.UpdateUploadedByte(file.UploadedByte, file.ID.String())
+ app.Server.Database.UpdateUploadedChunk(file.UploadedChunk, file.ID.String())
delete(fileCache, file.ID.String())
cacheClean++
}
@@ -92,7 +91,7 @@ func GetUser(email string) (*UserWithExpired, error) {
return user, nil
}
- userData, err := db.DB.GetUser(email)
+ userData, err := app.Server.Database.GetUser(email)
if err != nil {
return nil, err
}
@@ -122,7 +121,7 @@ func GetFile(id string) (*FileWithExpired, error) {
return file, nil
}
- uploadData, err := db.DB.GetFile(id)
+ uploadData, err := app.Server.Database.GetFile(id)
if err != nil {
return nil, err
}
@@ -149,7 +148,7 @@ func (file *FileWithExpired) UpdateProgress(index int64, size int64) {
}
func GetUserFile(name, ownerID string) (*FileWithExpired, error) {
- fileData, err := db.DB.GetUserFile(name, ownerID)
+ fileData, err := app.Server.Database.GetUserFile(name, ownerID)
if err != nil {
return nil, err
}
@@ -163,9 +162,9 @@ func GetUserFile(name, ownerID string) (*FileWithExpired, error) {
}
func (file *FileWithExpired) FinalizeFileUpload() {
- db.DB.UpdateUploadedByte(file.UploadedByte, file.ID.String())
- db.DB.UpdateUploadedChunk(file.UploadedChunk, file.ID.String())
- db.DB.FinalizeFileUpload(file.ID.String())
+ app.Server.Database.UpdateUploadedByte(file.UploadedByte, file.ID.String())
+ app.Server.Database.UpdateUploadedChunk(file.UploadedChunk, file.ID.String())
+ app.Server.Database.FinalizeFileUpload(file.ID.String())
delete(fileCache, file.ID.String())
return
}
diff --git a/db/database.go b/db/database.go
index 668b017..e01b291 100644
--- a/db/database.go
+++ b/db/database.go
@@ -12,8 +12,6 @@ import (
"strings"
)
-var DB Database
-
type mySQLdb struct {
*gorm.DB
}
@@ -35,6 +33,7 @@ type Database interface {
CreateUser(user *models.User) error
GetUser(email string) (*models.User, error)
+ GetAllUsers() ([]models.User, error)
UpdateUserPassword(email string, password string) error
CreateFile(file *models.File) error
@@ -197,6 +196,15 @@ func (db *mySQLdb) GetUser(email string) (*models.User, error) {
return &user, nil
}
+func (db *mySQLdb) GetAllUsers() ([]models.User, error) {
+ var users []models.User
+ err := db.DB.Table("users").Select("user_id, Username, Email").Find(&users).Error
+ if err != nil {
+ return nil, err
+ }
+ return users, nil
+}
+
func (db *mySQLdb) UpdateUserPassword(email string, password string) error {
var user models.User
err := db.DB.Table("users").Where("email = ?", email).First(&user).Error
@@ -320,6 +328,16 @@ func (db *postgresDB) GetUser(email string) (*models.User, error) {
return &user, nil
}
+func (db *postgresDB) GetAllUsers() ([]models.User, error) {
+ var users []models.User
+ err := db.DB.Table("users").Select("user_id, username, email").Find(&users).Error
+ if err != nil {
+ fmt.Println(err)
+ return nil, err
+ }
+ return users, nil
+}
+
func (db *postgresDB) UpdateUserPassword(email string, password string) error {
var user models.User
err := db.DB.Table("users").Where("email = $1", email).First(&user).Error
diff --git a/handler/auth/google/callback/callback.go b/handler/auth/google/callback/callback.go
index 0ca0b98..c112c46 100644
--- a/handler/auth/google/callback/callback.go
+++ b/handler/auth/google/callback/callback.go
@@ -7,7 +7,6 @@ import (
"fmt"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/cache"
- "github.com/fossyy/filekeeper/db"
googleOauthSetupHandler "github.com/fossyy/filekeeper/handler/auth/google/setup"
signinHandler "github.com/fossyy/filekeeper/handler/signin"
"github.com/fossyy/filekeeper/session"
@@ -145,7 +144,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
return
}
- if !db.DB.IsEmailRegistered(oauthUser.Email) {
+ if !app.Server.Database.IsEmailRegistered(oauthUser.Email) {
code := utils.GenerateRandomString(64)
googleOauthSetupHandler.SetupUser[code] = &googleOauthSetupHandler.UnregisteredUser{
Code: code,
diff --git a/handler/auth/google/setup/setup.go b/handler/auth/google/setup/setup.go
index 0324a61..17823f6 100644
--- a/handler/auth/google/setup/setup.go
+++ b/handler/auth/google/setup/setup.go
@@ -3,7 +3,6 @@ package googleOauthSetupHandler
import (
"fmt"
"github.com/fossyy/filekeeper/app"
- "github.com/fossyy/filekeeper/db"
signinHandler "github.com/fossyy/filekeeper/handler/signin"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
@@ -112,7 +111,7 @@ func POST(w http.ResponseWriter, r *http.Request) {
Password: hashedPassword,
}
- err = db.DB.CreateUser(&newUser)
+ err = app.Server.Database.CreateUser(&newUser)
if err != nil {
component := signupView.Main("Filekeeper - Sign up Page", types.Message{
Code: 0,
diff --git a/handler/download/download.go b/handler/download/download.go
index 61209ec..277bf1e 100644
--- a/handler/download/download.go
+++ b/handler/download/download.go
@@ -5,14 +5,13 @@ import (
"github.com/fossyy/filekeeper/view/client/download"
"net/http"
- "github.com/fossyy/filekeeper/db"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/utils"
)
func GET(w http.ResponseWriter, r *http.Request) {
userSession := r.Context().Value("user").(types.User)
- files, err := db.DB.GetFiles(userSession.UserID.String())
+ files, err := app.Server.Database.GetFiles(userSession.UserID.String())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
diff --git a/handler/download/file/file.go b/handler/download/file/file.go
index 71f0ad3..e80c883 100644
--- a/handler/download/file/file.go
+++ b/handler/download/file/file.go
@@ -5,13 +5,11 @@ import (
"net/http"
"os"
"path/filepath"
-
- "github.com/fossyy/filekeeper/db"
)
func GET(w http.ResponseWriter, r *http.Request) {
fileID := r.PathValue("id")
- file, err := db.DB.GetFile(fileID)
+ file, err := app.Server.Database.GetFile(fileID)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
diff --git a/handler/forgotPassword/verify/verify.go b/handler/forgotPassword/verify/verify.go
index 72b91a3..8deda5e 100644
--- a/handler/forgotPassword/verify/verify.go
+++ b/handler/forgotPassword/verify/verify.go
@@ -3,7 +3,6 @@ package forgotPasswordVerifyHandler
import (
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/cache"
- "github.com/fossyy/filekeeper/db"
forgotPasswordHandler "github.com/fossyy/filekeeper/handler/forgotPassword"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
@@ -83,7 +82,7 @@ func POST(w http.ResponseWriter, r *http.Request) {
return
}
- err = db.DB.UpdateUserPassword(data.User.Email, hashedPassword)
+ err = app.Server.Database.UpdateUserPassword(data.User.Email, hashedPassword)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
diff --git a/handler/signup/signup.go b/handler/signup/signup.go
index a62cc65..86d43ba 100644
--- a/handler/signup/signup.go
+++ b/handler/signup/signup.go
@@ -11,7 +11,6 @@ import (
"sync"
"time"
- "github.com/fossyy/filekeeper/db"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/types/models"
"github.com/fossyy/filekeeper/utils"
@@ -102,7 +101,7 @@ func POST(w http.ResponseWriter, r *http.Request) {
Password: hashedPassword,
}
- if registered := db.DB.IsUserRegistered(userEmail, username); registered {
+ if registered := app.Server.Database.IsUserRegistered(userEmail, username); registered {
component := signupView.Main("Filekeeper - Sign up Page", types.Message{
Code: 0,
Message: "Email or Username has been registered",
diff --git a/handler/signup/verify/verify.go b/handler/signup/verify/verify.go
index cfef3b5..5c66d0c 100644
--- a/handler/signup/verify/verify.go
+++ b/handler/signup/verify/verify.go
@@ -5,7 +5,6 @@ import (
signupView "github.com/fossyy/filekeeper/view/client/signup"
"net/http"
- "github.com/fossyy/filekeeper/db"
signupHandler "github.com/fossyy/filekeeper/handler/signup"
"github.com/fossyy/filekeeper/types"
)
@@ -19,7 +18,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
return
}
- err := db.DB.CreateUser(data.User)
+ err := app.Server.Database.CreateUser(data.User)
if err != nil {
component := signupView.Main("Filekeeper - Sign up Page", types.Message{
Code: 0,
diff --git a/handler/upload/initialisation/initialisation.go b/handler/upload/initialisation/initialisation.go
index 444d079..9c9158f 100644
--- a/handler/upload/initialisation/initialisation.go
+++ b/handler/upload/initialisation/initialisation.go
@@ -10,7 +10,6 @@ import (
"os"
"path/filepath"
- "github.com/fossyy/filekeeper/db"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/types/models"
"github.com/google/uuid"
@@ -93,7 +92,7 @@ func handleNewUpload(user types.User, file types.FileInfo) (models.File, error)
Done: false,
}
- err = db.DB.CreateFile(&newFile)
+ err = app.Server.Database.CreateFile(&newFile)
if err != nil {
app.Server.Logger.Error(err.Error())
return models.File{}, err
diff --git a/handler/user/ResetPassword/ResetPassword.go b/handler/user/ResetPassword/ResetPassword.go
index 26776c6..0f0f934 100644
--- a/handler/user/ResetPassword/ResetPassword.go
+++ b/handler/user/ResetPassword/ResetPassword.go
@@ -1,8 +1,8 @@
package userHandlerResetPassword
import (
+ "github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/cache"
- "github.com/fossyy/filekeeper/db"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/utils"
@@ -31,7 +31,7 @@ func POST(w http.ResponseWriter, r *http.Request) {
return
}
- err = db.DB.UpdateUserPassword(user.Email, hashPassword)
+ err = app.Server.Database.UpdateUserPassword(user.Email, hashPassword)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
diff --git a/handler/user/totp/setup.go b/handler/user/totp/setup.go
index 90fb057..600e917 100644
--- a/handler/user/totp/setup.go
+++ b/handler/user/totp/setup.go
@@ -4,13 +4,13 @@ import (
"bytes"
"encoding/base64"
"fmt"
+ "github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/cache"
"github.com/fossyy/filekeeper/view/client/user/totp"
"image/png"
"net/http"
"time"
- "github.com/fossyy/filekeeper/db"
"github.com/fossyy/filekeeper/types"
"github.com/skip2/go-qrcode"
"github.com/xlzd/gotp"
@@ -71,7 +71,7 @@ func POST(w http.ResponseWriter, r *http.Request) {
return
}
if totp.Verify(code, time.Now().Unix()) {
- if err := db.DB.InitializeTotp(userSession.Email, secret); err != nil {
+ if err := app.Server.Database.InitializeTotp(userSession.Email, secret); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
diff --git a/logger/logger.go b/logger/logger.go
index eb3aab1..27689bb 100644
--- a/logger/logger.go
+++ b/logger/logger.go
@@ -1,6 +1,7 @@
package logger
import (
+ "flag"
"fmt"
"io"
"log"
@@ -8,6 +9,9 @@ import (
"time"
)
+var logFlag *bool
+var infoLoggerWriter io.Writer
+
type AggregatedLogger struct {
infoLogger *log.Logger
warnLogger *log.Logger
@@ -16,6 +20,9 @@ type AggregatedLogger struct {
}
func init() {
+ logFlag = flag.Bool("log", false, "Enable logging")
+ flag.Parse()
+
if _, err := os.Stat("log"); os.IsNotExist(err) {
os.Mkdir("log", os.ModePerm)
}
@@ -25,15 +32,23 @@ func Logger() *AggregatedLogger {
currentTime := time.Now()
formattedTime := currentTime.Format("2006-01-02-15-04")
file, err := os.OpenFile(fmt.Sprintf("log/log-%s.log", formattedTime), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+ multiLogger := io.MultiWriter(os.Stdout, file)
+
if err != nil {
return &AggregatedLogger{}
}
- flag := log.Ldate | log.Ltime
- multiLogger := io.MultiWriter(os.Stdout, file)
- infoLogger := log.New(file, "INFO: ", flag)
- warnLogger := log.New(multiLogger, "WARN: ", flag)
- errorLogger := log.New(multiLogger, "ERROR: ", flag)
- panicLogger := log.New(multiLogger, "PANIC: ", flag)
+
+ if *logFlag {
+ infoLoggerWriter = multiLogger
+ } else {
+ infoLoggerWriter = file
+ }
+
+ slug := log.Ldate | log.Ltime
+ infoLogger := log.New(infoLoggerWriter, "INFO: ", slug)
+ warnLogger := log.New(multiLogger, "WARN: ", slug)
+ errorLogger := log.New(multiLogger, "ERROR: ", slug)
+ panicLogger := log.New(multiLogger, "PANIC: ", slug)
return &AggregatedLogger{
infoLogger: infoLogger,
diff --git a/main.go b/main.go
index c0e3e3d..9f5eb97 100644
--- a/main.go
+++ b/main.go
@@ -7,13 +7,15 @@ import (
"github.com/fossyy/filekeeper/email"
"github.com/fossyy/filekeeper/logger"
"github.com/fossyy/filekeeper/middleware"
- "github.com/fossyy/filekeeper/routes"
+ "github.com/fossyy/filekeeper/routes/admin"
+ "github.com/fossyy/filekeeper/routes/client"
"github.com/fossyy/filekeeper/utils"
"strconv"
)
func main() {
- serverAddr := fmt.Sprintf("%s:%s", utils.Getenv("SERVER_HOST"), utils.Getenv("SERVER_PORT"))
+ clientAddr := fmt.Sprintf("%s:%s", utils.Getenv("SERVER_HOST"), utils.Getenv("SERVER_PORT"))
+ adminAddr := fmt.Sprintf("%s:%s", utils.Getenv("SERVER_HOST"), "27000")
dbUser := utils.Getenv("DB_USERNAME")
dbPass := utils.Getenv("DB_PASSWORD")
@@ -22,13 +24,23 @@ func main() {
dbName := utils.Getenv("DB_NAME")
database := db.NewPostgresDB(dbUser, dbPass, dbHost, dbPort, dbName, db.DisableSSL)
- db.DB = database
smtpPort, _ := strconv.Atoi(utils.Getenv("SMTP_PORT"))
mailServer := email.NewSmtpServer(utils.Getenv("SMTP_HOST"), smtpPort, utils.Getenv("SMTP_USER"), utils.Getenv("SMTP_PASSWORD"))
- app.Server = app.NewServer(serverAddr, middleware.Handler(routes.SetupRoutes()), *logger.Logger(), database, mailServer)
- fmt.Printf("Listening on http://%s\n", app.Server.Addr)
+ app.Server = app.NewClientServer(clientAddr, middleware.Handler(client.SetupRoutes()), *logger.Logger(), database, mailServer)
+ app.Admin = app.NewAdminServer(adminAddr, middleware.Handler(admin.SetupRoutes()), database)
+
+ go func() {
+ fmt.Printf("Admin Web App Listening on http://%s\n", app.Admin.Addr)
+ err := app.Admin.ListenAndServe()
+ if err != nil {
+ panic(err)
+ return
+ }
+ }()
+
+ fmt.Printf("Client Web App Listening on http://%s\n", app.Server.Addr)
err := app.Server.ListenAndServe()
if err != nil {
panic(err)
diff --git a/routes/admin/routes.go b/routes/admin/routes.go
new file mode 100644
index 0000000..ddda602
--- /dev/null
+++ b/routes/admin/routes.go
@@ -0,0 +1,44 @@
+package admin
+
+import (
+ "github.com/fossyy/filekeeper/app"
+ adminIndex "github.com/fossyy/filekeeper/view/admin/index"
+ "net/http"
+ "os"
+ "path/filepath"
+)
+
+func SetupRoutes() *http.ServeMux {
+ handler := http.NewServeMux()
+ handler.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ //users, err := app.Admin.Database.GetAllUsers()
+ //if err != nil {
+ // http.Error(w, "Unable to retrieve users", http.StatusInternalServerError)
+ // return
+ //}
+ //w.Header().Set("Content-Type", "application/json")
+ //if err := json.NewEncoder(w).Encode(users); err != nil {
+ // http.Error(w, "Failed to encode response", http.StatusInternalServerError)
+ // return
+ //}
+ adminIndex.Main().Render(r.Context(), w)
+ return
+ })
+ handler.HandleFunc("/public/output.css", func(w http.ResponseWriter, r *http.Request) {
+ openFile, err := os.OpenFile(filepath.Join("public", "output.css"), os.O_RDONLY, 0)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ app.Server.Logger.Error(err.Error())
+ return
+ }
+ defer openFile.Close()
+ stat, err := openFile.Stat()
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ app.Server.Logger.Error(err.Error())
+ return
+ }
+ http.ServeContent(w, r, openFile.Name(), stat.ModTime(), openFile)
+ })
+ return handler
+}
diff --git a/routes/routes.go b/routes/client/routes.go
similarity index 99%
rename from routes/routes.go
rename to routes/client/routes.go
index 890c668..621911f 100644
--- a/routes/routes.go
+++ b/routes/client/routes.go
@@ -1,4 +1,4 @@
-package routes
+package client
import (
googleOauthHandler "github.com/fossyy/filekeeper/handler/auth/google"
diff --git a/staging.bat b/staging.bat
index cdbcc43..4e60c1f 100644
--- a/staging.bat
+++ b/staging.bat
@@ -7,4 +7,4 @@ REM Watch for changes in Tailwind CSS
start "" npx tailwindcss -i ./public/input.css -o ./public/output.css --watch
REM Watch for changes in templates and proxy to Go server
-start "" cmd /k "templ generate -watch -proxy=http://localhost:8000"
\ No newline at end of file
+start "" cmd /k "templ generate -watch"
\ No newline at end of file
diff --git a/view/admin/index/index.templ b/view/admin/index/index.templ
new file mode 100644
index 0000000..5cc2d96
--- /dev/null
+++ b/view/admin/index/index.templ
@@ -0,0 +1,429 @@
+package adminIndex
+
+import "github.com/fossyy/filekeeper/view/admin/layout"
+
+templ Main() {
+ @layout.Base() {
+
+
+
+
+
+
System Usage
+
Real-time metrics for your server.
+
+
+
+
+
+
75%
+
CPU Usage
+
+
+
+
8GB
+
Memory Usage
+
+
+
+
100Mbps
+
Network Usage
+
+
+
+
+
+
+
User List
+
Manage your registered users.
+
+
+
+
+
+
+
+ Name
+ |
+
+ Email
+ |
+
+ Role
+ |
+
+ Actions
+ |
+
+
+
+
+
+ John Doe
+ |
+
+ john@example.com
+ |
+
+
+ Admin
+
+ |
+ |
+
+
+
+ Jane Smith
+ |
+
+ jane@example.com
+ |
+
+
+ Editor
+
+ |
+ |
+
+
+
+ Bob Johnson
+ |
+
+ bob@example.com
+ |
+
+
+ User
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
Server Control
+
Manage your server instances.
+
+
+
+
+
+
Server 1
+
192.168.1.100
+
+
+
+
+
+
+
+
+
+
+
Server 2
+
192.168.1.101
+
+
+
+
+
+
+
+
+
+
+
Server 3
+
192.168.1.102
+
+
+
+
+
+
+
+
+
+
+
+
+
Server Environment
+
Manage your server environment variables.
+
+
+
+
+
+
NODE_ENV
+
Environment mode
+
+
+
+
+
+
+
+
+
+ }
+}
diff --git a/view/admin/layout/base.templ b/view/admin/layout/base.templ
new file mode 100644
index 0000000..2506102
--- /dev/null
+++ b/view/admin/layout/base.templ
@@ -0,0 +1,19 @@
+package layout
+
+templ Base(){
+
+
+
+
+
+
+ Admin Page
+
+
+
+
+ { children... }
+
+
+
+}
\ No newline at end of file