Grouping route

This commit is contained in:
2024-10-02 15:33:41 +07:00
parent 5d7dc70f1b
commit 93c44f40cc
41 changed files with 1176 additions and 1158 deletions

View File

@ -7,8 +7,8 @@ import (
"errors"
"fmt"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/view/client/auth/forgotPassword"
"github.com/fossyy/filekeeper/view/client/email"
"github.com/fossyy/filekeeper/view/client/forgotPassword"
"github.com/google/uuid"
"github.com/redis/go-redis/v9"
"net/http"
@ -130,7 +130,7 @@ func verifyForgot(user *models.User) error {
}
var buffer bytes.Buffer
err = emailView.ForgotPassword(user.Username, fmt.Sprintf("https://%s/forgot-password/verify/%s", utils.Getenv("DOMAIN"), code)).Render(context.Background(), &buffer)
err = emailView.ForgotPassword(user.Username, fmt.Sprintf("https://%s/auth/forgot-password/verify/%s", utils.Getenv("DOMAIN"), code)).Render(context.Background(), &buffer)
if err != nil {
return err
}

View File

@ -4,22 +4,16 @@ import (
"encoding/json"
"errors"
"github.com/fossyy/filekeeper/app"
forgotPasswordHandler "github.com/fossyy/filekeeper/handler/forgotPassword"
"github.com/fossyy/filekeeper/handler/auth/forgotPassword"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/utils"
"github.com/fossyy/filekeeper/view/client/forgotPassword"
signupView "github.com/fossyy/filekeeper/view/client/signup"
"github.com/fossyy/filekeeper/view/client/auth/forgotPassword"
signupView "github.com/fossyy/filekeeper/view/client/auth/signup"
"github.com/redis/go-redis/v9"
"net/http"
)
func init() {
//TESTING
}
func GET(w http.ResponseWriter, r *http.Request) {
code := r.PathValue("code")

View File

@ -48,21 +48,22 @@ func GET(w http.ResponseWriter, r *http.Request) {
_, err := app.Server.Cache.GetCache(r.Context(), "CsrfTokens:"+r.URL.Query().Get("state"))
if err != nil {
if errors.Is(err, redis.Nil) {
http.Redirect(w, r, fmt.Sprintf("/signin?error=%s", "csrf_token_error"), http.StatusFound)
http.Redirect(w, r, fmt.Sprintf("/auth/signin?error=%s", "csrf_token_error"), http.StatusFound)
return
}
app.Server.Logger.Error(err.Error())
w.WriteHeader(http.StatusInternalServerError)
return
}
err = app.Server.Cache.DeleteCache(r.Context(), "CsrfTokens:"+r.URL.Query().Get("state"))
if err != nil {
http.Redirect(w, r, fmt.Sprintf("/signin?error=%s", "csrf_token_error"), http.StatusFound)
http.Redirect(w, r, fmt.Sprintf("/auth/signin?error=%s", "csrf_token_error"), http.StatusFound)
return
}
if err := r.URL.Query().Get("error"); err != "" {
http.Redirect(w, r, fmt.Sprintf("/signin?error=%s", err), http.StatusFound)
http.Redirect(w, r, fmt.Sprintf("/auth/signin?error=%s", err), http.StatusFound)
return
}

View File

@ -9,7 +9,7 @@ import (
"github.com/fossyy/filekeeper/types/models"
"github.com/fossyy/filekeeper/utils"
"github.com/fossyy/filekeeper/view/client/auth"
signupView "github.com/fossyy/filekeeper/view/client/signup"
signupView "github.com/fossyy/filekeeper/view/client/auth/signup"
"github.com/google/uuid"
"github.com/redis/go-redis/v9"
"net/http"
@ -27,7 +27,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
_, err := app.Server.Cache.GetCache(r.Context(), "GoogleSetup:"+code)
if err != nil {
if errors.Is(err, redis.Nil) {
http.Redirect(w, r, "/signup", http.StatusSeeOther)
http.Redirect(w, r, "/auth/signup", http.StatusSeeOther)
return
}
w.WriteHeader(http.StatusInternalServerError)

View File

@ -7,7 +7,7 @@ import (
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/utils"
"github.com/fossyy/filekeeper/view/client/signin"
"github.com/fossyy/filekeeper/view/client/auth/signin"
"net/http"
)

View File

@ -8,8 +8,8 @@ import (
"fmt"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/utils"
signupView "github.com/fossyy/filekeeper/view/client/auth/signup"
"github.com/fossyy/filekeeper/view/client/email"
signupView "github.com/fossyy/filekeeper/view/client/signup"
"github.com/redis/go-redis/v9"
"net/http"
"time"
@ -117,7 +117,7 @@ func verifyEmail(user *models.User) error {
code = storedCode
}
err = emailView.RegistrationEmail(user.Username, fmt.Sprintf("https://%s/signup/verify/%s", utils.Getenv("DOMAIN"), code)).Render(context.Background(), &buffer)
err = emailView.RegistrationEmail(user.Username, fmt.Sprintf("https://%s/auth/signup/verify/%s", utils.Getenv("DOMAIN"), code)).Render(context.Background(), &buffer)
if err != nil {
return err
}

View File

@ -5,8 +5,8 @@ import (
"encoding/json"
"errors"
"github.com/fossyy/filekeeper/app"
signupHandler "github.com/fossyy/filekeeper/handler/signup"
signupView "github.com/fossyy/filekeeper/view/client/signup"
"github.com/fossyy/filekeeper/handler/auth/signup"
signupView "github.com/fossyy/filekeeper/view/client/auth/signup"
"github.com/redis/go-redis/v9"
"net/http"

View File

@ -39,6 +39,6 @@ func GET(w http.ResponseWriter, r *http.Request) {
MaxAge: -1,
})
http.Redirect(w, r, "/signin", http.StatusSeeOther)
http.Redirect(w, r, "/auth/signin", http.StatusSeeOther)
return
}

View File

@ -58,6 +58,6 @@ func POST(w http.ResponseWriter, r *http.Request) {
return
}
http.Redirect(w, r, "/signin", http.StatusSeeOther)
http.Redirect(w, r, "/auth/signin", http.StatusSeeOther)
return
}

View File

@ -1,67 +1,22 @@
package userHandler
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/a-h/templ"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/types/models"
"github.com/fossyy/filekeeper/utils"
"github.com/fossyy/filekeeper/view/client/user"
"github.com/google/uuid"
"github.com/gorilla/websocket"
"gorm.io/gorm"
"net/http"
"strings"
)
var errorMessages = map[string]string{
"password_not_match": "The passwords provided do not match. Please try again.",
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
type ActionType string
const (
UploadNewFile ActionType = "UploadNewFile"
DeleteFile ActionType = "DeleteFile"
Ping ActionType = "Ping"
)
type WebsocketAction struct {
Action ActionType `json:"action"`
}
type ActionUploadNewFile struct {
Action string `json:"action"`
Name string `json:"name"`
Size uint64 `json:"size"`
Chunk uint64 `json:"chunk"`
StartHash string `json:"startHash"`
EndHash string `json:"endHash"`
RequestID string `json:"requestID"`
}
func GET(w http.ResponseWriter, r *http.Request) {
userSession := r.Context().Value("user").(types.User)
if r.Header.Get("upgrade") == "websocket" {
upgrade, err := upgrader.Upgrade(w, r, nil)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
handlerWS(upgrade, userSession)
}
sessions, err := session.GetSessions(userSession.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
@ -126,168 +81,3 @@ func GET(w http.ResponseWriter, r *http.Request) {
return
}
}
func handlerWS(conn *websocket.Conn, userSession types.User) {
defer conn.Close()
var err error
var message []byte
for {
_, message, err = conn.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
app.Server.Logger.Error("Unexpected connection closure:", err)
} else {
app.Server.Logger.Error("Connection closed:", err)
}
return
}
var action WebsocketAction
err = json.Unmarshal(message, &action)
if err != nil {
app.Server.Logger.Error("Error unmarshalling WebsocketAction:", err)
sendErrorResponse(conn, action.Action, "Internal Server Error")
continue
}
switch action.Action {
case UploadNewFile:
var uploadNewFile ActionUploadNewFile
err = json.Unmarshal(message, &uploadNewFile)
if err != nil {
app.Server.Logger.Error("Error unmarshalling ActionUploadNewFile:", err)
sendErrorResponse(conn, action.Action, "Internal Server Error")
continue
}
var file *models.File
file, err = app.Server.Database.GetUserFile(uploadNewFile.Name, userSession.UserID.String())
allowedFileTypes := []string{"jpg", "jpeg", "png", "gif", "bmp", "tiff", "pdf", "doc", "docx", "txt", "odt", "xls", "xlsx", "ppt", "pptx", "zip", "rar", "tar", "gz", "7z", "bz2", "exe", "bin", "sh", "bat", "cmd", "msi", "apk"}
isAllowedFileType := func(fileType string) bool {
for _, allowed := range allowedFileTypes {
if fileType == allowed {
return true
}
}
return false
}
fileName := strings.Split(uploadNewFile.Name, ".")
fileType := fileName[len(fileName)-1]
if !isAllowedFileType(fileType) {
fileType = "doc"
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
fileID := uuid.New()
newFile := models.File{
ID: fileID,
OwnerID: userSession.UserID,
Name: uploadNewFile.Name,
Size: uploadNewFile.Size,
StartHash: uploadNewFile.StartHash,
EndHash: uploadNewFile.EndHash,
Type: fileType,
TotalChunk: uploadNewFile.Chunk,
Downloaded: 0,
}
err := app.Server.Database.CreateFile(&newFile)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Error Creating File")
continue
}
err = app.Server.Service.RemoveUserFilesCache(context.Background(), userSession.UserID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Error Creating File")
return
}
userFile, err := app.Server.Service.GetFileDetail(context.Background(), fileID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
sendSuccessResponseWithID(conn, action.Action, userFile, uploadNewFile.RequestID)
continue
} else {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
}
if uploadNewFile.StartHash != file.StartHash || uploadNewFile.EndHash != file.EndHash {
sendErrorResponse(conn, action.Action, "File Is Different")
continue
}
userFile, err := app.Server.Service.GetFileDetail(context.Background(), file.ID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
sendSuccessResponseWithID(conn, action.Action, userFile, uploadNewFile.RequestID)
continue
case Ping:
sendSuccessResponse(conn, action.Action, map[string]string{"message": "received"})
continue
}
}
}
func sendErrorResponse(conn *websocket.Conn, action ActionType, message string) {
response := map[string]interface{}{
"action": action,
"status": "error",
"message": message,
}
marshal, err := json.Marshal(response)
if err != nil {
app.Server.Logger.Error("Error marshalling error response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing error response:", err)
}
}
func sendSuccessResponse(conn *websocket.Conn, action ActionType, response interface{}) {
responseJSON := map[string]interface{}{
"action": action,
"status": "success",
"response": response,
}
marshal, err := json.Marshal(responseJSON)
if err != nil {
app.Server.Logger.Error("Error marshalling success response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing success response:", err)
}
}
func sendSuccessResponseWithID(conn *websocket.Conn, action ActionType, response interface{}, responseID string) {
responseJSON := map[string]interface{}{
"action": action,
"status": "success",
"response": response,
"responseID": responseID,
}
marshal, err := json.Marshal(responseJSON)
if err != nil {
app.Server.Logger.Error("Error marshalling success response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing success response:", err)
}
}

View File

@ -0,0 +1,221 @@
package websocketHandler
import (
"context"
"encoding/json"
"errors"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/types/models"
"github.com/google/uuid"
"github.com/gorilla/websocket"
"gorm.io/gorm"
"net/http"
"strings"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
type ActionUploadNewFile struct {
Action string `json:"action"`
Name string `json:"name"`
Size uint64 `json:"size"`
Chunk uint64 `json:"chunk"`
StartHash string `json:"startHash"`
EndHash string `json:"endHash"`
RequestID string `json:"requestID"`
}
type ActionType string
type WebsocketAction struct {
Action ActionType `json:"action"`
}
const (
UploadNewFile ActionType = "UploadNewFile"
DeleteFile ActionType = "DeleteFile"
Ping ActionType = "Ping"
)
func GET(w http.ResponseWriter, r *http.Request) {
userSession := r.Context().Value("user").(types.User)
if r.Header.Get("upgrade") == "websocket" {
upgrade, err := upgrader.Upgrade(w, r, nil)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
handlerWS(upgrade, userSession)
}
}
func handlerWS(conn *websocket.Conn, userSession types.User) {
defer conn.Close()
var err error
var message []byte
for {
_, message, err = conn.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
app.Server.Logger.Error("Unexpected connection closure:", err)
} else {
app.Server.Logger.Error("Connection closed:", err)
}
return
}
var action WebsocketAction
err = json.Unmarshal(message, &action)
if err != nil {
app.Server.Logger.Error("Error unmarshalling WebsocketAction:", err)
sendErrorResponse(conn, action.Action, "Internal Server Error")
continue
}
switch action.Action {
case UploadNewFile:
var uploadNewFile ActionUploadNewFile
err = json.Unmarshal(message, &uploadNewFile)
if err != nil {
app.Server.Logger.Error("Error unmarshalling ActionUploadNewFile:", err)
sendErrorResponse(conn, action.Action, "Internal Server Error")
continue
}
var file *models.File
file, err = app.Server.Database.GetUserFile(uploadNewFile.Name, userSession.UserID.String())
allowedFileTypes := []string{"jpg", "jpeg", "png", "gif", "bmp", "tiff", "pdf", "doc", "docx", "txt", "odt", "xls", "xlsx", "ppt", "pptx", "zip", "rar", "tar", "gz", "7z", "bz2", "exe", "bin", "sh", "bat", "cmd", "msi", "apk"}
isAllowedFileType := func(fileType string) bool {
for _, allowed := range allowedFileTypes {
if fileType == allowed {
return true
}
}
return false
}
fileName := strings.Split(uploadNewFile.Name, ".")
fileType := fileName[len(fileName)-1]
if !isAllowedFileType(fileType) {
fileType = "doc"
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
fileID := uuid.New()
newFile := models.File{
ID: fileID,
OwnerID: userSession.UserID,
Name: uploadNewFile.Name,
Size: uploadNewFile.Size,
StartHash: uploadNewFile.StartHash,
EndHash: uploadNewFile.EndHash,
Type: fileType,
TotalChunk: uploadNewFile.Chunk,
Downloaded: 0,
}
err := app.Server.Database.CreateFile(&newFile)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Error Creating File")
continue
}
err = app.Server.Service.RemoveUserFilesCache(context.Background(), userSession.UserID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Error Creating File")
return
}
userFile, err := app.Server.Service.GetFileDetail(context.Background(), fileID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
sendSuccessResponseWithID(conn, action.Action, userFile, uploadNewFile.RequestID)
continue
} else {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
}
if uploadNewFile.StartHash != file.StartHash || uploadNewFile.EndHash != file.EndHash {
sendErrorResponse(conn, action.Action, "File Is Different")
continue
}
userFile, err := app.Server.Service.GetFileDetail(context.Background(), file.ID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
sendSuccessResponseWithID(conn, action.Action, userFile, uploadNewFile.RequestID)
continue
case Ping:
sendSuccessResponse(conn, action.Action, map[string]string{"message": "received"})
continue
}
}
}
func sendErrorResponse(conn *websocket.Conn, action ActionType, message string) {
response := map[string]interface{}{
"action": action,
"status": "error",
"message": message,
}
marshal, err := json.Marshal(response)
if err != nil {
app.Server.Logger.Error("Error marshalling error response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing error response:", err)
}
}
func sendSuccessResponse(conn *websocket.Conn, action ActionType, response interface{}) {
responseJSON := map[string]interface{}{
"action": action,
"status": "success",
"response": response,
}
marshal, err := json.Marshal(responseJSON)
if err != nil {
app.Server.Logger.Error("Error marshalling success response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing success response:", err)
}
}
func sendSuccessResponseWithID(conn *websocket.Conn, action ActionType, response interface{}, responseID string) {
responseJSON := map[string]interface{}{
"action": action,
"status": "success",
"response": response,
"responseID": responseID,
}
marshal, err := json.Marshal(responseJSON)
if err != nil {
app.Server.Logger.Error("Error marshalling success response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing success response:", err)
}
}