new functions, yadda yadda
This commit is contained in:
parent
620db27468
commit
95587ba68d
22
css/main.css
22
css/main.css
@ -121,3 +121,25 @@ nav li a:hover {
|
|||||||
.item {
|
.item {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
border-collapse:collapse;
|
||||||
|
border-spacing:0;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: min-content + 20px;
|
||||||
|
margin-bottom: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
text-align: right
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td, .table th {
|
||||||
|
border-color:black;
|
||||||
|
border-style:solid;
|
||||||
|
border-width:2px
|
||||||
|
}
|
2
go.mod
2
go.mod
@ -3,8 +3,10 @@ module git.nils.zone/nils/goCake
|
|||||||
go 1.15
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
git.nils.zone/nils/prettify v0.0.4
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/kr/pretty v0.1.0 // indirect
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.0.3
|
||||||
github.com/stretchr/testify v1.6.1
|
github.com/stretchr/testify v1.6.1
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||||
)
|
)
|
||||||
|
4
main.go
4
main.go
@ -15,9 +15,9 @@ func main() {
|
|||||||
http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("css"))))
|
http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("css"))))
|
||||||
|
|
||||||
// when navigating to /home it should serve the home page
|
// when navigating to /home it should serve the home page
|
||||||
// http.HandleFunc("/", Home)
|
http.HandleFunc("/", Home)
|
||||||
http.HandleFunc("/", Rewards)
|
|
||||||
http.HandleFunc("/rewards", Rewards)
|
http.HandleFunc("/rewards", Rewards)
|
||||||
|
http.HandleFunc("/table", Rewards)
|
||||||
http.ListenAndServe(getPort(), nil)
|
http.ListenAndServe(getPort(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
109
rewards.go
109
rewards.go
@ -2,11 +2,15 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/lucasb-eyer/go-colorful"
|
||||||
)
|
)
|
||||||
|
|
||||||
type line struct {
|
type line struct {
|
||||||
@ -19,16 +23,28 @@ type line struct {
|
|||||||
Reference string
|
Reference string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type rewards struct {
|
||||||
|
Staking map[time.Month]string
|
||||||
|
Confectionery map[time.Month]string
|
||||||
|
LapisDFI map[time.Month]string
|
||||||
|
Lapis map[time.Month]string
|
||||||
|
Referral map[time.Month]string
|
||||||
|
}
|
||||||
|
|
||||||
// Rewards needs a comment
|
// Rewards needs a comment
|
||||||
func Rewards(w http.ResponseWriter, r *http.Request) {
|
func Rewards(w http.ResponseWriter, r *http.Request) {
|
||||||
type data struct {
|
type data struct {
|
||||||
Title string
|
Title string
|
||||||
Uploaded bool
|
Uploaded bool
|
||||||
Success bool
|
Success bool
|
||||||
Rewards map[time.Month]string
|
Rewards rewards
|
||||||
CumulativeRewards map[time.Month]string
|
CumulativeRewards map[time.Month]string
|
||||||
Color string
|
Color string
|
||||||
|
ColorAlt string
|
||||||
|
ColorAltAlt string
|
||||||
Currency string
|
Currency string
|
||||||
|
ErrorText string
|
||||||
|
Lending bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// set common attributes
|
// set common attributes
|
||||||
@ -48,32 +64,54 @@ func Rewards(w http.ResponseWriter, r *http.Request) {
|
|||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
// upload the file that was posted here
|
// upload the file that was posted here
|
||||||
var success bool = false
|
var success bool = false
|
||||||
|
var e string
|
||||||
|
|
||||||
lines, err := uploadFile(w, r)
|
lines, err := uploadFile(w, r)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
success = true
|
success = true
|
||||||
|
} else {
|
||||||
|
e = err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare data for usage
|
// prepare data for usage
|
||||||
var color string
|
var color string
|
||||||
var currency string
|
var currency string
|
||||||
var rewards map[time.Month]string
|
var rewards rewards
|
||||||
if success == true {
|
if success == true {
|
||||||
currency = lines[1].Cryptocurrency
|
currency = lines[1].Cryptocurrency
|
||||||
color, _ = getCurrencyOpts(currency)
|
color, _, d.Lending = getCurrencyOpts(currency)
|
||||||
rewards = monthlyRewardOverview(lines)
|
rewards = monthlyRewardOverview(lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
// prettify.Print(rewards)
|
// prettify.Print(rewards)
|
||||||
d.Uploaded = true
|
d.Uploaded = true
|
||||||
d.Success = success
|
d.Success = success
|
||||||
d.Rewards = rewards
|
d.Rewards.Staking = rewards.Staking
|
||||||
|
d.Rewards.Confectionery = rewards.Confectionery
|
||||||
|
d.Rewards.Lapis = rewards.Lapis
|
||||||
|
d.Rewards.LapisDFI = rewards.LapisDFI
|
||||||
|
d.Rewards.Referral = rewards.Referral
|
||||||
d.Color = color
|
d.Color = color
|
||||||
|
d.ColorAlt = getOtherColors(color, 2)
|
||||||
|
d.ColorAltAlt = getOtherColors(color, 4)
|
||||||
d.Currency = currency
|
d.Currency = currency
|
||||||
|
d.ErrorText = e
|
||||||
render(w, "rewards.html", d)
|
render(w, "rewards.html", d)
|
||||||
}
|
}
|
||||||
// create a new line instance
|
// create a new line instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getOtherColors(color string, factor float64) string {
|
||||||
|
col, err := colorful.Hex(color)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// get r,g,b from color
|
||||||
|
r, g, b := col.LinearRgb()
|
||||||
|
// return color reduced in "brightness" by factor of f
|
||||||
|
return colorful.LinearRgb(r/factor, g/factor, b/factor).Hex()
|
||||||
|
}
|
||||||
|
|
||||||
func uploadFile(w http.ResponseWriter, r *http.Request) ([]line, error) {
|
func uploadFile(w http.ResponseWriter, r *http.Request) ([]line, error) {
|
||||||
// Maximum upload of 10 MB files
|
// Maximum upload of 10 MB files
|
||||||
r.ParseMultipartForm(10 << 20)
|
r.ParseMultipartForm(10 << 20)
|
||||||
@ -81,7 +119,7 @@ func uploadFile(w http.ResponseWriter, r *http.Request) ([]line, error) {
|
|||||||
// Get handler for filename, size and headers
|
// Get handler for filename, size and headers
|
||||||
file, handler, err := r.FormFile("csvFile")
|
file, handler, err := r.FormFile("csvFile")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.New("please upload a .csv file")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
@ -91,30 +129,37 @@ func uploadFile(w http.ResponseWriter, r *http.Request) ([]line, error) {
|
|||||||
// accept this gift and read content of file
|
// accept this gift and read content of file
|
||||||
fileContents, err := ioutil.ReadAll(file)
|
fileContents, err := ioutil.ReadAll(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Println("file was uploaded but can't be read! 1", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// read uploaded file
|
// read uploaded file
|
||||||
lines := readUploadedFile(fileContents)
|
lines, err := readUploadedFile(fileContents)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("the .csv file could not be read, error was: %s", err)
|
||||||
|
}
|
||||||
return lines, err
|
return lines, err
|
||||||
}
|
}
|
||||||
return nil, errors.New("please only upload .csv files")
|
return nil, errors.New("please only upload .csv files")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCurrencyOpts(currency string) (color string, precision int) {
|
func getCurrencyOpts(currency string) (color string, precision int, lending bool) {
|
||||||
// set default precision
|
// set default precision
|
||||||
precision = 8
|
precision = 8
|
||||||
|
lending = false
|
||||||
|
|
||||||
// set other options according to the coin
|
// set other options according to the coin
|
||||||
switch currency {
|
switch currency {
|
||||||
case "BTC": // Bitcoin
|
case "BTC": // Bitcoin
|
||||||
color = "#F7931A"
|
color = "#F7931A"
|
||||||
|
lending = true
|
||||||
case "DASH":
|
case "DASH":
|
||||||
color = "#008de4"
|
color = "#008de4"
|
||||||
case "DFI": // DeFiChain
|
case "DFI": // DeFiChain
|
||||||
color = "#fd0bb0"
|
color = "#fd0bb0"
|
||||||
case "ETH": // Ethereum
|
case "ETH": // Ethereum
|
||||||
color = "#627eea"
|
color = "#627eea"
|
||||||
|
lending = true
|
||||||
precision = 18
|
precision = 18
|
||||||
case "PIVX":
|
case "PIVX":
|
||||||
color = "#5e4778"
|
color = "#5e4778"
|
||||||
@ -123,30 +168,49 @@ func getCurrencyOpts(currency string) (color string, precision int) {
|
|||||||
color = "#24b852"
|
color = "#24b852"
|
||||||
case "USDT": // Tether
|
case "USDT": // Tether
|
||||||
color = "#26a17b"
|
color = "#26a17b"
|
||||||
|
lending = true
|
||||||
precision = 6
|
precision = 6
|
||||||
}
|
}
|
||||||
return color, precision
|
return color, precision, lending
|
||||||
}
|
}
|
||||||
|
|
||||||
func monthlyRewardOverview(lines []line) map[time.Month]string {
|
func monthlyRewardOverview(lines []line) rewards {
|
||||||
// create a map to hold all months' sums
|
// create a map to hold all months' sums
|
||||||
sums := make(map[time.Month]float64)
|
staking := make(map[time.Month]float64)
|
||||||
|
confectionery := make(map[time.Month]float64)
|
||||||
|
lapisDFI := make(map[time.Month]float64)
|
||||||
|
lapis := make(map[time.Month]float64)
|
||||||
|
referral := make(map[time.Month]float64)
|
||||||
|
|
||||||
// loop through all lines
|
// loop through all lines
|
||||||
for i := range lines {
|
for i := range lines {
|
||||||
// filter out operations
|
// filter out operations
|
||||||
switch lines[i].Operation {
|
switch lines[i].Operation {
|
||||||
case "Staking reward ", "Confectionery Lapis DFI Bonus ", "Lapis DFI Bonus ", "Lapis reward ", "Referral reward ":
|
case "Staking reward":
|
||||||
sums[lines[i].Date.Month()] += lines[i].Amount
|
staking[lines[i].Date.Month()] += lines[i].Amount
|
||||||
|
case "Confectionery Lapis DFI Bonus":
|
||||||
|
confectionery[lines[i].Date.Month()] += lines[i].Amount
|
||||||
|
case "Lapis DFI Bonus":
|
||||||
|
lapisDFI[lines[i].Date.Month()] += lines[i].Amount
|
||||||
|
case "Lapis reward":
|
||||||
|
lapis[lines[i].Date.Month()] += lines[i].Amount
|
||||||
|
case "Referral reward":
|
||||||
|
referral[lines[i].Date.Month()] += lines[i].Amount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get precision for specific coin
|
// get precision for specific coin
|
||||||
_, precision := getCurrencyOpts(lines[0].Cryptocurrency)
|
_, precision, _ := getCurrencyOpts(lines[0].Cryptocurrency)
|
||||||
// fill empty data with zeroes
|
// fill empty data with zeroes
|
||||||
sumsString := fillSums(sums, precision)
|
r := rewards{
|
||||||
|
Staking: fillSums(staking, precision),
|
||||||
|
Confectionery: fillSums(confectionery, precision),
|
||||||
|
LapisDFI: fillSums(lapisDFI, precision),
|
||||||
|
Lapis: fillSums(lapis, precision),
|
||||||
|
Referral: fillSums(referral, precision),
|
||||||
|
}
|
||||||
|
|
||||||
return sumsString
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillSums(s map[time.Month]float64, precision int) map[time.Month]string {
|
func fillSums(s map[time.Month]float64, precision int) map[time.Month]string {
|
||||||
@ -166,12 +230,13 @@ func fillSums(s map[time.Month]float64, precision int) map[time.Month]string {
|
|||||||
return sumsString
|
return sumsString
|
||||||
}
|
}
|
||||||
|
|
||||||
func readUploadedFile(fileContents []byte) []line {
|
func readUploadedFile(fileContents []byte) ([]line, error) {
|
||||||
var lines []line
|
var lines []line
|
||||||
csvLines := strings.Split(string(fileContents), "\n")
|
csvLines := strings.Split(string(fileContents), "\n")
|
||||||
|
|
||||||
// loop through all lines (except headers)
|
// loop through all lines (except headers)
|
||||||
for _, csvLine := range csvLines[1:] {
|
for _, csvLine := range csvLines[1:] {
|
||||||
|
if csvLine != "" {
|
||||||
// split arguments by comma
|
// split arguments by comma
|
||||||
csvArgs := strings.Split(csvLine, ",")
|
csvArgs := strings.Split(csvLine, ",")
|
||||||
|
|
||||||
@ -187,7 +252,7 @@ func readUploadedFile(fileContents []byte) []line {
|
|||||||
var err error
|
var err error
|
||||||
l.Date, err = time.Parse(time.RFC3339, csvArgs[0])
|
l.Date, err = time.Parse(time.RFC3339, csvArgs[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
l.Operation = csvArgs[1]
|
l.Operation = csvArgs[1]
|
||||||
l.Cryptocurrency = csvArgs[2]
|
l.Cryptocurrency = csvArgs[2]
|
||||||
@ -197,14 +262,6 @@ func readUploadedFile(fileContents []byte) []line {
|
|||||||
l.Reference = csvArgs[6]
|
l.Reference = csvArgs[6]
|
||||||
lines = append(lines, l)
|
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)
|
|
||||||
}
|
}
|
||||||
|
return lines, nil
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
{{ if .Title}}
|
{{ if .Title}}
|
||||||
<!-- set current tab active, according to title -->
|
<!-- set current tab active, according to title -->
|
||||||
<!-- <li><a {{ if (eq .Title "Home") }}class="active"{{end}} href="/">Home</a></li> -->
|
<li><a {{ if (eq .Title "Home") }}class="active"{{end}} href="/">Home</a></li>
|
||||||
<!-- <li><a {{ if (eq .Title "Rewards") }}class="active"{{end}} href="rewards">Monthly Rewards</a></li> -->
|
<!-- <li><a {{ if (eq .Title "Rewards") }}class="active"{{end}} href="rewards">Monthly Rewards</a></li> -->
|
||||||
<!-- <li><a {{ if (eq .Title "Graphs") }}class="active"{{end}} href="graphs">Graphs</a></li> -->
|
<!-- <li><a {{ if (eq .Title "Graphs") }}class="active"{{end}} href="graphs">Graphs</a></li> -->
|
||||||
<li><a {{ if (eq .Title "Monthly Rewards") }}class="active"{{end}} href="rewards">Monthly Rewards</a></li>
|
<li><a {{ if (eq .Title "Monthly Rewards") }}class="active"{{end}} href="rewards">Monthly Rewards</a></li>
|
||||||
@ -29,8 +29,8 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "footer"}}
|
{{define "footer"}}
|
||||||
<div class="footer">♥ 2020 Nils Jakobi
|
<div class="footer">
|
||||||
- <a href="https://git.nils.zone/nils/goCake">Source Code</a>
|
♥ <a href="https://github.com/thunderstorm99/goCoinAnalyzer">Source Code</a> ♥
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -46,23 +46,59 @@
|
|||||||
var rewardOptions = {
|
var rewardOptions = {
|
||||||
title: {"text":"Monthly Rewards","subtext":"{{.Currency}}"},
|
title: {"text":"Monthly Rewards","subtext":"{{.Currency}}"},
|
||||||
tooltip: {"show":true},
|
tooltip: {"show":true},
|
||||||
legend: {"show":false},
|
legend: {"show":true},
|
||||||
dataZoom:[{"type":"inside"}],
|
dataZoom:[{"type":"inside"}],
|
||||||
xAxis: {{ template "xAxis" . }}
|
xAxis: {{ template "xAxis" . }}
|
||||||
yAxis: [{}],
|
yAxis: [{}],
|
||||||
series: [{{template "series" . }}],
|
series: [{{template "series" . }}],
|
||||||
color: ["{{.Color}}"],
|
color: ["{{.Color}}","{{.ColorAlt}}","{{.ColorAltAlt}}"],
|
||||||
};
|
};
|
||||||
rewardChart.setOption(rewardOptions);
|
rewardChart.setOption(rewardOptions);
|
||||||
</script>
|
</script>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
{{define "xAxis"}}
|
{{define "xAxis"}}
|
||||||
[{"data":[ {{ range $month, $amount := .Rewards}}"{{ $month }}",{{ end }}]}],
|
[{"data":[ {{ range $month, $amount := .Rewards.Staking}}"{{ $month }}",{{ end }}]}],
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "series"}}
|
{{define "series"}}
|
||||||
{"name":"{{.Currency}}","type":"bar","waveAnimation":false,"data":[
|
{{if .Lending}}
|
||||||
{{ range $month, $amount := .Rewards}}{"value": "{{ $amount }}" },{{ end }}
|
// Lending coins
|
||||||
|
{"name":"Lapis reward","type":"bar","stack":"stackA","waveAnimation":false,"data":[
|
||||||
|
{{ range $month, $amount := .Rewards.Lapis}}{"value": "{{ $amount }}" },{{ end }}
|
||||||
|
]},
|
||||||
|
{"name":"Referral reward","type":"bar","stack":"stackA","waveAnimation":false,"data":[
|
||||||
|
{{ range $month, $amount := .Rewards.Referral}}{"value": "{{ $amount }}" },{{ end }}
|
||||||
|
]},
|
||||||
|
{{else}}
|
||||||
|
// Stakeable coins
|
||||||
|
{"name":"Staking Rewards","type":"bar","stack":"stackA","waveAnimation":false,"data":[
|
||||||
|
{{ range $month, $amount := .Rewards.Staking}}{"value": "{{ $amount }}" },{{ end }}
|
||||||
|
]},
|
||||||
|
{"name":"Lapis DFI Bonus","type":"bar","stack":"stackA","waveAnimation":false,"data":[
|
||||||
|
{{ range $month, $amount := .Rewards.LapisDFI}}{"value": "{{ $amount }}" },{{ end }}
|
||||||
|
]},
|
||||||
|
{"name":"Confectionery Lapis DFI Bonus","type":"bar","stack":"stackA","waveAnimation":false,"data":[
|
||||||
|
{{ range $month, $amount := .Rewards.Confectionery}}{"value": "{{ $amount }}" },{{ end }}
|
||||||
]},
|
]},
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "table"}}
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Month</th>
|
||||||
|
<th>{{.Currency}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{ range $month, $amount := .Rewards.Staking}}
|
||||||
|
<tr>
|
||||||
|
<td class="left">{{ $month }}</td>
|
||||||
|
<td class="right">{{ $amount }}</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{end}}
|
@ -14,12 +14,15 @@
|
|||||||
{{if .Uploaded}}
|
{{if .Uploaded}}
|
||||||
<!-- Uploaded but not successful -->
|
<!-- Uploaded but not successful -->
|
||||||
<div class="err">
|
<div class="err">
|
||||||
<p>Please only upload .csv Files!</p>
|
{{if ne .ErrorText ""}}
|
||||||
|
<p>{{.ErrorText}}</p>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<!-- successful -->
|
<!-- successful -->
|
||||||
{{template "barGraph" .}}
|
{{template "barGraph" .}}
|
||||||
|
<!-- {{template "table" .}} -->
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{template "footer" .}}
|
{{template "footer" .}}
|
Loading…
Reference in New Issue
Block a user