goCake/rewards.go

211 lines
4.7 KiB
Go

package main
import (
"errors"
"io/ioutil"
"net/http"
"strconv"
"strings"
"time"
)
type line struct {
Date time.Time
Operation string
Cryptocurrency string
Amount float64
TransactionID string
WithdrawalAddress string
Reference string
}
// Rewards needs a comment
func Rewards(w http.ResponseWriter, r *http.Request) {
type data struct {
Title string
Uploaded bool
Success bool
Rewards map[time.Month]string
CumulativeRewards map[time.Month]string
Color string
Currency string
}
// set common attributes
d := data{
Title: "Monthly Rewards",
}
// check the method used to access this site (GET/POST)
switch r.Method {
case http.MethodGet:
// display upload site
d.Uploaded = false
d.Success = false
render(w, "rewards.html", d)
case http.MethodPost:
// upload the file that was posted here
var success bool = false
lines, err := uploadFile(w, r)
if err == nil {
success = true
}
// prepare data for usage
var color string
var currency string
var rewards map[time.Month]string
if success == true {
currency = lines[1].Cryptocurrency
color, _ = getCurrencyOpts(currency)
rewards = monthlyRewardOverview(lines)
}
// prettify.Print(rewards)
d.Uploaded = true
d.Success = success
d.Rewards = rewards
d.Color = color
d.Currency = currency
render(w, "rewards.html", d)
}
// create a new line instance
}
func uploadFile(w http.ResponseWriter, r *http.Request) ([]line, error) {
// Maximum upload of 10 MB files
r.ParseMultipartForm(10 << 20)
// Get handler for filename, size and headers
file, handler, err := r.FormFile("csvFile")
if err != nil {
return nil, err
}
defer file.Close()
// check if we got a csv file
if handler.Header["Content-Type"][0] == "text/csv" {
// accept this gift and read content of file
fileContents, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}
// read uploaded file
lines := readUploadedFile(fileContents)
return lines, err
}
return nil, errors.New("please only upload .csv files")
}
func getCurrencyOpts(currency string) (color string, precision int) {
// set default precision
precision = 8
// set other options according to the coin
switch currency {
case "BTC": // Bitcoin
color = "#F7931A"
case "DASH":
color = "#008de4"
case "DFI": // DeFiChain
color = "#fd0bb0"
case "ETH": // Ethereum
color = "#627eea"
precision = 18
case "PIVX":
color = "#5e4778"
precision = 9
case "XZC": // Zcoin
color = "#24b852"
case "USDT": // Tether
color = "#26a17b"
precision = 6
}
return color, precision
}
func monthlyRewardOverview(lines []line) map[time.Month]string {
// create a map to hold all months' sums
sums := make(map[time.Month]float64)
// loop through all lines
for i := range lines {
// filter out operations
switch lines[i].Operation {
case "Staking reward ", "Confectionery Lapis DFI Bonus ", "Lapis DFI Bonus ", "Lapis reward ", "Referral reward ":
sums[lines[i].Date.Month()] += lines[i].Amount
}
}
// get precision for specific coin
_, precision := getCurrencyOpts(lines[0].Cryptocurrency)
// fill empty data with zeroes
sumsString := fillSums(sums, precision)
return sumsString
}
func fillSums(s map[time.Month]float64, precision int) map[time.Month]string {
// maps are always referenced by pointers
// create empty map
sumsString := make(map[time.Month]string)
// loop through month
for i := 1; i < 13; i++ {
// check what month are missing in array
if _, ok := s[time.Month(i)]; !ok {
s[time.Month(i)] = 0
}
// format to strings
sumsString[time.Month(i)] = strconv.FormatFloat(s[time.Month(i)], 'g', precision, 64)
}
return sumsString
}
func readUploadedFile(fileContents []byte) []line {
var lines []line
csvLines := strings.Split(string(fileContents), "\n")
// loop through all lines (except headers)
for _, csvLine := range csvLines[1:] {
// split arguments by comma
csvArgs := strings.Split(csvLine, ",")
// fix stupid " in lines
for i := range csvArgs {
csvArgs[i] = strings.ReplaceAll(csvArgs[i], `"`, "")
}
// create output variable
var l line
// assign values from CSV file to output variable
var err error
l.Date, err = time.Parse(time.RFC3339, csvArgs[0])
if err != nil {
panic(err)
}
l.Operation = csvArgs[1]
l.Cryptocurrency = csvArgs[2]
l.Amount, _ = strconv.ParseFloat(csvArgs[3], 64)
l.TransactionID = csvArgs[4]
l.WithdrawalAddress = csvArgs[5]
l.Reference = csvArgs[6]
lines = append(lines, l)
}
return lines
}
func uploadHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
render(w, "upload", nil)
case "POST":
uploadFile(w, r)
}
}