211 lines
4.7 KiB
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)
|
|
}
|
|
}
|