You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
6.7 KiB

package widgets
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/jacobmveber-01839764/BudgetBuddy/db"
"github.com/jacobmveber-01839764/BudgetBuddy/money"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
const (
RecentTransactionAmount = 10
)
type RecentTransactionsResponse struct {
Status int `json:"status"`
Transactions []db.Transaction `json:"transactions"`
}
func GetRecentTransactions(w http.ResponseWriter, r *http.Request) {
// get session key from request
session := r.Header.Get("x-session-key")
// get collection handle from db
var userCollection = db.Client.Database("budgetbuddy").Collection("users")
var user = db.UserSchema{}
err := userCollection.FindOne(context.Background(), bson.D{primitive.E{Key: "session", Value: session}}).Decode(&user)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintf(w, "{\"error\":\"invalid session key\"}")
return
}
var transactionA []db.Transaction
i := 0
j := 0
for i+j < RecentTransactionAmount {
// if we are out of transactions, return
if i >= len(user.Expenses) && j >= len(user.Income) {
break
} else if i > len(user.Expenses)-1 { // if we are out of expenses, just use income
transactionA = append(transactionA, user.Income[j])
j++
} else if j > len(user.Income)-1 { // if we are out of income, just use expenses
transactionA = append(transactionA, user.Expenses[i])
i++
} else if user.Expenses[i].Timestamp > user.Income[j].Timestamp {
transactionA = append(transactionA, user.Expenses[i])
i++
} else {
transactionA = append(transactionA, user.Income[j])
j++
}
}
response := RecentTransactionsResponse{
Status: 200,
Transactions: transactionA,
}
ret, err := json.Marshal(response)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "{\"error\":\"problem marshalling response\"}")
}
w.Write(ret)
}
func NewTransaction(w http.ResponseWriter, r *http.Request) {
// get session key from request
session := r.Header.Get("x-session-key")
// get collection handle from db
var userCollection = db.Client.Database("budgetbuddy").Collection("users")
var user = db.UserSchema{}
err := userCollection.FindOne(context.Background(), bson.D{primitive.E{Key: "session", Value: session}}).Decode(&user)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintf(w, "{\"error\":\"invalid session key\"}")
return
}
r.ParseForm()
whole, err := strconv.Atoi(r.Form.Get("whole"))
if err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "{\"error\":\"incorrect whole value\"}")
return
}
decimal, err := strconv.Atoi(r.Form.Get("decimal"))
if err != nil || decimal < 0 || decimal > 99 {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "{\"error\":\"incorrect decimal value\"}")
return
}
var cat string
if r.FormValue("category") == "" {
cat = "uncategorized"
} else {
cat = r.FormValue("category")
}
newT := db.Transaction{
Timestamp: time.Now().Unix(),
Category: cat,
Amount: money.Money{
Currency: money.Currency(r.FormValue("currency")),
Whole: whole,
Decimal: decimal,
},
Type: r.FormValue("type"),
}
var newArr []db.Transaction
var success bool
if r.FormValue("type") == "income" {
newArr = append(user.Income, newT)
success = addToBalance(user, newT.Amount)
} else if r.FormValue("type") == "expenses" {
newArr = append(user.Expenses, newT)
success = subtractFromBalance(user, newT.Amount)
} else {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "{\"error\":\"invalid transaction type - only income or expenses are allowed\"}")
return
}
if !success {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "{\"error\":\"unable to update balance\"}")
return
}
// push the new transaction to db
filter := bson.D{primitive.E{Key: "session", Value: user.Session}}
opts := options.Update().SetUpsert(true)
update := bson.D{primitive.E{Key: "$set", Value: bson.D{primitive.E{Key: r.FormValue("type"), Value: newArr}}}}
userCollection.UpdateOne(context.TODO(), filter, update, opts)
w.Write([]byte("{\"status\":200}"))
}
func NewRecurring(w http.ResponseWriter, r *http.Request) {
// get session key from request
session := r.Header.Get("x-session-key")
// get collection handle from db
var userCollection = db.Client.Database("budgetbuddy").Collection("users")
var user = db.UserSchema{}
err := userCollection.FindOne(context.Background(), bson.D{primitive.E{Key: "session", Value: session}}).Decode(&user)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintf(w, "{\"error\":\"invalid session key\"}")
return
}
r.ParseForm()
whole, err := strconv.Atoi(r.Form.Get("whole"))
if err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "{\"error\":\"incorrect whole value\"}")
return
}
decimal, err := strconv.Atoi(r.Form.Get("decimal"))
if err != nil || decimal < 0 || decimal > 99 {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "{\"error\":\"incorrect decimal value\"}")
return
}
period, err := strconv.Atoi(r.Form.Get("period"))
if err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "{\"error\":\"period must be specified\"}")
return
}
var cat string
if r.FormValue("category") == "" {
cat = "uncategorized"
}
newT := db.Transaction{
Timestamp: time.Now().Unix(),
Category: cat,
Amount: money.Money{
Currency: money.Currency(r.FormValue("currency")),
Whole: whole,
Decimal: decimal,
},
Type: r.FormValue("type"),
}
newR := db.RecurringTransaction{
Transaction: newT,
Period: period,
Since: time.Now().Unix(),
Until: int64(0),
}
var newArr []db.RecurringTransaction
var success bool
if r.FormValue("type") == "income" {
newArr = append(user.RecurringIncome, newR)
success = addToBalance(user, newT.Amount)
} else if r.FormValue("type") == "expenses" {
newArr = append(user.RecurringExpenses, newR)
success = subtractFromBalance(user, newT.Amount)
} else {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "{\"error\":\"invalid transaction type - only income or expenses are allowed\"}")
return
}
if !success {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "{\"error\":\"unable to update balance\"}")
return
}
// push the new transaction to db
filter := bson.D{primitive.E{Key: "session", Value: user.Session}}
opts := options.Update().SetUpsert(true)
update := bson.D{primitive.E{Key: "$set", Value: bson.D{primitive.E{Key: r.FormValue("type"), Value: newArr}}}}
userCollection.UpdateOne(context.TODO(), filter, update, opts)
w.Write([]byte("{\"status\":200}"))
}