Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# Building the binary of the App
FROM golang:1.19 AS build

ARG arch=amd64
WORKDIR /go/src/tasky
COPY . .
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /go/src/tasky/tasky
RUN CGO_ENABLED=0 GOOS=linux GOARCH="$ARG" go build -o /go/src/tasky/tasky


FROM alpine:3.17.0 as release
FROM alpine:3.19.0 as release

WORKDIR /app
COPY --from=build /go/src/tasky/tasky .
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ The following environment variables are needed.
|Variable|Purpose|example|
|---|---|---|
|`MONGODB_URI`|Address to mongo server|`mongodb://servername:27017` or `mongodb://username:password@hostname:port` or `mongodb+srv://` schema|
|`POSTGRES_URI`|Address to postgres server (`DB_TYPE` must be defined)|`postgresql://servername:5432` or `postgresql://user:pass@hostname:port`|
|`SECRET_KEY`|Secret key for JWT tokens|`secret123`|
|`DB_TYPE`|Specify database type (`mongodb` or `postgres`); default is `mongodb`|`mongodb`|

Alternatively, you can create a `.env` file and load it up with the environment variables.

Expand All @@ -23,4 +25,4 @@ Run the command `go run main.go` and the project should run on `locahost:8080`

This project is licensed under the terms of the MIT license.

Original project: https://github.com/dogukanozdemir/golang-todo-mongodb
Original project: https://github.com/dogukanozdemir/golang-todo-mongodb
94 changes: 29 additions & 65 deletions controllers/todoController.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,18 @@ import (
"net/http"
"time"

"github.com/gin-gonic/gin"
"github.com/jeffthorne/tasky/auth"
"github.com/jeffthorne/tasky/database"
"github.com/jeffthorne/tasky/models"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)

var todoCollection *mongo.Collection = database.OpenCollection(database.Client, "todos")

