From a1d06686d349d904a2db1685880e3ef90c612246 Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Tue, 27 May 2025 16:28:36 +1000 Subject: [PATCH] cmd/apichecker: Remove tool (#1921) * chore: Remove apichecker.tmpl Removed template file related to the decommissioned apichecker. * chore: Remove apichecker.tmpl Removed template file related to the decommissioned apichecker. --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- cmd/apichecker/README.md | 132 -- cmd/apichecker/apicheck.go | 1568 ----------------- cmd/apichecker/apicheck_test.go | 656 ------- cmd/apichecker/apicheck_types.go | 100 -- cmd/apichecker/backup.json | 391 ---- cmd/apichecker/testupdates.json | 324 ---- cmd/apichecker/updates.json | 324 ---- .../cmd_templates/apichecker.tmpl | 98 -- 8 files changed, 3593 deletions(-) delete mode 100644 cmd/apichecker/README.md delete mode 100644 cmd/apichecker/apicheck.go delete mode 100644 cmd/apichecker/apicheck_test.go delete mode 100644 cmd/apichecker/apicheck_types.go delete mode 100644 cmd/apichecker/backup.json delete mode 100644 cmd/apichecker/testupdates.json delete mode 100644 cmd/apichecker/updates.json delete mode 100644 cmd/documentation/cmd_templates/apichecker.tmpl diff --git a/cmd/apichecker/README.md b/cmd/apichecker/README.md deleted file mode 100644 index 1f0e01ee..00000000 --- a/cmd/apichecker/README.md +++ /dev/null @@ -1,132 +0,0 @@ -# GoCryptoTrader package Apichecker - - - - -[![Build Status](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml) -[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE) -[![GoDoc](https://godoc.org/github.com/thrasher-corp/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-corp/gocryptotrader/cmd/apichecker) -[![Coverage Status](https://codecov.io/gh/thrasher-corp/gocryptotrader/graph/badge.svg?token=41784B23TS)](https://codecov.io/gh/thrasher-corp/gocryptotrader) -[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-corp/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader) - - -This apichecker package is part of the GoCryptoTrader codebase. - -## This is still in active development - -You can track ideas, planned features and what's in progress on our [GoCryptoTrader Kanban board](https://github.com/orgs/thrasher-corp/projects/3). - -Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTc5ZDE1ZTNiOGM3ZGMyMmY1NTAxYWZhODE0MWM5N2JlZDk1NDU0YTViYzk4NTk3OTRiMDQzNGQ1YTc4YmRlMTk) - -## Current Features for apichecker - -+ Checks for API updates -+ Can automatically update Trello checklist for the updates required -+ Supports trello integration - -#### This tool tracks changes in exchange API documentation -#### Keeps track of all the updates using the GoCryptoTrader trello board - -Be aware, this tool will: -- Automatically update the live trello board if API keys and trello information are provided. -- Automatically update the main json updates file, however a backup of the copy before the updates will be stored. - -## Usage - -+ To run a real check for updates, parse Trello API info as flags or add them to the updates.json file and use the following command from apichecker folder in GCT: - -###### Linux/OSX -GoCryptoTrader is built using [Go Modules](https://github.com/golang/go/wiki/Modules) and requires Go 1.11 or above -Using Go Modules you now clone this repository **outside** your GOPATH - -```bash -git clone https://github.com/thrasher-corp/gocryptotrader.git -cd gocryptotrader/cmd/apichecker -go build -./apichecker -``` - -###### Windows - -```bash -git clone https://github.com/thrasher-corp/gocryptotrader.git -cd gocryptotrader\cmd\apichecker -go build && apichecker.exe -``` - -+ Upon addition of a new exchange, to update Trello checklist and to add the exchange to updates.json the following would need to be done: - -###### HTML Scraping method: -HTMLScrapingData is a struct which contains the necessary information to scrape data from the given path website. Not all the elements of HTMLScrapingData are necessary, its all dependent on site where information is being extracted from. Regexp is used to capture necessary bits of data using r.FindString() where r is the declared regular expression. If update dates data is available, DateFormat is used to convert the dates to a more standard format which can then be used for further comparisons of which update is most recent. -```go -func TestAdd(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{TokenData: "h1", - Key: "id", - Val: "revision-history", - TokenDataEnd: "table", - TextTokenData: "td", - DateFormat: "2006/01/02", - RegExp: "^20(\\d){2}/(\\d){2}/(\\d){2}$", - CheckString: "2019/11/15", - Path: "https://docs.gemini.com/rest-api/#revision-history"} - err := Add("Gemini", htmlScrape, data.Path, data, true, &testConfigData) - if err != nil { - t.Error(err) - } -} -``` - -###### Github SHA Check Method: -```go -func TestAdd(t *testing.T) { - t.Parallel() - data := GithubData{Repo: "LBank-exchange/lbank-official-api-docs"} - err := Add("Lbank", github, fmt.Sprintf(githubPath, data.Repo), data, false, &configData) - if err != nil { - t.Error(err) - } -} -``` - -###### Add using flags: -```bash -apichecker.exe -add=true -key=id -val=revision-history -tokendata=h1 -tokendataend=table -texttokendata=td -dateformat=2006/01/02 -checktype="HTML String Check" -regexp="^20(\d){2}/(\d){2}/(\d){2}$" -path="https://docs.gemini.com/rest-api/#revision-history" -exchangename=Gemini -``` - -+ If all the authentication variables for trello are set trello checklist will be automatically updated with the format of 'Exchange Name (integer of how many updates have been released since the exchange API was last worked on): - -- To acquire your trello key and access token please login into trello using the following link and follow the steps: https://trello.com/app-key - -- To acquire BoardID, ListID, CardID and ChecklistID inbuilt functions can be used such as trelloGetAllLists() - -- To create a new list, card, checklist, and to populate the the checklist --create flag can be used. - -- To create a new check within a checklist, an inbuilt function within apichecker can be used: trelloCreateNewCheck - -- For the first time running the application & to create a list, card and checklist use the following: -```bash -apichecker.exe --create -apikey="insertkeyhere" -apitoken="inserttokenhere" -boardname="insertboardnamehere" -``` - - -### Please click GoDocs chevron above to view current GoDoc information for this package - -## Contribution - -Please feel free to submit any pull requests or suggest any desired features to be added. - -When submitting a PR, please abide by our coding guidelines: - -+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)). -+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines. -+ Code must adhere to our [coding style](https://github.com/thrasher-corp/gocryptotrader/blob/master/doc/coding_style.md). -+ Pull requests need to be based on and opened against the `master` branch. - -## Donations - - - -If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to: - -***bc1qk0jareu4jytc0cfrhr5wgshsq8282awpavfahc*** diff --git a/cmd/apichecker/apicheck.go b/cmd/apichecker/apicheck.go deleted file mode 100644 index 36676437..00000000 --- a/cmd/apichecker/apicheck.go +++ /dev/null @@ -1,1568 +0,0 @@ -package main - -import ( - "context" - "errors" - "flag" - "fmt" - "io" - "net/http" - "net/url" - "os" - "regexp" - "slices" - "strconv" - "strings" - "sync" - "time" - - "github.com/thrasher-corp/gocryptotrader/common" - gctfile "github.com/thrasher-corp/gocryptotrader/common/file" - "github.com/thrasher-corp/gocryptotrader/encoding/json" - exchange "github.com/thrasher-corp/gocryptotrader/exchanges" - "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "github.com/thrasher-corp/gocryptotrader/log" - "golang.org/x/net/html" -) - -const ( - githubPath = "https://api.github.com/repos/%s/commits/master" - jsonFile = "updates.json" - testJSONFile = "testupdates.json" - backupFile = "backup.json" - github = "GitHub Sha Check" - htmlScrape = "HTML String Check" - pathBinance = "https://binance-docs.github.io/apidocs/spot/en/#change-log" - pathBTSE = "https://www.btse.com/apiexplorer/spot/#btse-spot-api" - pathBitfinex = "https://docs.bitfinex.com/docs/changelog" - pathBitmex = "https://www.bitmex.com/static/md/en-US/apiChangelog" - pathANX = "https://anxv3.docs.apiary.io/" - pathPoloniex = "https://docs.poloniex.com/#changelog" - pathBTCMarkets = "https://api.btcmarkets.net/openapi/info/index.yaml" - pathEXMO = "https://exmo.com/en/api/" - pathBitstamp = "https://www.bitstamp.net/api/" - pathHitBTC = "https://api.hitbtc.com/" - pathBitflyer = "https://lightning.bitflyer.com/docs?lang=en" - pathKraken = "https://www.kraken.com/features/api" - pathAlphaPoint = "https://alphapoint.github.io/slate/#introduction" - pathYobit = "https://www.yobit.net/en/api/" - pathGetAllLists = "https://api.trello.com/1/boards/%s/lists?cards=none&card_fields=all&filter=open&fields=all&key=%s&token=%s" - pathNewCard = "https://api.trello.com/1/cards?idList=%s&name=%s&key=%s&token=%s" - pathChecklists = "https://api.trello.com/1/checklists/%s/checkItems?%s&key=%s&token=%s" - pathChecklistItems = "https://api.trello.com/1/checklists/%s?fields=name&cards=all&card_fields=name&key=%s&token=%s" - pathUpdateItems = "https://api.trello.com/1/cards/%s/checkItem/%s?%s&key=%s&token=%s" - pathCheckBoardID = "https://api.trello.com/1/members/me/boards?key=%s&token=%s" - pathNewChecklist = "https://api.trello.com/1/checklists?idCard=%s&name=%s&key=%s&token=%s" - pathNewList = "https://api.trello.com/1/lists?name=%s&idBoard=%s&key=%s&token=%s" - pathGetCards = "https://api.trello.com/1/lists/%s/cards?key=%s&token=%s" - pathGetChecklists = "https://api.trello.com/1/cards/%s/checklists?&key=%s&token=%s" - pathDeleteCheckitems = "https://api.trello.com/1/checklists/%s/checkItems/%s?key=%s&token=%s" - complete = "complete" - incomplete = "incomplete" - createList = "UpdatesList" - createCard = "UpdatesCard" - createChecklist = "UpdatesChecklist" - btcMarkets = "BTC Markets" -) - -var ( - verbose, add, create, testMode bool - apiKey, apiToken, trelloBoardID, trelloBoardName, trelloListID, - trelloChecklistID, trelloCardID, exchangeName, checkType, tokenData, - key, val, tokenDataEnd, textTokenData, dateFormat, regExp, path string - configData, testConfigData, usageData Config -) - -func main() { - flag.StringVar(&apiKey, "apikey", "", "sets the API key for Trello board interaction") - flag.StringVar(&apiToken, "apitoken", "", "sets the API token for Trello board interaction") - flag.StringVar(&trelloChecklistID, "checklistid", "", "sets the checklist ID for Trello board interaction") - flag.StringVar(&trelloCardID, "cardid", "", "sets the card ID for Trello board interaction") - flag.StringVar(&trelloListID, "listid", "", "sets the list ID for Trello board interaction") - flag.StringVar(&trelloBoardID, "boardid", "", "sets the board ID for Trello board interaction") - flag.StringVar(&trelloBoardName, "boardname", "", "sets the board name for Trello board interaction") - flag.StringVar(&exchangeName, "exchangename", "", "sets the exchangeName for the new exchange") - flag.StringVar(&checkType, "checktype", "", "sets the checkType for the new exchange") - flag.StringVar(&tokenData, "tokendata", "", "sets the tokenData for adding a new exchange") - flag.StringVar(&key, "key", "", "sets the key for adding a new exchange") - flag.StringVar(&val, "val", "", "sets the val for adding a new exchange") - flag.StringVar(&tokenDataEnd, "tokendataend", "", "sets the tokenDataEnd for adding a new exchange") - flag.StringVar(&textTokenData, "texttokendata", "", "sets the textTokenData for adding a new exchange") - flag.StringVar(®Exp, "regexp", "", "sets the regExp for adding a new exchange") - flag.StringVar(&dateFormat, "dateformat", "", "sets the dateFormat for adding a new exchange") - flag.StringVar(&path, "path", "", "sets the path for adding a new exchange") - flag.BoolVar(&add, "add", false, "used as a trigger to add a new exchange from command line") - flag.BoolVar(&verbose, "verbose", false, "increases logging verbosity for API Update Checker") - flag.BoolVar(&create, "create", false, "specifies whether to automatically create trello list, card and checklist in a given board") - flag.Parse() - - err := log.SetGlobalLogConfig(log.GenDefaultSettings()) - if err != nil { - fmt.Printf("Could not setup global logger. Error: %v.\n", err) - os.Exit(1) - } - - err = log.SetupGlobalLogger("cmd/apicheck", false) - if err != nil { - fmt.Printf("Could not setup global logger. Error: %v.\n", err) - os.Exit(1) - } - configData, err = readFileData(jsonFile) - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - testConfigData, err = readFileData(testJSONFile) - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - usageData = testConfigData - if canUpdateTrello() || (create && areAPIKeysSet()) { - usageData = configData - } - if add { - switch checkType { - case github: - var data GithubData - data.Repo = path - err = addExch(exchangeName, checkType, data, false) - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - case htmlScrape: - var data HTMLScrapingData - data.TokenData = tokenData - data.Key = key - data.Val = val - data.TokenDataEnd = tokenDataEnd - data.TextTokenData = textTokenData - data.DateFormat = dateFormat - data.RegExp = regExp - data.Path = path - err = addExch(exchangeName, checkType, data, false) - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - } - } - var a string - if canUpdateTrello() || create { - setAuthVars() - if trelloBoardName != "" { - a, err = trelloGetBoardID() - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - trelloBoardID = a - } - if create { - err = createAndSet() - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - } - err = updateFile(backupFile) - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - err = checkUpdates(jsonFile) - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - } else { - log.Warnln(log.Global, "This is a test update since API keys are not set.") - err := checkUpdates(testJSONFile) - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - log.Infoln(log.Global, "API update check completed successfully") - } -} - -// createAndSet creates and sets the necessary trello board items and sets the authenticated variables accordingly -func createAndSet() error { - var err error - err = trelloCreateNewList() - if err != nil { - return err - } - err = trelloCreateNewCard() - if err != nil { - return err - } - err = trelloCreateNewChecklist() - if err != nil { - return err - } - setAuthVars() - return nil -} - -// setAuthVars checks if the cmdline vars are set and sets them onto config file and vice versa -func setAuthVars() { - if apiKey == "" { - apiKey = configData.Key - usageData.Key = configData.Key - } else { - configData.Key = apiKey - usageData.Key = apiKey - } - if apiToken == "" { - apiToken = configData.Token - usageData.Token = configData.Token - } else { - configData.Token = apiToken - usageData.Token = apiToken - } - if trelloCardID == "" { - trelloCardID = configData.CardID - usageData.CardID = configData.CardID - } else { - configData.CardID = trelloCardID - usageData.CardID = trelloCardID - } - if trelloChecklistID == "" { - trelloChecklistID = configData.ChecklistID - usageData.ChecklistID = configData.ChecklistID - } else { - configData.ChecklistID = trelloChecklistID - usageData.ChecklistID = trelloChecklistID - } - if trelloListID == "" { - trelloListID = configData.ListID - usageData.ListID = configData.ListID - } else { - configData.ListID = trelloListID - usageData.ListID = trelloListID - } - if trelloBoardID == "" { - trelloBoardID = configData.BoardID - usageData.BoardID = configData.BoardID - } else { - configData.BoardID = trelloBoardID - usageData.BoardID = trelloBoardID - } -} - -// writeAuthVars writes the new authentication variables to the updates.json file -func writeAuthVars(testMode bool) error { - setAuthVars() - if testMode { - return updateFile(testJSONFile) - } - return updateFile(jsonFile) -} - -// canUpdateTrello checks if all the data necessary for updating trello is available -func canUpdateTrello() bool { - return areAPIKeysSet() && isTrelloBoardDataSet() -} - -// areAPIKeysSet checks if api keys and tokens are set -func areAPIKeysSet() bool { - return (apiKey != "" && apiToken != "") || (configData.Key != "" && configData.Token != "") -} - -// isTrelloBoardDataSet checks if data required to update trello board is set -func isTrelloBoardDataSet() bool { - if (trelloBoardID != "" && trelloListID != "" && trelloChecklistID != "" && trelloCardID != "") || - (configData.CardID != "" && configData.ChecklistID != "" && configData.BoardID != "" && configData.ListID != "") { - return true - } - return false -} - -// getSha gets the sha of the latest commit -func getSha(repoPath string) (ShaResponse, error) { - var resp ShaResponse - getPath := fmt.Sprintf(githubPath, repoPath) - if verbose { - log.Debugf(log.Global, "Getting SHA of this path: %v\n", getPath) - } - return resp, sendGetReq(getPath, &resp) -} - -// checkExistingExchanges checks if the given exchange exists -func checkExistingExchanges(exchName string) bool { - for x := range usageData.Exchanges { - if usageData.Exchanges[x].Name == exchName { - return true - } - } - return false -} - -// checkMissingExchanges checks if any supported exchanges are missing api checker functionality -func checkMissingExchanges() []string { - exchanges := make([]string, len(usageData.Exchanges)) - for i, exch := range usageData.Exchanges { - exchanges[i] = exch.Name - } - - supportedExchs := slices.Clone(exchange.Exchanges) - - return slices.DeleteFunc(supportedExchs, func(exchName string) bool { - return common.StringSliceContainsInsensitive(exchanges, exchName) - }) -} - -// readFileData reads the file data from the given json file -func readFileData(fileName string) (Config, error) { - var c Config - data, err := os.ReadFile(fileName) - if err != nil { - return c, err - } - err = json.Unmarshal(data, &c) - if err != nil { - return c, err - } - return c, nil -} - -// checkUpdates checks updates.json for all the existing exchanges -func checkUpdates(fileName string) error { - var resp []string - errMap := make(map[string]error) - var wg sync.WaitGroup - var m sync.Mutex - allExchangeData := usageData.Exchanges - for x := range allExchangeData { - if allExchangeData[x].Disabled { - continue - } - wg.Add(1) - go func(e ExchangeInfo) { - defer wg.Done() - switch e.CheckType { - case github: - m.Lock() - repoPath := e.Data.GitHubData.Repo - m.Unlock() - sha, err := getSha(repoPath) - m.Lock() - if err != nil { - errMap[e.Name] = err - m.Unlock() - return - } - if sha.ShaResp == "" { - errMap[e.Name] = errors.New("invalid sha") - m.Unlock() - return - } - if sha.ShaResp != e.Data.GitHubData.Sha { - resp = append(resp, e.Name) - e.Data.GitHubData.Sha = sha.ShaResp - } - m.Unlock() - case htmlScrape: - checkStr, err := checkChangeLog(e.Data.HTMLData) - m.Lock() - if err != nil { - errMap[e.Name] = err - m.Unlock() - return - } - if checkStr != e.Data.HTMLData.CheckString { - resp = append(resp, e.Name) - e.Data.HTMLData.CheckString = checkStr - } - m.Unlock() - } - }(allExchangeData[x]) - } - wg.Wait() - file, err := json.MarshalIndent(&usageData, "", " ") - if err != nil { - return err - } - var check bool - if areAPIKeysSet() { - check, err = trelloCheckBoardID() - if err != nil { - return err - } - if !check { - return errors.New("incorrect boardID or api info") - } - var a ChecklistItemData - for y := range resp { - a, err = trelloGetChecklistItems() - if err != nil { - return err - } - var contains bool - for z := range a.CheckItems { - if strings.Contains(a.CheckItems[z].Name, resp[y]) { - err = trelloUpdateCheckItem(a.CheckItems[z].ID, a.CheckItems[z].Name, a.CheckItems[z].State) - if err != nil { - return err - } - contains = true - } - } - if !contains { - err = trelloCreateNewCheck(resp[y]) - if err != nil { - return err - } - } - } - a, err = trelloGetChecklistItems() - if err != nil { - return err - } - for l := range a.CheckItems { - if a.CheckItems[l].State == complete { - err = trelloDeleteCheckItem(a.CheckItems[l].ID) - if err != nil { - return err - } - } - } - } - if !areAPIKeysSet() { - fileName = testJSONFile - if verbose { - log.Warnln(log.Global, "Updating test file; main file & trello will not be automatically updated since API key & token are not set") - } - } - log.Warnf(log.Global, "The following exchanges need an update: %v\n", resp) - for k := range errMap { - log.Warnf(log.Global, "Error: %v\n", errMap[k]) - } - unsup := checkMissingExchanges() - log.Warnf(log.Global, "The following exchanges are not supported by apichecker: %v\n", unsup) - log.Debugf(log.Global, "Saving the updates to the following file: %s\n", fileName) - return os.WriteFile(fileName, file, gctfile.DefaultPermissionOctal) -} - -// checkChangeLog checks the exchanges which support changelog updates.json -func checkChangeLog(htmlData *HTMLScrapingData) (string, error) { - var dataStrings []string - var err error - switch htmlData.Path { - case pathBinance: - dataStrings, err = htmlScrapeBinance(htmlData) - case pathBTSE: - dataStrings, err = htmlScrapeBTSE(htmlData) - case pathBitfinex: - dataStrings, err = htmlScrapeBitfinex(htmlData) - case pathBitmex: - dataStrings, err = htmlScrapeBitmex(htmlData) - case pathPoloniex: - dataStrings, err = htmlScrapePoloniex(htmlData) - case pathBTCMarkets: - dataStrings, err = htmlScrapeBTCMarkets(htmlData) - case pathEXMO: - dataStrings, err = htmlScrapeExmo(htmlData) - case pathBitstamp: - dataStrings, err = htmlScrapeBitstamp(htmlData) - case pathHitBTC: - dataStrings, err = htmlScrapeHitBTC(htmlData) - case pathBitflyer: - dataStrings, err = htmlScrapeBitflyer(htmlData) - case pathKraken: - dataStrings, err = htmlScrapeKraken(htmlData) - case pathAlphaPoint: - dataStrings, err = htmlScrapeAlphaPoint(htmlData) - case pathYobit: - dataStrings, err = htmlScrapeYobit(htmlData) - default: - dataStrings, err = htmlScrapeDefault(htmlData) - } - if err != nil { - return "", err - } - switch { - case len(dataStrings) == 1: - return dataStrings[0], nil - case len(dataStrings) > 1: - x, err := time.Parse(htmlData.DateFormat, dataStrings[0]) - if err != nil { - return "", err - } - y, err := time.Parse(htmlData.DateFormat, dataStrings[len(dataStrings)-1]) - if err != nil { - return "", err - } - z := y.Sub(x) - switch { - case z > 0: - return dataStrings[len(dataStrings)-1], nil - case z < 0: - return dataStrings[0], nil - default: - return "", errors.New("two or more updates were done on the same day, please check manually") - } - } - return "", fmt.Errorf("no response found for the following path: %s", htmlData.Path) -} - -// addExch appends exchange data to updates.json for future api checks -func addExch(exchName, checkType string, data any, isUpdate bool) error { - var file []byte - if !isUpdate { - if checkExistingExchanges(exchName) { - log.Debugf(log.Global, "%v exchange already exists\n", exchName) - return nil - } - exchangeData, err := fillData(exchName, checkType, data) - if err != nil { - return err - } - usageData.Exchanges = append(usageData.Exchanges, exchangeData) - file, err = json.MarshalIndent(&usageData, "", " ") - if err != nil { - return err - } - } else { - info, err := fillData(exchName, checkType, data) - if err != nil { - return err - } - allExchData := update(exchName, usageData.Exchanges, info) - usageData.Exchanges = allExchData - file, err = json.MarshalIndent(&usageData, "", " ") - if err != nil { - return err - } - } - if canUpdateTrello() { - if !isUpdate { - err := trelloCreateNewCheck(exchName + " 1") - if err != nil { - return err - } - } - return os.WriteFile(jsonFile, file, gctfile.DefaultPermissionOctal) - } - return os.WriteFile(testJSONFile, file, gctfile.DefaultPermissionOctal) -} - -// fillData fills exchange data based on the given checkType -func fillData(exchName, checkType string, data any) (ExchangeInfo, error) { - switch checkType { - case github: - tempData, ok := data.(GithubData) - if !ok { - return ExchangeInfo{}, common.GetTypeAssertError("GithubData", data) - } - tempSha, err := getSha(path) - if err != nil { - return ExchangeInfo{}, err - } - tempData.Sha = tempSha.ShaResp - return ExchangeInfo{ - Name: exchName, - CheckType: checkType, - Data: &CheckData{ - GitHubData: &tempData, - }, - }, nil - case htmlScrape: - tempData, ok := data.(HTMLScrapingData) - if !ok { - return ExchangeInfo{}, common.GetTypeAssertError("HTMLScrapingData", data) - } - checkStr, err := checkChangeLog(&tempData) - if err != nil { - return ExchangeInfo{}, err - } - return ExchangeInfo{ - Name: exchName, - CheckType: checkType, - Data: &CheckData{ - HTMLData: &HTMLScrapingData{ - CheckString: checkStr, - DateFormat: tempData.DateFormat, - Key: tempData.Key, - RegExp: tempData.RegExp, - TextTokenData: tempData.TextTokenData, - TokenData: tempData.TokenData, - TokenDataEnd: tempData.TokenDataEnd, - Val: tempData.Val, - Path: tempData.Path, - }, - }, - }, nil - default: - return ExchangeInfo{}, errors.New("invalid checkType") - } -} - -// htmlScrapeDefault gets check string data for the default cases -func htmlScrapeDefault(htmlData *HTMLScrapingData) ([]string, error) { - var resp []string - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - tokenizer := html.NewTokenizer(temp.Body) -loop: - for { - next := tokenizer.Next() - switch next { - case html.ErrorToken: - break loop - case html.StartTagToken: - token := tokenizer.Token() - if token.Data == htmlData.TokenData { - for _, a := range token.Attr { - if a.Key == htmlData.Key && a.Val == htmlData.Val { - loop2: - for { - nextToken := tokenizer.Next() - switch nextToken { - case html.EndTagToken: - t := tokenizer.Token() - if t.Data == htmlData.TokenDataEnd { - break loop2 - } - case html.StartTagToken: - newtok := tokenizer.Token() - if newtok.Data == htmlData.TextTokenData { - inner := tokenizer.Next() - if inner == html.TextToken { - tempStr := string(tokenizer.Text()) - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return resp, err - } - if r.MatchString(tempStr) { - appendStr := r.FindString(tempStr) - resp = append(resp, appendStr) - } - } - } - } - } - } - } - } - } - } - return resp, nil -} - -// htmlScrapeBTSE gets the check string for BTSE exchange -func htmlScrapeBTSE(htmlData *HTMLScrapingData) ([]string, error) { - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - tokenizer := html.NewTokenizer(temp.Body) - - var resp []string -loop: - for { - next := tokenizer.Next() - switch next { - case html.ErrorToken: - break loop - case html.StartTagToken: - token := tokenizer.Token() - if token.Data == htmlData.TokenData { - for _, z := range token.Attr { - if z.Key == htmlData.Key && z.Val == htmlData.Val { - inner := tokenizer.Next() - if inner == html.TextToken { - resp = append(resp, string(tokenizer.Text())) - } - } - } - } - } - } - return resp, nil -} - -// htmlScrapeBitmex gets the check string for Bitmex exchange -func htmlScrapeBitmex(htmlData *HTMLScrapingData) ([]string, error) { - var resp []string - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - tokenizer := html.NewTokenizer(temp.Body) -loop: - for { - next := tokenizer.Next() - switch next { - case html.ErrorToken: - break loop - case html.StartTagToken: - token := tokenizer.Token() - if token.Data == htmlData.TokenData { - for _, x := range token.Attr { - if x.Key != htmlData.Key { - continue - } - tempStr := x.Val - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return resp, err - } - result := r.MatchString(tempStr) - if result { - appendStr := r.FindString(tempStr) - resp = append(resp, appendStr) - } - } - } - } - } - return resp, nil -} - -// htmlScrapeHitBTC gets the check string for HitBTC Exchange -func htmlScrapeHitBTC(htmlData *HTMLScrapingData) ([]string, error) { - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - - a, err := io.ReadAll(temp.Body) - if err != nil { - return nil, err - } - - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return nil, err - } - - return r.FindAllString(string(a), -1), nil -} - -// htmlScrapeBTCMarkets gets the check string for BTCMarkets exchange -func htmlScrapeBTCMarkets(htmlData *HTMLScrapingData) ([]string, error) { - var resp []string - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - tempData, err := io.ReadAll(temp.Body) - if err != nil { - return resp, err - } - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return resp, err - } - result := r.FindString(string(tempData)) - resp = append(resp, result) - return resp, nil -} - -// htmlScrapeOk gets the check string for Okx -func htmlScrapeOk(htmlData *HTMLScrapingData) ([]string, error) { - var resp []string - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - tokenizer := html.NewTokenizer(temp.Body) -loop: - for { - next := tokenizer.Next() - switch next { - case html.ErrorToken: - break loop - case html.StartTagToken: - token := tokenizer.Token() - if token.Data == htmlData.TokenData { - for _, a := range token.Attr { - if a.Key == htmlData.Key && a.Val == htmlData.Val { - loop2: - for { - nextToken := tokenizer.Next() - switch nextToken { - case html.StartTagToken: - f := tokenizer.Token() - for _, tkz := range f.Attr { - if tkz.Key == htmlData.Key { - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return resp, err - } - result := r.MatchString(tkz.Val) - if result { - appendStr := strings.Replace(tkz.Val, htmlData.TokenDataEnd, "", 1) - resp = append(resp, appendStr) - } - } - } - case html.EndTagToken: - tk := tokenizer.Token() - if tk.Data == "ul" { - break loop2 - } - } - } - } - } - } - } - } - if len(resp) > 1 { - resp = resp[:1] - } - return resp, nil -} - -// htmlScrapeExmo gets the check string for Exmo Exchange -func htmlScrapeExmo(htmlData *HTMLScrapingData) ([]string, error) { - header := map[string]string{ - "User-Agent": "GCT", - } - - httpResp, err := sendHTTPGetRequest(htmlData.Path, header) - if err != nil { - return nil, err - } - - defer httpResp.Body.Close() - a, err := io.ReadAll(httpResp.Body) - if err != nil { - return nil, err - } - aBody := string(a) - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return nil, err - } - resp := r.FindAllString(aBody, -1) - return resp, nil -} - -// htmlScrapePoloniex gets the check string for Poloniex Exchange -func htmlScrapePoloniex(htmlData *HTMLScrapingData) ([]string, error) { - var resp []string - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - tokenizer := html.NewTokenizer(temp.Body) -loop: - for { - next := tokenizer.Next() - switch next { - case html.ErrorToken: - break loop - case html.StartTagToken: - token := tokenizer.Token() - if token.Data == htmlData.TokenData { - for _, z := range token.Attr { - if z.Key == htmlData.Key && z.Val == htmlData.Val { - loop2: - for { - nextToken := tokenizer.Next() - switch nextToken { - case html.EndTagToken: - t := tokenizer.Token() - if t.Data == htmlData.TokenDataEnd { - break loop2 - } - case html.StartTagToken: - t := tokenizer.Token() - if t.Data == htmlData.TextTokenData { - newToken := tokenizer.Next() - if newToken == html.TextToken { - tempStr := string(tokenizer.Text()) - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return resp, err - } - result := r.FindString(tempStr) - resp = append(resp, result) - } - } - } - } - } - } - } - } - } - return resp, nil -} - -// htmlScrapeBitstamp gets the check string for Bitstamp Exchange -func htmlScrapeBitstamp(htmlData *HTMLScrapingData) ([]string, error) { - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - - a, err := io.ReadAll(temp.Body) - if err != nil { - return nil, err - } - aBody := string(a) - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return nil, err - } - resp := r.FindAllString(aBody, -1) - return resp, nil -} - -// htmlScrapeAlphaPoint gets the check string for Kraken Exchange -func htmlScrapeAlphaPoint(htmlData *HTMLScrapingData) ([]string, error) { - var resp []string - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - tokenizer := html.NewTokenizer(temp.Body) -loop: - for { - next := tokenizer.Next() - switch next { - case html.ErrorToken: - break loop - case html.StartTagToken: - token := tokenizer.Token() - if token.Data == htmlData.TokenData { - for _, x := range token.Attr { - if x.Key == htmlData.Key && x.Val == htmlData.Val { - loop2: - for { - inner := tokenizer.Next() - switch inner { - case html.EndTagToken: - t := tokenizer.Token() - if t.Data == htmlData.TokenDataEnd { - break loop2 - } - case html.StartTagToken: - t := tokenizer.Token() - if t.Data == htmlData.TextTokenData { - for _, y := range t.Attr { - if y.Key == htmlData.Key { - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return resp, err - } - result := r.MatchString(y.Val) - if result { - resp = append(resp, y.Val) - } - } - } - } - } - } - } - } - } - } - } - return resp, nil -} - -// htmlScrapeYobit gets the check string for Yobit Exchange -func htmlScrapeYobit(htmlData *HTMLScrapingData) ([]string, error) { - var resp []string - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - tokenizer := html.NewTokenizer(temp.Body) - var case1, case2, case3 bool -loop: - for { - next := tokenizer.Next() - switch next { - case html.ErrorToken: - break loop - case html.StartTagToken: - token := tokenizer.Token() - if token.Data == htmlData.TokenData { - for _, x := range token.Attr { - if x.Key == htmlData.Key { - switch x.Val { - case "n4": - inner := tokenizer.Next() - if inner == html.TextToken { - if string(tokenizer.Text()) == "v2" { - case1 = true - } - } - case "n5": - inner := tokenizer.Next() - if inner == html.TextToken { - tempStr := string(tokenizer.Text()) - if tempStr == "v3" { - case2 = true - resp = append(resp, tempStr) - } - } - case "n6": - inner := tokenizer.Next() - if inner == html.TextToken { - tempStr := string(tokenizer.Text()) - if tempStr != "v4" { - case3 = true - } - if case1 && case2 && case3 { - return resp, nil - } - resp = append(resp, tempStr) - } - } - } - } - } - } - } - return resp, nil -} - -// trelloCreateNewCheck creates a new checklist item within a given checklist from trello -func trelloCreateNewCheck(newCheckName string) error { - newName, err := nameStateChanges(newCheckName, "") - if err != nil { - return err - } - var resp any - params := url.Values{} - params.Set("name", newName) - return sendAuthReq(http.MethodPost, - fmt.Sprintf(pathChecklists, trelloChecklistID, params.Encode(), apiKey, apiToken), - &resp) -} - -// trelloCheckBoardID gets board id of the trello boards for a user which can be used for checking if a given board exists -func trelloCheckBoardID() (bool, error) { - var data []MembersData - err := sendAuthReq(http.MethodGet, - fmt.Sprintf(pathCheckBoardID, apiKey, apiToken), - &data) - if err != nil { - return false, err - } - if data == nil { - return false, errors.New("no trello boards available for the given apikey and token") - } - for x := range data { - if (trelloBoardID == data[x].ShortID) || (trelloBoardID == data[x].ID) || (trelloBoardName == data[x].Name) { - return true, nil - } - } - return false, nil -} - -// trelloGetChecklistItems get info on all the items on a given checklist from trello -func trelloGetChecklistItems() (ChecklistItemData, error) { - var resp ChecklistItemData - path := fmt.Sprintf(pathChecklistItems, trelloChecklistID, apiKey, apiToken) - return resp, sendGetReq(path, &resp) -} - -// nameStateChanges returns the appropriate update name & state for trello -func nameStateChanges(currentName, currentState string) (string, error) { - name := currentName - exists := false - var num int64 - var err error - switch currentName { - case btcMarkets: - if strings.Count(currentName, " ") == 2 { - exists = true - } - name = fmt.Sprintf("%s %s", strings.Split(currentName, " ")[0], strings.Split(currentName, " ")[1]) - if !exists { - return name + " 1", nil - } - num, err = strconv.ParseInt(strings.Split(currentName, " ")[2], 10, 64) - if err != nil { - return "", err - } - default: - if strings.Contains(currentName, " ") { - exists = true - name = strings.Split(currentName, " ")[0] - if !exists { - return name + " 1", nil - } - num, err = strconv.ParseInt(strings.Split(currentName, " ")[1], 10, 64) - if err != nil { - return "", err - } - } - if !exists { - return name + " 1", nil - } - } - - newNum := num - if currentState == complete { - newNum = 1 - } else { - newNum++ - } - return fmt.Sprintf("%s %d", name, newNum), nil -} - -// trelloUpdateCheckItem updates a check item for trello -func trelloUpdateCheckItem(checkItemID, name, state string) error { - var resp any - params := url.Values{} - newName, err := nameStateChanges(name, state) - if err != nil { - return err - } - params.Set("name", newName) - params.Set("state", incomplete) - path := fmt.Sprintf(pathUpdateItems, trelloCardID, checkItemID, params.Encode(), apiKey, apiToken) - err = sendAuthReq(http.MethodPut, path, &resp) - return err -} - -// update updates the exchange data -func update(currentName string, info []ExchangeInfo, updatedInfo ExchangeInfo) []ExchangeInfo { - for x := range info { - if info[x].Name == currentName { - if info[x].CheckType == updatedInfo.CheckType { - info[x].Data.GitHubData = updatedInfo.Data.GitHubData - info[x].Data.HTMLData = updatedInfo.Data.HTMLData - break - } - } - } - return info -} - -// UpdateFile updates the given file to match updates.json -func updateFile(name string) error { - file, err := json.MarshalIndent(&configData, "", " ") - if err != nil { - return err - } - return os.WriteFile(name, file, gctfile.DefaultPermissionOctal) -} - -// SendGetReq sends get req -func sendGetReq(path string, result any) error { - var requester *request.Requester - var err error - if strings.Contains(path, "github") { - requester, err = request.New("Apichecker", - common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(request.NewBasicRateLimit(time.Hour, 60, 1))) - } else { - requester, err = request.New("Apichecker", - common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(request.NewBasicRateLimit(time.Second, 100, 1))) - } - if err != nil { - return err - } - item := &request.Item{ - Method: http.MethodGet, - Path: path, - Result: result, - Verbose: verbose, - } - return requester.SendPayload(context.Background(), request.Unset, func() (*request.Item, error) { - return item, nil - }, request.UnauthenticatedRequest) -} - -// sendAuthReq sends auth req -func sendAuthReq(method, path string, result any) error { - requester, err := request.New("Apichecker", - common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(request.NewBasicRateLimit(time.Second*10, 100, 1))) - if err != nil { - return err - } - item := &request.Item{ - Method: method, - Path: path, - Result: result, - Verbose: verbose, - } - return requester.SendPayload(context.Background(), request.Unset, func() (*request.Item, error) { - return item, nil - }, request.AuthenticatedRequest) -} - -// trelloGetBoardID gets all board ids on trello for a given user -func trelloGetBoardID() (string, error) { - if trelloBoardName == "" { - return "", errors.New("trelloBoardName not set, cannot find the trelloBoard") - } - var resp []TrelloData - err := sendGetReq(fmt.Sprintf(pathCheckBoardID, apiKey, apiToken), - &resp) - if err != nil { - return "", err - } - for x := range resp { - if resp[x].Name == trelloBoardName { - return resp[x].ID, err - } - } - return "", errors.New("boardID not found") -} - -// trelloGetLists gets all lists from a given board -func trelloGetLists() ([]TrelloData, error) { - var resp []TrelloData - return resp, sendGetReq(fmt.Sprintf(pathGetAllLists, trelloBoardID, apiKey, apiToken), &resp) -} - -// trelloCreateNewList creates a new list on a specified boards on trello -func trelloCreateNewList() error { - if trelloBoardID == "" { - return errors.New("trelloBoardID not set, cannot create a new list") - } - var resp any - listName := createList - if configData.CreateListName != "" { - listName = configData.CreateListName - } - err := sendAuthReq(http.MethodPost, - fmt.Sprintf(pathNewList, listName, trelloBoardID, apiKey, apiToken), - &resp) - if err != nil { - return err - } - lists, err := trelloGetLists() - if err != nil { - return err - } - for x := range lists { - if lists[x].Name != listName { - continue - } - trelloListID = lists[x].ID - usageData.ListID = lists[x].ID - err = writeAuthVars(testMode) - if err != nil { - return err - } - return nil - } - return nil -} - -// trelloDeleteCheckItem deletes check item from a checklist -func trelloDeleteCheckItem(checkitemID string) error { - if checkitemID == "" { - return errors.New("checkitemID cannot be empty") - } - var resp any - return sendAuthReq(http.MethodDelete, - fmt.Sprintf(pathDeleteCheckitems, trelloChecklistID, checkitemID, apiKey, apiToken), - &resp) -} - -// trelloGetAllCards gets all cards from a given list -func trelloGetAllCards() ([]TrelloData, error) { - var resp []TrelloData - return resp, sendGetReq(fmt.Sprintf(pathGetCards, trelloListID, apiKey, apiToken), &resp) -} - -// trelloCreateNewCard creates a new card on the list specified on trello -func trelloCreateNewCard() error { - if trelloListID == "" { - return errors.New("trelloListID not set, cannot create a new checklist") - } - var resp any - cardName := createCard - if configData.CreateCardName != "" { - cardName = configData.CreateCardName - } - err := sendAuthReq(http.MethodPost, - fmt.Sprintf(pathNewCard, trelloListID, cardName, apiKey, apiToken), - &resp) - if err != nil { - return err - } - cards, err := trelloGetAllCards() - if err != nil { - return err - } - for x := range cards { - if cards[x].Name != cardName { - continue - } - trelloCardID = cards[x].ID - usageData.CardID = cards[x].ID - err = writeAuthVars(testMode) - if err != nil { - return err - } - return nil - } - return errors.New("card id and name not found, list creation failed") -} - -// trelloGetAllChecklists gets all checklists from a card on trello -func trelloGetAllChecklists() ([]TrelloData, error) { - var resp []TrelloData - return resp, sendGetReq(fmt.Sprintf(pathGetChecklists, trelloCardID, apiKey, apiToken), &resp) -} - -// trelloCreateNewChecklist creates a new checklist on a specified card on trello -func trelloCreateNewChecklist() error { - if !areAPIKeysSet() || (trelloCardID == "") { - return errors.New("apikeys or trelloCardID not set, cannot create a new checklist") - } - var resp any - checklistName := createChecklist - if configData.CreateChecklistName != "" { - checklistName = configData.CreateChecklistName - } - err := sendAuthReq(http.MethodPost, - fmt.Sprintf(pathNewChecklist, trelloCardID, checklistName, apiKey, apiToken), - &resp) - if err != nil { - return err - } - checklists, err := trelloGetAllChecklists() - if err != nil { - return err - } - for x := range checklists { - if checklists[x].Name != checklistName { - continue - } - trelloChecklistID = checklists[x].ID - usageData.ChecklistID = checklists[x].ID - err = writeAuthVars(testMode) - if err != nil { - return err - } - return nil - } - return errors.New("checklist id and name not found, checklist creation failed") -} - -// htmlScrapeKraken gets the check string for Kraken Exchange -func htmlScrapeKraken(htmlData *HTMLScrapingData) ([]string, error) { - var resp []string - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - tokenizer := html.NewTokenizer(temp.Body) -loop: - for { - next := tokenizer.Next() - switch next { - case html.ErrorToken: - break loop - case html.StartTagToken: - token := tokenizer.Token() - if token.Data == htmlData.TokenData { - inner := tokenizer.Next() - if inner == html.TextToken { - if string(tokenizer.Text()) == "Get account balance" { - loop2: - for { - next := tokenizer.Next() - switch next { - case html.EndTagToken: - t := tokenizer.Token() - if t.Data == htmlData.TokenDataEnd { - break loop2 - } - case html.StartTagToken: - t := tokenizer.Token() - if t.Data == htmlData.TextTokenData { - inside := tokenizer.Next() - if inside == html.TextToken { - tempStr := string(tokenizer.Text()) - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return resp, err - } - result := r.MatchString(tempStr) - if result { - resp = append(resp, tempStr) - } - } - } - } - } - } - } - } - } - } - return resp, nil -} - -// htmlScrapeBitflyer gets the check string for BTCMarkets exchange -func htmlScrapeBitflyer(htmlData *HTMLScrapingData) ([]string, error) { - var resp []string - var tempArray []string - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - tokenizer := html.NewTokenizer(temp.Body) -loop: - for { - next := tokenizer.Next() - switch next { - case html.ErrorToken: - break loop - case html.StartTagToken: - token := tokenizer.Token() - if token.Data == htmlData.TokenData { - for { - nextToken := tokenizer.Next() - switch nextToken { - case html.EndTagToken: - t := tokenizer.Token() - if t.Data == htmlData.TokenDataEnd { - break loop - } - case html.StartTagToken: - t := tokenizer.Token() - if t.Data == htmlData.TextTokenData { - inner := tokenizer.Next() - if inner == html.TextToken { - tempStr := string(tokenizer.Text()) - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return resp, err - } - result := r.MatchString(tempStr) - if result { - appendStr := r.FindString(tempStr) - tempArray = append(tempArray, appendStr) - } - } - } - } - } - } - } - } - resp = append(resp, tempArray[1]) - return resp, nil -} - -// htmlScrapeBitfinex gets the check string for Bitfinex exchange -func htmlScrapeBitfinex(htmlData *HTMLScrapingData) ([]string, error) { - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - - a, err := io.ReadAll(temp.Body) - if err != nil { - return nil, err - } - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return nil, err - } - matches := r.FindAllString(string(a), -1) - results := make([]string, 0, len(matches)) - for _, match := range matches { - s := strings.Replace(match, "section-v-", "", 1) - results = append(results, s) - } - slices.Sort(results) - return slices.Clip(slices.Compact(results)), nil -} - -// htmlScrapeBinance gets checkstring for binance exchange -func htmlScrapeBinance(htmlData *HTMLScrapingData) ([]string, error) { - temp, err := sendHTTPGetRequest(htmlData.Path, nil) - if err != nil { - return nil, err - } - defer temp.Body.Close() - - tokenizer := html.NewTokenizer(temp.Body) - var resp []string -loop: - for { - next := tokenizer.Next() - switch next { - case html.ErrorToken: - break loop - case html.StartTagToken: - token := tokenizer.Token() - if token.Data == htmlData.TokenData { - for _, a := range token.Attr { - if a.Key == htmlData.Key && a.Val == htmlData.Val { - loop2: - for { - nextToken := tokenizer.Next() - switch nextToken { - case html.EndTagToken: - nt := tokenizer.Token() - if nt.Data == htmlData.TokenDataEnd { - break loop2 - } - case html.StartTagToken: - tk := tokenizer.Token() - if tk.Data == htmlData.TextTokenData { - inner := tokenizer.Next() - if inner == html.TextToken { - tempStr := string(tokenizer.Text()) - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return resp, err - } - if r.MatchString(tempStr) { - resp = append(resp, tempStr) - } - } - } - } - } - } - } - } - } - } - return resp, nil -} - -func sendHTTPGetRequest(path string, headers map[string]string) (*http.Response, error) { - req, err := http.NewRequestWithContext(context.TODO(), - http.MethodGet, - path, - http.NoBody) - if err != nil { - return nil, err - } - - for k, v := range headers { - req.Header.Set(k, v) - } - return http.DefaultClient.Do(req) -} diff --git a/cmd/apichecker/apicheck_test.go b/cmd/apichecker/apicheck_test.go deleted file mode 100644 index fd870f54..00000000 --- a/cmd/apichecker/apicheck_test.go +++ /dev/null @@ -1,656 +0,0 @@ -package main - -import ( - "os" - "reflect" - "testing" - - "github.com/stretchr/testify/require" - gctfile "github.com/thrasher-corp/gocryptotrader/common/file" - "github.com/thrasher-corp/gocryptotrader/encoding/json" - exchange "github.com/thrasher-corp/gocryptotrader/exchanges" - "github.com/thrasher-corp/gocryptotrader/log" -) - -var ( - testAPIKey = "" - testAPIToken = "" - testChecklistID = "" - testCardID = "" - testListID = "" - testBoardID = "" - testBoardName = "" - canTestMainFile = false -) - -func TestMain(m *testing.M) { - setTestVars() - err := log.SetGlobalLogConfig(log.GenDefaultSettings()) - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - log.Infoln(log.Global, "set verbose to true for more detailed output") - configData, err = readFileData(jsonFile) - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - testConfigData, err = readFileData(testJSONFile) - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - usageData = testConfigData - setTestVars() - testExitCode := m.Run() - err = removeTestFileVars() - if err != nil { - log.Errorln(log.Global, err) - os.Exit(1) - } - os.Exit(testExitCode) -} - -func areTestAPIKeysSet() bool { - return (testAPIKey != "" && testAPIToken != "") -} - -func setTestVars() { - if !canUpdateTrello() { - apiKey = testAPIKey - apiToken = testAPIToken - trelloChecklistID = testChecklistID - trelloCardID = testCardID - trelloListID = testListID - trelloBoardID = testBoardID - trelloBoardName = testBoardName - return - } -} - -func removeTestFileVars() error { - a, err := readFileData(testJSONFile) - if err != nil { - return err - } - a.BoardID = "" - a.CardID = "" - a.ChecklistID = "" - a.Key = "" - a.ListID = "" - a.Token = "" - file, err := json.MarshalIndent(&a, "", " ") - if err != nil { - return err - } - return os.WriteFile(testJSONFile, file, gctfile.DefaultPermissionOctal) -} - -func canTestTrello() bool { - if testAPIKey != "" && testAPIToken != "" && testChecklistID != "" && testCardID != "" && testListID != "" && (testBoardID != "" || testBoardName != "") { - return true - } - return false -} - -func TestCheckUpdates(t *testing.T) { - if !canUpdateTrello() || !canTestTrello() { - t.Skip("cannot update or test trello, skipping") - } - err := checkUpdates(testJSONFile) - if err != nil { - t.Fatal(err) - } -} - -func TestUpdateFile(t *testing.T) { - realConf, err := readFileData(jsonFile) - if err != nil { - t.Fatal(err) - } - configData = realConf - err = updateFile(testJSONFile) - if err != nil { - t.Fatal(err) - } - testConf, err := readFileData(testJSONFile) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(realConf, testConf) { - t.Error("test file update failed") - } -} - -func TestCheckExistingExchanges(t *testing.T) { - t.Parallel() - if !checkExistingExchanges("Kraken") { - t.Fatal("Kraken data not found") - } -} - -func TestCheckChangeLog(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "h1", - Key: "id", - Val: "revision-history", - TokenDataEnd: "table", - TextTokenData: "td", - DateFormat: "2006/01/02", - RegExp: `^20(\d){2}/(\d){2}/(\d){2}$`, - Path: "https://docs.gemini.com/rest-api/#revision-history", - } - if _, err := checkChangeLog(&data); err != nil { - t.Error(err) - } -} - -func TestAdd(t *testing.T) { - t.Parallel() - data2 := HTMLScrapingData{ - TokenData: "h1", - Key: "id", - Val: "change-log", - TextTokenData: "strong", - TokenDataEnd: "p", - Path: "incorrectpath", - } - err := addExch("FalseName", htmlScrape, data2, false) - if err == nil { - t.Error("expected an error due to invalid path being parsed in") - } -} - -func TestHTMLScrapeGemini(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "h1", - Key: "id", - Val: "revision-history", - TokenDataEnd: "table", - TextTokenData: "td", - DateFormat: "2006/01/02", - RegExp: "^20(\\d){2}/(\\d){2}/(\\d){2}$", - CheckString: "2019/11/15", - Path: "https://docs.gemini.com/rest-api/#revision-history", - } - _, err := htmlScrapeDefault(&data) - if err != nil { - t.Error(err) - } -} - -func TestHTMLScrapeHuobi(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "h1", - Key: "id", - Val: "change-log", - TokenDataEnd: "h2", - TextTokenData: "td", - DateFormat: "2006.01.02 15:04", - RegExp: "^20(\\d){2}.(\\d){2}.(\\d){2} (\\d){2}:(\\d){2}$", - CheckString: "2019.12.27 19:00", - Path: "https://huobiapi.github.io/docs/spot/v1/en/#change-log", - } - _, err := htmlScrapeDefault(&data) - if err != nil { - t.Error(err) - } -} - -func TestHTMLScrapeCoinbasepro(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "h1", - Key: "id", - Val: "changelog", - TokenDataEnd: "ul", - TextTokenData: "strong", - DateFormat: "01/02/06", - RegExp: "^(\\d){1,2}/(\\d){1,2}/(\\d){2}$", - CheckString: "12/16/19", - Path: "https://docs.pro.coinbase.com/#changelog", - } - _, err := htmlScrapeDefault(&data) - if err != nil { - t.Error(err) - } -} - -func TestHTMLScrapeBitfinex(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{DateFormat: "2006-01-02", RegExp: `section-v-(2\d{3}-\d{1,2}-\d{1,2})`, Path: "https://docs.bitfinex.com/docs/changelog"} - r, err := htmlScrapeBitfinex(&data) - require.NoError(t, err, "htmlScrapeBitfinex must not error") - require.NotEmpty(t, r, "htmlScrapeBitfinex must return a non empty result") -} - -func TestHTMLScrapeBitmex(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "h4", - Key: "id", - Val: "", - TokenDataEnd: "", - TextTokenData: "", - DateFormat: "Jan-2-2006", - RegExp: `([A-Z]{1}[a-z]{2}-\d{1,2}-2\d{3})`, - Path: "https://www.bitmex.com/static/md/en-US/apiChangelog", - } - if _, err := htmlScrapeBitmex(&data); err != nil { - t.Error(err) - } -} - -func TestHTMLScrapeHitBTC(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{RegExp: `newest version \d{1}.\d{1}`, Path: "https://api.hitbtc.com/"} - r, err := htmlScrapeHitBTC(&data) - require.NoError(t, err, "htmlScrapeHitBTC must not error") - require.NotEmpty(t, r, "htmlScrapeHitBTC must return a non empty result") -} - -func TestHTMLScrapeBTSE(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - RegExp: `^version: \d{1}.\d{1}.\d{1}`, - Path: "https://api.btcmarkets.net/openapi/info/index.yaml", - } - if _, err := htmlScrapeBTSE(&data); err != nil { - t.Error(err) - } -} - -func TestHTMLScrapeBTCMarkets(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - RegExp: `^version: \d{1}.\d{1}.\d{1}`, - Path: "https://api.btcmarkets.net/openapi/info/index.yaml", - } - if _, err := htmlScrapeBTCMarkets(&data); err != nil { - t.Error(err) - } -} - -func TestHTMLScrapeBitflyer(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "p", - TokenDataEnd: "h3", - TextTokenData: "code", - RegExp: `^https://api.bitflyer.com/v\d{1}/$`, - Path: "https://lightning.bitflyer.com/docs?lang=en", - } - if _, err := htmlScrapeBitflyer(&data); err != nil { - t.Error(err) - } -} - -func TestHTMLPoloniex(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "h1", - Key: "id", - Val: "changelog", - TokenDataEnd: "div", - TextTokenData: "h2", - DateFormat: "2006-01-02", - RegExp: `(2\d{3}-\d{1,2}-\d{1,2})`, - Path: "https://docs.poloniex.com/#changelog", - } - if _, err := htmlScrapePoloniex(&data); err != nil { - t.Error(err) - } -} - -func TestHTMLScrapeExmo(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - RegExp: `Last updated on [\s\S]*, 20\d{2}`, - Path: "https://exmo.com/en/api/", - } - if _, err := htmlScrapeExmo(&data); err != nil { - t.Error(err) - } -} - -func TestHTMLBitstamp(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - RegExp: `refer to the v\d{1} API for future references.`, - Path: "https://www.bitstamp.net/api/", - } - if _, err := htmlScrapeBitstamp(&data); err != nil { - t.Error(err) - } -} - -func TestHTMLKraken(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "h3", - TokenDataEnd: "p", - TextTokenData: "p", - RegExp: `URL: https://api.kraken.com/\d{1}/private/Balance`, - Path: "https://www.kraken.com/features/api", - } - if _, err := htmlScrapeKraken(&data); err != nil { - t.Error(err) - } -} - -func TestHTMLAlphaPoint(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "h1", - Key: "id", - Val: "introduction", - TokenDataEnd: "blockquote", - TextTokenData: "h3", - RegExp: `revised-calls-\d{1}-\d{1}-\d{1}-gt-\d{1}-\d{1}-\d{1}`, - Path: "https://alphapoint.github.io/slate/#introduction", - } - if _, err := htmlScrapeAlphaPoint(&data); err != nil { - t.Error(err) - } -} - -func TestHTMLYobit(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "h2", - Key: "id", - Path: "https://www.yobit.net/en/api/", - } - if _, err := htmlScrapeYobit(&data); err != nil { - t.Error(err) - } -} - -func TestHTMLScrapeOk(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{ - TokenData: "a", - Key: "href", - Val: "./#change-change", - TokenDataEnd: "./#change-", - RegExp: `./#change-\d{8}`, - Path: "https://www.okx.com/docs/en/", - } - if _, err := htmlScrapeOk(&data); err != nil { - t.Error(err) - } -} - -func TestUpdate(t *testing.T) { - t.Parallel() - var exchCheck, updatedExch HTMLScrapingData - for x := range configData.Exchanges { - if configData.Exchanges[x].Name == "Exmo" { - exchCheck = *configData.Exchanges[x].Data.HTMLData - } - } - info := ExchangeInfo{ - Name: "Exmo", - CheckType: "HTML String Check", - Data: &CheckData{ - HTMLData: &HTMLScrapingData{ - RegExp: `Last updated on [\s\S]*, 20\d{2}`, - Path: "https://exmo.com/en/api/", - }, - }, - } - updatedExchs := update("Exmo", configData.Exchanges, info) - for y := range updatedExchs { - if updatedExchs[y].Name == "Exmo" { - updatedExch = *updatedExchs[y].Data.HTMLData - } - } - if updatedExch == exchCheck { - t.Fatal("update failed") - } -} - -func TestCheckMissingExchanges(t *testing.T) { - t.Parallel() - if a := checkMissingExchanges(); len(a) > len(exchange.Exchanges) { - t.Fatal("invalid response") - } -} - -func TestNameUpdates(t *testing.T) { - t.Parallel() - tester := []struct { - Name string - Status string - ExpectedName string - ErrorExpected bool - }{ - { - Name: "incorrectname", - Status: "incomplete", - ErrorExpected: true, - }, - { - Name: "Gemini 2 2", - Status: "incomplete", - ErrorExpected: false, - }, - { - Name: " Gemini 23", - Status: "incomplete", - ErrorExpected: true, - }, - { - Name: "Gemini 123", - Status: "complete", - ExpectedName: "Gemini 1", - ErrorExpected: false, - }, - { - Name: "Gemini", - Status: "complete", - ExpectedName: "Gemini 1", - ErrorExpected: false, - }, - { - Name: "Gemini 24 ", - Status: "incomplete", - ErrorExpected: false, - }, - } - for x := range tester { - r, err := nameStateChanges(tester[x].Name, tester[x].Status) - if r != tester[x].ExpectedName && err != nil && !tester[x].ErrorExpected { - t.Errorf("%d failed, expected %v, %v, got: %v, %v\n", x, - tester[x].ExpectedName, - tester[x].ErrorExpected, - r, - err) - } - } -} - -func TestReadFileData(t *testing.T) { - t.Parallel() - _, err := readFileData(testJSONFile) - if err != nil { - t.Error(err) - } -} - -func TestGetSha(t *testing.T) { - t.Parallel() - _, err := getSha("binance-exchange/binance-official-api-docs") - if err != nil { - t.Error(err) - } -} - -func TestCheckBoardID(t *testing.T) { - if !areTestAPIKeysSet() { - t.Skip("API Keys unset, skipping") - } - a, err := trelloCheckBoardID() - if err != nil { - t.Error(err) - } - if a != true { - t.Error("no match found for the given boardID") - } -} - -func TestTrelloGetLists(t *testing.T) { - if !areTestAPIKeysSet() { - t.Skip("API Keys unset, skipping") - } - if _, err := trelloGetLists(); err != nil { - t.Error(err) - } -} - -func TestGetAllCards(t *testing.T) { - if !areTestAPIKeysSet() { - t.Skip("API Keys unset, skipping") - } - if _, err := trelloGetAllCards(); err != nil { - t.Error(err) - } -} - -func TestGetAllChecklists(t *testing.T) { - if !areTestAPIKeysSet() { - t.Skip("API Keys unset, skipping") - } - if _, err := trelloGetAllChecklists(); err != nil { - t.Error(err) - } -} - -func TestTrelloGetAllBoards(t *testing.T) { - if !areTestAPIKeysSet() { - t.Skip("API Keys unset, skipping") - } - if trelloBoardID != "" || testBoardName != "" { - t.Skip("trello details empty, skipping") - } - if _, err := trelloGetBoardID(); err != nil { - t.Error(err) - } -} - -func TestCreateNewList(t *testing.T) { - if !areTestAPIKeysSet() { - t.Skip("API Keys unset, skipping") - } - if err := trelloCreateNewList(); err != nil { - t.Error(err) - } -} - -func TestTrelloCreateNewCard(t *testing.T) { - if !areTestAPIKeysSet() { - t.Skip("API Keys unset, skipping") - } - if err := trelloCreateNewCard(); err != nil { - t.Error(err) - } -} - -func TestCreateNewChecklist(t *testing.T) { - if !areTestAPIKeysSet() { - t.Skip("API Keys unset, skipping") - } - if err := trelloCreateNewChecklist(); err != nil { - t.Error(err) - } -} - -func TestWriteAuthVars(t *testing.T) { - if canTestMainFile { - trelloCardID = "jdsfl" - if err := writeAuthVars(testMode); err != nil { - t.Error(err) - } - } -} - -func TestCreateNewCheck(t *testing.T) { - if !canTestTrello() { - t.Skip("cannot test trello, skipping") - } - err := trelloCreateNewCheck("Gemini") - if err != nil { - t.Error(err) - } -} - -func TestUpdateCheckItem(t *testing.T) { - if !canTestTrello() { - t.Skip("cannot test trello, skipping") - } - a, err := trelloGetChecklistItems() - if err != nil { - t.Error(err) - } - var checkID string - for x := range a.CheckItems { - if a.CheckItems[x].Name == "Gemini 1" { - checkID = a.CheckItems[x].ID - } - } - err = trelloUpdateCheckItem(checkID, "Gemini 1", "incomplete") - if err != nil { - t.Error(err) - } -} - -func TestGetChecklistItems(t *testing.T) { - if !canTestTrello() { - t.Skip("cannot test trello, skipping") - } - _, err := trelloGetChecklistItems() - if err != nil { - t.Error(err) - } -} - -func TestSetAuthVars(t *testing.T) { - t.Parallel() - apiKey = "" - configData.Key = "" - apiToken = "" - configData.Token = "" - setAuthVars() - if usageData.Key != "" && usageData.Token != "" { - t.Errorf("incorrect key and token values") - } -} - -func TestTrelloDeleteCheckItems(t *testing.T) { - if !areTestAPIKeysSet() { - t.Skip("API Keys unset, skipping") - } - err := trelloDeleteCheckItem("") - if err != nil { - t.Error(err) - } -} - -func TestHTMLScrapeBinance(t *testing.T) { - data := HTMLScrapingData{ - TokenData: "h1", - Key: "id", - Val: "change-log", - TextTokenData: "strong", - TokenDataEnd: "p", - Path: "https://binance-docs.github.io/apidocs/spot/en/#change-log", - } - _, err := htmlScrapeBinance(&data) - if err != nil { - t.Error(err) - } -} diff --git a/cmd/apichecker/apicheck_types.go b/cmd/apichecker/apicheck_types.go deleted file mode 100644 index e628e57d..00000000 --- a/cmd/apichecker/apicheck_types.go +++ /dev/null @@ -1,100 +0,0 @@ -package main - -// ShaResponse stores raw response from the queries -type ShaResponse struct { - ShaResp string `json:"sha"` -} - -// ExchangeInfo stores exchange info -type ExchangeInfo struct { - Name string - CheckType string - Data *CheckData `json:",omitempty"` - Disabled bool -} - -// CheckData is the necessary data required for checking updates -type CheckData struct { - HTMLData *HTMLScrapingData `json:",omitempty"` - GitHubData *GithubData `json:",omitempty"` -} - -// HTMLScrapingData stores input required for extracting latest update data using HTML -type HTMLScrapingData struct { - TokenData string `json:",omitempty"` - Key string `json:",omitempty"` - Val string `json:",omitempty"` - TokenDataEnd string `json:",omitempty"` - TextTokenData string `json:",omitempty"` - DateFormat string `json:",omitempty"` - RegExp string `json:",omitempty"` - CheckString string `json:",omitempty"` - Path string `json:",omitempty"` -} - -// GithubData stores input required for extracting latest update data -type GithubData struct { - Repo string `json:",omitempty"` - Sha string `json:",omitempty"` -} - -// ListData stores trello lists' required data -type ListData struct { - ID string `json:"id"` - Name string `json:"name"` - IDBoard string `json:"idBoard"` -} - -// CardFill contains data necessary to create a new card -type CardFill struct { - Name string - Desc string - Pos string - Due string - ListID string - MembersID string - LabelsID string - URLSource string -} - -// ItemData stores data of items on a given checklist -type ItemData struct { - State string `json:"state"` - ID string `json:"id"` - Name string `json:"name"` - Position int64 `json:"pos"` -} - -// ChecklistItemData stores items on a given checklist -type ChecklistItemData struct { - ID string `json:"id"` - Name string `json:"name"` - CheckItems []ItemData `json:"checkItems"` -} - -// MembersData saves member's data which includes the boards accessible -type MembersData struct { - Name string `json:"name"` - ShortID string `json:"shortlink"` - ID string `json:"id"` -} - -// Config is a format for storing update data -type Config struct { - CardID string `json:"CardID"` - ChecklistID string `json:"ChecklistID"` - ListID string `json:"ListID"` - BoardID string `json:"BoardID"` - Key string `json:"Key"` - Token string `json:"Token"` - CreateCardName string - CreateListName string - CreateChecklistName string - Exchanges []ExchangeInfo `json:"Exchanges"` -} - -// TrelloData stores data on a given item (board, list, card) -type TrelloData struct { - ID string `json:"id"` - Name string `json:"name"` -} diff --git a/cmd/apichecker/backup.json b/cmd/apichecker/backup.json deleted file mode 100644 index d1af165f..00000000 --- a/cmd/apichecker/backup.json +++ /dev/null @@ -1,391 +0,0 @@ -{ - "CardID": "", - "ChecklistID": "", - "ListID": "", - "BoardID": "", - "Key": "", - "Token": "", - "CreateCardName": "", - "CreateListName": "", - "CreateChecklistName": "", - "Exchanges": [ - { - "Name": "Huobi", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "change-log", - "TokenDataEnd": "h2", - "TextTokenData": "td", - "DateFormat": "2006.01.02 15:04", - "RegExp": "^20(\\d){2}.(\\d){2}.(\\d){2} (\\d){2}:(\\d){2}$", - "CheckString": "2019.12.27 19:00", - "Path": "https://huobiapi.github.io/docs/spot/v1/en/#change-log" - } - }, - "Disabled": false - }, - { - "Name": "Coinbasepro", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "changelog", - "TokenDataEnd": "ul", - "TextTokenData": "strong", - "DateFormat": "01/02/06", - "RegExp": "^(\\d){1,2}/(\\d){1,2}/(\\d){2}$", - "CheckString": "2/20/20", - "Path": "https://docs.pro.coinbase.com/#changelog" - } - }, - "Disabled": false - }, - { - "Name": "Binance", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "binance-exchange/binance-official-api-docs", - "Sha": "4878d48adc0075669ba85033b0e2d40c2876cf56" - } - }, - "Disabled": false - }, - { - "Name": "Bithumb", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "bithumb-pro/bithumb.pro-official-api-docs", - "Sha": "6293502c7736ab4971491978225ef4d104bdff31" - } - }, - "Disabled": false - }, - { - "Name": "Bittrex", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "Bittrex/bittrex.github.io", - "Sha": "fc1ea9c10c48aa82c4dc2c6be74887ef61b5b31b" - } - }, - "Disabled": false - }, - { - "Name": "Coinut", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "coinut/api", - "Sha": "6936dab4d2beba3c8245a603aebf3f545ebcf3f9" - } - }, - "Disabled": false - }, - { - "Name": "Gateio", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "gateio/gateapi-go", - "Sha": "81e2f1bb92c5406853139ae054bbda599483e127" - } - }, - "Disabled": false - }, - { - "Name": "Lbank", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "LBank-exchange/lbank-official-api-docs", - "Sha": "85e7bb83f03d4239c3aad26cabb997a1a2bbb3d1" - } - }, - "Disabled": false - }, - { - "Name": "BTSE", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "btse-spot-api", - "TokenDataEnd": "blockquote", - "TextTokenData": "h1", - "RegExp": "^BTSE Spot API v(\\d){1}.(\\d){1}$", - "CheckString": "BTSE Spot API v3.0.2", - "Path": "https://www.btse.com/apiexplorer/spot/#btse-spot-api" - } - }, - "Disabled": false - }, - { - "Name": "Bitfinex", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "class", - "Val": "header-scroll", - "TokenDataEnd": "p", - "DateFormat": "2006-01-02", - "RegExp": "section-v-(2\\d{3}-\\d{1,2}-\\d{1,2})", - "CheckString": "2019-08-19", - "Path": "https://docs.bitfinex.com/docs/changelog" - } - }, - "Disabled": false - }, - { - "Name": "ANX", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "RegExp": "ANX Exchange API v\\d{1}", - "CheckString": "ANX Exchange API v3", - "Path": "https://anxv3.docs.apiary.io/" - } - }, - "Disabled": false - }, - { - "Name": "Poloniex", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "changelog", - "TokenDataEnd": "div", - "TextTokenData": "h2", - "DateFormat": "2006-01-02", - "RegExp": "(2\\d{3}-\\d{1,2}-\\d{1,2})", - "CheckString": "2020-03-24", - "Path": "https://docs.poloniex.com/#changelog" - } - }, - "Disabled": false - }, - { - "Name": "ItBit", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "a", - "Key": "href", - "RegExp": "^https://api.itbit.com/v\\d{1}/$", - "CheckString": "https://api.itbit.com/v1/", - "Path": "https://api.itbit.com/docs" - } - }, - "Disabled": false - }, - { - "Name": "Bitmex", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h4", - "Key": "id", - "DateFormat": "Jan-2-2006", - "RegExp": "([A-Z]{1}[a-z]{2}-\\d{1,2}-2\\d{3})", - "CheckString": "Dec-16-2019", - "Path": "https://www.bitmex.com/static/md/en-US/apiChangelog" - } - }, - "Disabled": false - }, - { - "Name": "HitBTC", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "about-companyname-api", - "TokenDataEnd": "h2", - "TextTokenData": "p", - "RegExp": "newest version \\d{1}.\\d{1}", - "CheckString": "newest version 2.0", - "Path": "https://api.hitbtc.com/" - } - }, - "Disabled": false - }, - { - "Name": "BTC Markets", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "RegExp": "^version: \\d{1}.\\d{1}.\\d{1}", - "CheckString": "version: 3.0.0", - "Path": "https://api.btcmarkets.net/openapi/info/index.yaml" - } - }, - "Disabled": false - }, - { - "Name": "Bitflyer", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "p", - "TokenDataEnd": "h3", - "TextTokenData": "code", - "RegExp": "^https://api.bitflyer.com/v\\d{1}/$", - "CheckString": "https://api.bitflyer.com/v1/", - "Path": "https://lightning.bitflyer.com/docs?lang=en" - } - }, - "Disabled": false - }, - { - "Name": "Exmo", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "RegExp": "Last updated on [\\s\\S]*, 20\\d{2}", - "CheckString": "Last updated on December, 16th, 2019", - "Path": "https://exmo.com/en/api/" - } - }, - "Disabled": false - }, - { - "Name": "Kraken", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h3", - "TokenDataEnd": "p", - "TextTokenData": "p", - "RegExp": "URL: https://api.kraken.com/\\d{1}/private/Balance", - "CheckString": "URL: https://api.kraken.com/0/private/Balance", - "Path": "https://www.kraken.com/features/api" - } - }, - "Disabled": false - }, - { - "Name": "Bitstamp", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h2", - "Key": "class", - "Val": "text-subtitle mt48", - "TokenDataEnd": "h4", - "TextTokenData": "p", - "RegExp": "refer to the v\\d{1} API for future references.", - "CheckString": "refer to the v2 API for future references.", - "Path": "https://www.bitstamp.net/api/" - } - }, - "Disabled": false - }, - { - "Name": "AlphaPoint", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "introduction", - "TokenDataEnd": "blockquote", - "TextTokenData": "h3", - "RegExp": "revised-calls-\\d{1}-\\d{1}-\\d{1}-gt-\\d{1}-\\d{1}-\\d{1}", - "CheckString": "revised-calls-3-3-2-gt-3-3-3", - "Path": "https://alphapoint.github.io/slate/#introduction" - } - }, - "Disabled": false - }, - { - "Name": "Yobit", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h2", - "Key": "id", - "CheckString": "v3", - "Path": "https://www.yobit.net/en/api/" - } - }, - "Disabled": false - }, - { - "Name": "LocalBitcoins", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "div", - "Key": "class", - "Val": "col-md-12", - "RegExp": "col-md-12([\\s\\S]*?)clearfix", - "CheckString": "37a144dc619776b87c098da5a88bef7fed6c8a7cea2d4b9a38c96750726c93ff", - "Path": "https://localbitcoins.com/api-docs/" - } - }, - "Disabled": false - }, - { - "Name": "OkCoin International", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "a", - "Key": "href", - "Val": "./#change-change", - "TokenDataEnd": "./#change-", - "RegExp": "./#change-\\d{8}", - "CheckString": "20200229", - "Path": "https://www.okcoin.com/docs/en/#change-change" - } - }, - "Disabled": false - }, - { - "Name": "Okex", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "a", - "Key": "href", - "Val": "./#change-change", - "TokenDataEnd": "./#change-", - "RegExp": "./#change-\\d{8}", - "CheckString": "20200331", - "Path": "https://www.okex.com/docs/en/#change-change" - } - }, - "Disabled": false - }, - { - "Name": "Gemini", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "revision-history", - "TokenDataEnd": "table", - "TextTokenData": "td", - "DateFormat": "2006/01/02", - "RegExp": "^20(\\d){2}/(\\d){2}/(\\d){2}$", - "CheckString": "2020/03/05", - "Path": "https://docs.gemini.com/rest-api/#revision-history" - } - }, - "Disabled": false - } - ] -} \ No newline at end of file diff --git a/cmd/apichecker/testupdates.json b/cmd/apichecker/testupdates.json deleted file mode 100644 index 24beb207..00000000 --- a/cmd/apichecker/testupdates.json +++ /dev/null @@ -1,324 +0,0 @@ -{ - "CardID": "", - "ChecklistID": "", - "ListID": "", - "BoardID": "", - "Key": "", - "Token": "", - "CreateCardName": "", - "CreateListName": "", - "CreateChecklistName": "", - "Exchanges": [ - { - "Name": "Huobi", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "change-log", - "TokenDataEnd": "h2", - "TextTokenData": "td", - "DateFormat": "2006.01.02 15:04", - "RegExp": "^20(\\d){2}.(\\d){2}.(\\d){2} (\\d){2}:(\\d){2}$", - "CheckString": "2019.12.27 19:00", - "Path": "https://huobiapi.github.io/docs/spot/v1/en/#change-log" - } - }, - "Disabled": false - }, - { - "Name": "Coinbasepro", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "changelog", - "TokenDataEnd": "ul", - "TextTokenData": "strong", - "DateFormat": "01/02/06", - "RegExp": "^(\\d){1,2}/(\\d){1,2}/(\\d){2}$", - "CheckString": "2/20/20", - "Path": "https://docs.pro.coinbase.com/#changelog" - } - }, - "Disabled": false - }, - { - "Name": "Binance", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "change-log", - "TokenDataEnd": "p", - "TextTokenData": "strong", - "CheckString": "2020-05-06", - "Path": "https://binance-docs.github.io/apidocs/spot/en/#change-log" - } - }, - "Disabled": false - }, - { - "Name": "Bithumb", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "bithumb-pro/bithumb.pro-official-api-docs", - "Sha": "6293502c7736ab4971491978225ef4d104bdff31" - } - }, - "Disabled": false - }, - { - "Name": "Coinut", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "coinut/api", - "Sha": "6936dab4d2beba3c8245a603aebf3f545ebcf3f9" - } - }, - "Disabled": false - }, - { - "Name": "Gateio", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "gateio/gateapi-go", - "Sha": "81e2f1bb92c5406853139ae054bbda599483e127" - } - }, - "Disabled": false - }, - { - "Name": "Lbank", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "LBank-exchange/lbank-official-api-docs", - "Sha": "85e7bb83f03d4239c3aad26cabb997a1a2bbb3d1" - } - }, - "Disabled": false - }, - { - "Name": "BTSE", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "btse-spot-api", - "TokenDataEnd": "blockquote", - "TextTokenData": "h1", - "RegExp": "^BTSE Spot API v(\\d){1}.(\\d){1}$", - "CheckString": "BTSE Spot API v3.0.2", - "Path": "https://www.btse.com/apiexplorer/spot/#btse-spot-api" - } - }, - "Disabled": false - }, - { - "Name": "Bitfinex", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "class", - "Val": "header-scroll", - "TokenDataEnd": "p", - "DateFormat": "2006-01-02", - "RegExp": "section-v-(2\\d{3}-\\d{1,2}-\\d{1,2})", - "CheckString": "2019-08-19", - "Path": "https://docs.bitfinex.com/docs/changelog" - } - }, - "Disabled": false - }, - { - "Name": "ANX", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "RegExp": "ANX Exchange API v\\d{1}", - "CheckString": "ANX Exchange API v3", - "Path": "https://anxv3.docs.apiary.io/" - } - }, - "Disabled": false - }, - { - "Name": "Poloniex", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "changelog", - "TokenDataEnd": "div", - "TextTokenData": "h2", - "DateFormat": "2006-01-02", - "RegExp": "(2\\d{3}-\\d{1,2}-\\d{1,2})", - "CheckString": "2020-03-24", - "Path": "https://docs.poloniex.com/#changelog" - } - }, - "Disabled": false - }, - { - "Name": "Bitmex", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h4", - "Key": "id", - "DateFormat": "Jan-2-2006", - "RegExp": "([A-Z]{1}[a-z]{2}-\\d{1,2}-2\\d{3})", - "CheckString": "Dec-16-2019", - "Path": "https://www.bitmex.com/static/md/en-US/apiChangelog" - } - }, - "Disabled": false - }, - { - "Name": "HitBTC", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "about-companyname-api", - "TokenDataEnd": "h2", - "TextTokenData": "p", - "RegExp": "newest version \\d{1}.\\d{1}", - "CheckString": "newest version 2.0", - "Path": "https://api.hitbtc.com/" - } - }, - "Disabled": false - }, - { - "Name": "BTC Markets", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "RegExp": "^version: \\d{1}.\\d{1}.\\d{1}", - "CheckString": "version: 3.0.0", - "Path": "https://api.btcmarkets.net/openapi/info/index.yaml" - } - }, - "Disabled": false - }, - { - "Name": "Bitflyer", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "p", - "TokenDataEnd": "h3", - "TextTokenData": "code", - "RegExp": "^https://api.bitflyer.com/v\\d{1}/$", - "CheckString": "https://api.bitflyer.com/v1/", - "Path": "https://lightning.bitflyer.com/docs?lang=en" - } - }, - "Disabled": false - }, - { - "Name": "Exmo", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "RegExp": "Last updated on [\\s\\S]*, 20\\d{2}", - "CheckString": "Last updated on December, 16th, 2019", - "Path": "https://exmo.com/en/api/" - } - }, - "Disabled": false - }, - { - "Name": "Kraken", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h3", - "TokenDataEnd": "p", - "TextTokenData": "p", - "RegExp": "URL: https://api.kraken.com/\\d{1}/private/Balance", - "CheckString": "URL: https://api.kraken.com/0/private/Balance", - "Path": "https://www.kraken.com/features/api" - } - }, - "Disabled": false - }, - { - "Name": "Bitstamp", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h2", - "Key": "class", - "Val": "text-subtitle mt48", - "TokenDataEnd": "h4", - "TextTokenData": "p", - "RegExp": "refer to the v\\d{1} API for future references.", - "CheckString": "refer to the v2 API for future references.", - "Path": "https://www.bitstamp.net/api/" - } - }, - "Disabled": false - }, - { - "Name": "AlphaPoint", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "introduction", - "TokenDataEnd": "blockquote", - "TextTokenData": "h3", - "RegExp": "revised-calls-\\d{1}-\\d{1}-\\d{1}-gt-\\d{1}-\\d{1}-\\d{1}", - "CheckString": "revised-calls-3-3-2-gt-3-3-3", - "Path": "https://alphapoint.github.io/slate/#introduction" - } - }, - "Disabled": false - }, - { - "Name": "Yobit", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h2", - "Key": "id", - "CheckString": "v3", - "Path": "https://www.yobit.net/en/api/" - } - }, - "Disabled": false - }, - { - "Name": "Gemini", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "revision-history", - "TokenDataEnd": "table", - "TextTokenData": "td", - "DateFormat": "2006/01/02", - "RegExp": "^20(\\d){2}/(\\d){2}/(\\d){2}$", - "CheckString": "2020/03/05", - "Path": "https://docs.gemini.com/rest-api/#revision-history" - } - }, - "Disabled": false - } - ] -} \ No newline at end of file diff --git a/cmd/apichecker/updates.json b/cmd/apichecker/updates.json deleted file mode 100644 index 86365592..00000000 --- a/cmd/apichecker/updates.json +++ /dev/null @@ -1,324 +0,0 @@ -{ - "CardID": "", - "ChecklistID": "", - "ListID": "", - "BoardID": "", - "Key": "", - "Token": "", - "CreateCardName": "", - "CreateListName": "", - "CreateChecklistName": "", - "Exchanges": [ - { - "Name": "Huobi", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "change-log", - "TokenDataEnd": "h2", - "TextTokenData": "td", - "DateFormat": "2006.01.02 15:04", - "RegExp": "^20(\\d){2}.(\\d){2}.(\\d){2} (\\d){2}:(\\d){2}$", - "CheckString": "2019.12.27 19:00", - "Path": "https://huobiapi.github.io/docs/spot/v1/en/#change-log" - } - }, - "Disabled": false - }, - { - "Name": "Coinbasepro", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "changelog", - "TokenDataEnd": "ul", - "TextTokenData": "strong", - "DateFormat": "01/02/06", - "RegExp": "^(\\d){1,2}/(\\d){1,2}/(\\d){2}$", - "CheckString": "2/20/20", - "Path": "https://docs.pro.coinbase.com/#changelog" - } - }, - "Disabled": false - }, - { - "Name": "Binance", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "change-log", - "TokenDataEnd": "p", - "TextTokenData": "strong", - "CheckString": "2020-05-06", - "Path": "https://binance-docs.github.io/apidocs/spot/en/#change-log" - } - }, - "Disabled": false - }, - { - "Name": "Bithumb", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "bithumb-pro/bithumb.pro-official-api-docs", - "Sha": "6293502c7736ab4971491978225ef4d104bdff31" - } - }, - "Disabled": false - }, - { - "Name": "Coinut", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "coinut/api", - "Sha": "6936dab4d2beba3c8245a603aebf3f545ebcf3f9" - } - }, - "Disabled": false - }, - { - "Name": "Gateio", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "gateio/gateapi-go", - "Sha": "81e2f1bb92c5406853139ae054bbda599483e127" - } - }, - "Disabled": false - }, - { - "Name": "Lbank", - "CheckType": "GitHub Sha Check", - "Data": { - "GitHubData": { - "Repo": "LBank-exchange/lbank-official-api-docs", - "Sha": "85e7bb83f03d4239c3aad26cabb997a1a2bbb3d1" - } - }, - "Disabled": false - }, - { - "Name": "BTSE", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "btse-spot-api", - "TokenDataEnd": "blockquote", - "TextTokenData": "h1", - "RegExp": "^BTSE Spot API v(\\d){1}.(\\d){1}$", - "CheckString": "BTSE Spot API v3.0.2", - "Path": "https://www.btse.com/apiexplorer/spot/#btse-spot-api" - } - }, - "Disabled": false - }, - { - "Name": "Bitfinex", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "class", - "Val": "header-scroll", - "TokenDataEnd": "p", - "DateFormat": "2006-01-02", - "RegExp": "section-v-(2\\d{3}-\\d{1,2}-\\d{1,2})", - "CheckString": "2019-08-19", - "Path": "https://docs.bitfinex.com/docs/changelog" - } - }, - "Disabled": false - }, - { - "Name": "ANX", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "RegExp": "ANX Exchange API v\\d{1}", - "CheckString": "ANX Exchange API v3", - "Path": "https://anxv3.docs.apiary.io/" - } - }, - "Disabled": false - }, - { - "Name": "Poloniex", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "changelog", - "TokenDataEnd": "div", - "TextTokenData": "h2", - "DateFormat": "2006-01-02", - "RegExp": "(2\\d{3}-\\d{1,2}-\\d{1,2})", - "CheckString": "2020-03-24", - "Path": "https://docs.poloniex.com/#changelog" - } - }, - "Disabled": false - }, - { - "Name": "Bitmex", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h4", - "Key": "id", - "DateFormat": "Jan-2-2006", - "RegExp": "([A-Z]{1}[a-z]{2}-\\d{1,2}-2\\d{3})", - "CheckString": "Dec-16-2019", - "Path": "https://www.bitmex.com/static/md/en-US/apiChangelog" - } - }, - "Disabled": false - }, - { - "Name": "HitBTC", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "about-companyname-api", - "TokenDataEnd": "h2", - "TextTokenData": "p", - "RegExp": "newest version \\d{1}.\\d{1}", - "CheckString": "newest version 2.0", - "Path": "https://api.hitbtc.com/" - } - }, - "Disabled": false - }, - { - "Name": "BTC Markets", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "RegExp": "^version: \\d{1}.\\d{1}.\\d{1}", - "CheckString": "version: 3.0.0", - "Path": "https://api.btcmarkets.net/openapi/info/index.yaml" - } - }, - "Disabled": false - }, - { - "Name": "Bitflyer", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "p", - "TokenDataEnd": "h3", - "TextTokenData": "code", - "RegExp": "^https://api.bitflyer.com/v\\d{1}/$", - "CheckString": "https://api.bitflyer.com/v1/", - "Path": "https://lightning.bitflyer.com/docs?lang=en" - } - }, - "Disabled": false - }, - { - "Name": "Exmo", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "RegExp": "Last updated on [\\s\\S]*, 20\\d{2}", - "CheckString": "Last updated on December, 16th, 2019", - "Path": "https://exmo.com/en/api/" - } - }, - "Disabled": false - }, - { - "Name": "Kraken", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h3", - "TokenDataEnd": "p", - "TextTokenData": "p", - "RegExp": "URL: https://api.kraken.com/\\d{1}/private/Balance", - "CheckString": "URL: https://api.kraken.com/0/private/Balance", - "Path": "https://www.kraken.com/features/api" - } - }, - "Disabled": false - }, - { - "Name": "Bitstamp", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h2", - "Key": "class", - "Val": "text-subtitle mt48", - "TokenDataEnd": "h4", - "TextTokenData": "p", - "RegExp": "refer to the v\\d{1} API for future references.", - "CheckString": "refer to the v2 API for future references.", - "Path": "https://www.bitstamp.net/api/" - } - }, - "Disabled": false - }, - { - "Name": "AlphaPoint", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "introduction", - "TokenDataEnd": "blockquote", - "TextTokenData": "h3", - "RegExp": "revised-calls-\\d{1}-\\d{1}-\\d{1}-gt-\\d{1}-\\d{1}-\\d{1}", - "CheckString": "revised-calls-3-3-2-gt-3-3-3", - "Path": "https://alphapoint.github.io/slate/#introduction" - } - }, - "Disabled": false - }, - { - "Name": "Yobit", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h2", - "Key": "id", - "CheckString": "v3", - "Path": "https://www.yobit.net/en/api/" - } - }, - "Disabled": false - }, - { - "Name": "Gemini", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "h1", - "Key": "id", - "Val": "revision-history", - "TokenDataEnd": "table", - "TextTokenData": "td", - "DateFormat": "2006/01/02", - "RegExp": "^20(\\d){2}/(\\d){2}/(\\d){2}$", - "CheckString": "2020/03/05", - "Path": "https://docs.gemini.com/rest-api/#revision-history" - } - }, - "Disabled": false - } - ] -} \ No newline at end of file diff --git a/cmd/documentation/cmd_templates/apichecker.tmpl b/cmd/documentation/cmd_templates/apichecker.tmpl deleted file mode 100644 index 023d9099..00000000 --- a/cmd/documentation/cmd_templates/apichecker.tmpl +++ /dev/null @@ -1,98 +0,0 @@ -{{define "cmd apichecker" -}} -{{template "header" .}} -## Current Features for {{.Name}} - -+ Checks for API updates -+ Can automatically update Trello checklist for the updates required -+ Supports trello integration - -#### This tool tracks changes in exchange API documentation -#### Keeps track of all the updates using the GoCryptoTrader trello board - -Be aware, this tool will: -- Automatically update the live trello board if API keys and trello information are provided. -- Automatically update the main json updates file, however a backup of the copy before the updates will be stored. - -## Usage - -+ To run a real check for updates, parse Trello API info as flags or add them to the updates.json file and use the following command from apichecker folder in GCT: - -###### Linux/OSX -GoCryptoTrader is built using [Go Modules](https://github.com/golang/go/wiki/Modules) and requires Go 1.11 or above -Using Go Modules you now clone this repository **outside** your GOPATH - -```bash -git clone https://github.com/thrasher-corp/gocryptotrader.git -cd gocryptotrader/cmd/apichecker -go build -./apichecker -``` - -###### Windows - -```bash -git clone https://github.com/thrasher-corp/gocryptotrader.git -cd gocryptotrader\cmd\apichecker -go build && apichecker.exe -``` - -+ Upon addition of a new exchange, to update Trello checklist and to add the exchange to updates.json the following would need to be done: - -###### HTML Scraping method: -HTMLScrapingData is a struct which contains the necessary information to scrape data from the given path website. Not all the elements of HTMLScrapingData are necessary, its all dependent on site where information is being extracted from. Regexp is used to capture necessary bits of data using r.FindString() where r is the declared regular expression. If update dates data is available, DateFormat is used to convert the dates to a more standard format which can then be used for further comparisons of which update is most recent. -```go -func TestAdd(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{TokenData: "h1", - Key: "id", - Val: "revision-history", - TokenDataEnd: "table", - TextTokenData: "td", - DateFormat: "2006/01/02", - RegExp: "^20(\\d){2}/(\\d){2}/(\\d){2}$", - CheckString: "2019/11/15", - Path: "https://docs.gemini.com/rest-api/#revision-history"} - err := Add("Gemini", htmlScrape, data.Path, data, true, &testConfigData) - if err != nil { - t.Error(err) - } -} -``` - -###### Github SHA Check Method: -```go -func TestAdd(t *testing.T) { - t.Parallel() - data := GithubData{Repo: "LBank-exchange/lbank-official-api-docs"} - err := Add("Lbank", github, fmt.Sprintf(githubPath, data.Repo), data, false, &configData) - if err != nil { - t.Error(err) - } -} -``` - -###### Add using flags: -```bash -apichecker.exe -add=true -key=id -val=revision-history -tokendata=h1 -tokendataend=table -texttokendata=td -dateformat=2006/01/02 -checktype="HTML String Check" -regexp="^20(\d){2}/(\d){2}/(\d){2}$" -path="https://docs.gemini.com/rest-api/#revision-history" -exchangename=Gemini -``` - -+ If all the authentication variables for trello are set trello checklist will be automatically updated with the format of 'Exchange Name (integer of how many updates have been released since the exchange API was last worked on): - -- To acquire your trello key and access token please login into trello using the following link and follow the steps: https://trello.com/app-key - -- To acquire BoardID, ListID, CardID and ChecklistID inbuilt functions can be used such as trelloGetAllLists() - -- To create a new list, card, checklist, and to populate the the checklist --create flag can be used. - -- To create a new check within a checklist, an inbuilt function within apichecker can be used: trelloCreateNewCheck - -- For the first time running the application & to create a list, card and checklist use the following: -```bash -apichecker.exe --create -apikey="insertkeyhere" -apitoken="inserttokenhere" -boardname="insertboardnamehere" -``` - - -### Please click GoDocs chevron above to view current GoDoc information for this package -{{template "contributions"}} -{{template "donations" .}} -{{end}} \ No newline at end of file