func GetTodo(c *gin.Context) {
func GetTodo(c *gin.Context, db database.DBClient) {
var ctx, cancel = context.WithTimeout(context.Background(), 100*time.Second)

id := c.Param("id")
objId, _ := primitive.ObjectIDFromHex(id)

var todo models.Todo
err := todoCollection.FindOne(ctx, bson.M{"_id": objId}).Decode(&todo)
todo, err := db.GetTodo(ctx, id)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error ": err.Error()})
}
Expand All @@ -33,111 +26,83 @@ func GetTodo(c *gin.Context) {
c.JSON(http.StatusOK, todo)
}

func ClearAll(c *gin.Context) {
func ClearAll(c *gin.Context, db database.DBClient) {
session := auth.ValidateSession(c)
if !session{
if !session {
return
}

var ctx, cancel = context.WithTimeout(context.Background(), 100*time.Second)
userid := c.Param("userid")
_, err := todoCollection.DeleteMany(ctx, bson.M{"userid": userid})
}

var ctx, cancel = context.WithTimeout(context.Background(), 100*time.Second)
defer cancel()
err := db.ClearTodos(ctx, c.Param("userid"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

defer cancel()
c.JSON(http.StatusOK, gin.H{"success": "All todos deleted."})

}

func GetTodos(c *gin.Context) {
func GetTodos(c *gin.Context, db database.DBClient) {
session := auth.ValidateSession(c)
if !session{
if !session {
return
}
}
var ctx, cancel = context.WithTimeout(context.Background(), 100*time.Second)
userid := c.Param("userid")
findResult, err := todoCollection.Find(ctx, bson.M{"userid": userid})
defer cancel()
todos, err := db.GetTodos(ctx, c.Param("userid"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"FindError": err.Error()})
return
}

var todos []models.Todo
for findResult.Next(ctx) {
var todo models.Todo
err := findResult.Decode(&todo)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"Decode Error": err.Error()})
return
}
todos = append(todos, todo)
}
defer cancel()

c.JSON(http.StatusOK, todos)
}

func DeleteTodo(c *gin.Context) {
func DeleteTodo(c *gin.Context, db database.DBClient) {
session := auth.ValidateSession(c)
if !session{
if !session {
return
}
}
var ctx, cancel = context.WithTimeout(context.Background(), 100*time.Second)

id := c.Param("id")
userid := c.Param("userid")
objId, _ := primitive.ObjectIDFromHex(id)
deleteResult, err := todoCollection.DeleteOne(ctx, bson.M{"_id": objId, "userid": userid})
defer cancel()
msg, err := db.DeleteTodo(ctx, c.Param("id"), c.Param("userid"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if deleteResult.DeletedCount == 0 {
msg := fmt.Sprintf("No todo with id : %v was found, no deletion occurred.", id)
c.JSON(http.StatusBadRequest, gin.H{"error": msg})
return
}
defer cancel()

msg := fmt.Sprintf("todo with id : %v was deleted successfully.", id)
c.JSON(http.StatusOK, gin.H{"success": msg})

}

func UpdateTodo(c *gin.Context) {
func UpdateTodo(c *gin.Context, db database.DBClient) {
session := auth.ValidateSession(c)
if !session{
if !session {
return
}
}
var ctx, cancel = context.WithTimeout(context.Background(), 100*time.Second)
defer cancel()
var newTodo models.Todo
if err := c.BindJSON(&newTodo); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

_, err := todoCollection.UpdateOne(ctx, bson.M{"_id": newTodo.ID, "userid" : newTodo.UserID}, bson.M{"$set": newTodo})
if err != nil {
if err := db.UpdateTodo(ctx, &newTodo); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
fmt.Println(err.Error())
return
}

defer cancel()

c.JSON(http.StatusOK, newTodo)
}

func AddTodo(c *gin.Context) {
func AddTodo(c *gin.Context, db database.DBClient) {
session := auth.ValidateSession(c)
if !session{
if !session {
return
}
}
var ctx, cancel = context.WithTimeout(context.Background(), 100*time.Second)
defer cancel()

var todo models.Todo
if err := c.BindJSON(&todo); err != nil {
Expand All @@ -148,11 +113,10 @@ func AddTodo(c *gin.Context) {
todo.ID = primitive.NewObjectID()
todo.UserID = c.Param("userid")

_, err := todoCollection.InsertOne(ctx, todo)
err := db.AddTodo(ctx, &todo)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer cancel()
c.JSON(http.StatusOK, gin.H{"insertedId": todo.ID})
}
69 changes: 27 additions & 42 deletions controllers/userController.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,25 @@ import (
"os"
"time"

"github.com/gin-gonic/gin"
"github.com/jeffthorne/tasky/auth"
"github.com/jeffthorne/tasky/database"
"github.com/jeffthorne/tasky/models"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"golang.org/x/crypto/bcrypt"
)

var SECRET_KEY string = os.Getenv("SECRET_KEY")
var userCollection *mongo.Collection = database.OpenCollection(database.Client, "user")


func SignUp(c * gin.Context){

func SignUp(c *gin.Context, db database.DBClient) {
var user models.User
if err := c.BindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var ctx, cancel = context.WithTimeout(context.Background(), 100*time.Second)
defer cancel()

emailCount, err := userCollection.CountDocuments(ctx, bson.M{"email": user.Email})
emailCount, err := db.FindExistingUsers(ctx, user)
defer cancel()

if err != nil {
Expand All @@ -46,14 +41,7 @@ func SignUp(c * gin.Context){
c.JSON(http.StatusBadRequest, gin.H{"error": "User with this email already exists!"})
return
}
user.ID = primitive.NewObjectID()
resultInsertionNumber, insertErr := userCollection.InsertOne(ctx, user)
if insertErr != nil {
msg := fmt.Sprintf("user item was not created")
c.JSON(http.StatusInternalServerError, gin.H{"error": msg})
return
}
defer cancel()
msg, err := db.AddUser(ctx, &user)
userId := user.ID.Hex()
username := *user.Name

Expand All @@ -70,33 +58,30 @@ func SignUp(c * gin.Context){
})

http.SetCookie(c.Writer, &http.Cookie{
Name : "userID",
Value : userId,
Name: "userID",
Value: userId,
Expires: expirationTime,
})
http.SetCookie(c.Writer, &http.Cookie{
Name : "username",
Value : username,
Name: "username",
Value: username,
Expires: expirationTime,
})

c.JSON(http.StatusOK, resultInsertionNumber)

c.JSON(http.StatusOK, msg)

}
func Login(c * gin.Context){
func Login(c *gin.Context, db database.DBClient) {
var user models.User
var foundUser models.User


if err := c.BindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "bind error"})
return
}
var ctx, cancel = context.WithTimeout(context.Background(), 100*time.Second)

err := userCollection.FindOne(ctx, bson.M{"email": user.Email}).Decode(&foundUser)
defer cancel()

foundUser, err := db.GetUser(ctx, *user.Email)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": " email or password is incorrect"})
return
Expand All @@ -116,14 +101,14 @@ func Login(c * gin.Context){
}
userId := foundUser.ID.Hex()
username := *foundUser.Name

shouldRefresh, err, expirationTime := auth.RefreshToken(c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "refresh token error"})
return
}

if shouldRefresh{
if shouldRefresh {
token, err, expirationTime := auth.GenerateJWT(userId)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "error occured while generating token"})
Expand All @@ -137,35 +122,35 @@ func Login(c * gin.Context){
})

http.SetCookie(c.Writer, &http.Cookie{
Name : "userID",
Value : userId,
Name: "userID",
Value: userId,
Expires: expirationTime,
})
http.SetCookie(c.Writer, &http.Cookie{
Name : "username",
Value : username,
Name: "username",
Value: username,
Expires: expirationTime,
})

} else {
http.SetCookie(c.Writer, &http.Cookie{
Name : "userID",
Value : userId,
Name: "userID",
Value: userId,
Expires: expirationTime,
})
http.SetCookie(c.Writer, &http.Cookie{
Name : "username",
Value : username,
Name: "username",
Value: username,
Expires: expirationTime,
})
}
c.JSON(http.StatusOK, gin.H{"msg": "login successful"})
}

func Todo(c * gin.Context) {
func Todo(c *gin.Context, db database.DBClient) {
session := auth.ValidateSession(c)
if session {
c.HTML(http.StatusOK,"todo.html", nil)
c.HTML(http.StatusOK, "todo.html", nil)
}
}

Expand All @@ -188,4 +173,4 @@ func VerifyPassword(userPassword string, providedPassword string) (bool, string)
}

return check, msg
}
}
Loading