mirror of https://github.com/statping/statping
				
				
				
			Merge branch 'master' into line-notify
						commit
						82f2c47c8d
					
				| 
						 | 
				
			
			@ -4,7 +4,7 @@ os:
 | 
			
		|||
language: go
 | 
			
		||||
 | 
			
		||||
go:
 | 
			
		||||
  - "1.10.x"
 | 
			
		||||
  - "1.10.3"
 | 
			
		||||
 | 
			
		||||
go_import_path: github.com/hunterlong/statup
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,14 @@
 | 
			
		|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:b62a3c5b37db602bf1158e921da1a762315a4c37855fd418a14498aa87a342d5"
 | 
			
		||||
  name = "cloud.google.com/go"
 | 
			
		||||
  packages = ["civil"]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad"
 | 
			
		||||
  version = "v0.27.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:65796e5fdb94d94bc0ee6bc422aa3541dbe69ed4da275cb5a27f8fa141f4e35c"
 | 
			
		||||
| 
						 | 
				
			
			@ -13,12 +21,20 @@
 | 
			
		|||
  revision = "c02ca9a983da5807ddf7d796784928f5be4afd09"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:4b79025e1eaa5726b92e409a46571f1998b56f0a2d881d6271ca616095eae46e"
 | 
			
		||||
  digest = "1:e92f5581902c345eb4ceffdcd4a854fb8f73cf436d47d837d1ec98ef1fe0a214"
 | 
			
		||||
  name = "github.com/StackExchange/wmi"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "5d049714c4a64225c3c79a7cf7d02f7fb5b96338"
 | 
			
		||||
  version = "1.0.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:f1ec92a2b8473612547f6e13edbc8c8e6cda6c8be9c54b31958aad4a7ccaaa2b"
 | 
			
		||||
  name = "github.com/ararog/timeago"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "e9969cf18b8d5f04cc42f050e8b9968e152cd294"
 | 
			
		||||
  revision = "518814407569bf983ea81e1bf8b550dd4e7b34f3"
 | 
			
		||||
  version = "0.0.1"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
| 
						 | 
				
			
			@ -29,28 +45,50 @@
 | 
			
		|||
  revision = "a5fe2436ffcb3236e175e5149162b41cd28bd27d"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
 | 
			
		||||
  digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
 | 
			
		||||
  name = "github.com/davecgh/go-spew"
 | 
			
		||||
  packages = ["spew"]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "346938d642f2ec3594ed81d874461961cd0faa76"
 | 
			
		||||
  version = "v1.1.0"
 | 
			
		||||
  revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
 | 
			
		||||
  version = "v1.1.1"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:14f498fc55a89776c562fa3510aeb7687356944a560c561c0e617af5f9c5f2c7"
 | 
			
		||||
  digest = "1:6f120164f62e62991d0f85562abe2002d438abb2ca80b7717a2f4ae2af1c6829"
 | 
			
		||||
  name = "github.com/denisenkom/go-mssqldb"
 | 
			
		||||
  packages = [
 | 
			
		||||
    ".",
 | 
			
		||||
    "internal/cp",
 | 
			
		||||
  ]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "1eb28afdf9b6e56cf673badd47545f844fe81103"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:ca82a3b99694824c627573c2a76d0e49719b4a9c02d1d85a2ac91f1c1f52ab9b"
 | 
			
		||||
  name = "github.com/fatih/structs"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "ebf56d35bba727c68ac77f56f2fcf90b181851aa"
 | 
			
		||||
  revision = "a720dfa8df582c51dee1b36feabb906bde1588bd"
 | 
			
		||||
  version = "v1.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:70a20b8adf085489a342d033b68b7fc27f4017c51e015b857387249493ee0561"
 | 
			
		||||
  digest = "1:64a5a67c69b70c2420e607a8545d674a23778ed9c3e80607bfd17b77c6c87f6a"
 | 
			
		||||
  name = "github.com/go-ole/go-ole"
 | 
			
		||||
  packages = [
 | 
			
		||||
    ".",
 | 
			
		||||
    "oleutil",
 | 
			
		||||
  ]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "a41e3c4b706f6ae8dfbff342b06e40fa4d2d0506"
 | 
			
		||||
  version = "v1.2.1"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:adea5a94903eb4384abef30f3d878dc9ff6b6b5b0722da25b82e5169216dfb61"
 | 
			
		||||
  name = "github.com/go-sql-driver/mysql"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "99ff426eb706cffe92ff3d058e168b278cabf7c7"
 | 
			
		||||
  revision = "d523deb1b23d913de5bdada721a6071e71283618"
 | 
			
		||||
  version = "v1.4.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
 | 
			
		||||
| 
						 | 
				
			
			@ -69,35 +107,74 @@
 | 
			
		|||
  version = "v1.1.1"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:195b71563f8432dac9d9692aca2a9ae098bc35763999573eb1c7d52a02a47ce7"
 | 
			
		||||
  digest = "1:664d37ea261f0fc73dd17f4a1f5f46d01fbb0b0d75f6375af064824424109b7d"
 | 
			
		||||
  name = "github.com/gorilla/handlers"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "7e0847f9db758cdebd26c149d0ae9d5d0b9c98ce"
 | 
			
		||||
  version = "v1.4.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:e73f5b0152105f18bc131fba127d9949305c8693f8a762588a82a48f61756f5f"
 | 
			
		||||
  name = "github.com/gorilla/mux"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "cb4698366aa625048f3b815af6a0dea8aef9280a"
 | 
			
		||||
  revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
 | 
			
		||||
  version = "v1.6.2"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:6e0af49591c81ae6d542fd0ba41ea7206f4242471b384bebd206283b9f38e091"
 | 
			
		||||
  digest = "1:e72d1ebb8d395cf9f346fd9cbc652e5ae222dd85e0ac842dc57f175abed6d195"
 | 
			
		||||
  name = "github.com/gorilla/securecookie"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "78f3d318a8bf316cda921f25e96fd0b441c5173d"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:0fe783ea0c04c7d13f7c55d8f74b01b17e18a8320e7deecf578b41ef99b27205"
 | 
			
		||||
  name = "github.com/gorilla/sessions"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "03b6f63cc43ef9c7240a635a5e22b13180e822b8"
 | 
			
		||||
  revision = "e59506cc896acb7f7bf732d4fdf5e25f7ccd8983"
 | 
			
		||||
  version = "v1.1.1"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:0aa142ca3543fa3aca344c2fa2d52e01d706a3ce4e1fa893e0ef29b5349ddf7a"
 | 
			
		||||
  name = "github.com/gorilla/sessions"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "81547393f870a35be888759a606ba7bf71dbe5c7"
 | 
			
		||||
  version = "v1.1.2"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d"
 | 
			
		||||
  name = "github.com/gorilla/websocket"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
 | 
			
		||||
  version = "v1.4.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:4d28d632da146ec6e632bdd29676a95e0874f1ad837fff06aef6610b3b6b4728"
 | 
			
		||||
  name = "github.com/jinzhu/gorm"
 | 
			
		||||
  packages = [
 | 
			
		||||
    ".",
 | 
			
		||||
    "dialects/mssql",
 | 
			
		||||
    "dialects/mysql",
 | 
			
		||||
    "dialects/postgres",
 | 
			
		||||
    "dialects/sqlite",
 | 
			
		||||
  ]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "6ed508ec6a4ecb3531899a69cbc746ccf65a4166"
 | 
			
		||||
  version = "v1.9.1"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:d166a4b3543a71d87e34767ace94e8b516e79ba45111730306f07c8d6f797f1f"
 | 
			
		||||
  digest = "1:fd97437fbb6b7dce04132cf06775bd258cce305c44add58eb55ca86c6c325160"
 | 
			
		||||
  name = "github.com/jinzhu/inflection"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "04140366298a54a039076d798123ffa108fff46c"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:70e697d67ccaec45e16bac3a32380ebcd9e7e071079c60d0171d42cf1cf9748a"
 | 
			
		||||
  name = "github.com/joho/godotenv"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "1709ab122c988931ad53508747b3c061400c2984"
 | 
			
		||||
  revision = "a79fa1e548e2c689c241d10173efd51e5d689d5b"
 | 
			
		||||
  version = "v1.2.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
| 
						 | 
				
			
			@ -108,31 +185,43 @@
 | 
			
		|||
  revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:37ce7d7d80531b227023331002c0d42b4b4b291a96798c82a049d03a54ba79e4"
 | 
			
		||||
  digest = "1:b18ffc558326ebaed3b4a175617f1e12ed4e3f53d6ebfe5ba372a3de16d22278"
 | 
			
		||||
  name = "github.com/lib/pq"
 | 
			
		||||
  packages = [
 | 
			
		||||
    ".",
 | 
			
		||||
    "hstore",
 | 
			
		||||
    "oid",
 | 
			
		||||
  ]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "90697d60dd844d5ef6ff15135d0203f65d2f53b8"
 | 
			
		||||
  revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
 | 
			
		||||
  version = "v1.0.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:05b7bf6e275fe5d56f479a944d1fd823437f6a2739610ae8359e137690d0a050"
 | 
			
		||||
  digest = "1:3cafc6a5a1b8269605d9df4c6956d43d8011fc57f266ca6b9d04da6c09dee548"
 | 
			
		||||
  name = "github.com/mattn/go-sqlite3"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "b3511bfdd742af558b54eb6160aca9446d762a19"
 | 
			
		||||
  revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4"
 | 
			
		||||
  version = "v1.9.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:3891cc78541df6e4596b3e73978eb062d32967084069270ec881b959be5155ae"
 | 
			
		||||
  digest = "1:4f4fd75cbdd5ad0696f4d762328f094b9c86061323c9a9f8d0de157f06197e89"
 | 
			
		||||
  name = "github.com/mkevac/debugcharts"
 | 
			
		||||
  packages = [
 | 
			
		||||
    ".",
 | 
			
		||||
    "bindata",
 | 
			
		||||
  ]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "d3203a8fa92649b82dc35c214979861de918874a"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
 | 
			
		||||
  name = "github.com/pkg/errors"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "816c9085562cd7ee03e7f8188a1cfd942858cded"
 | 
			
		||||
  revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
 | 
			
		||||
  version = "v0.8.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
 | 
			
		||||
| 
						 | 
				
			
			@ -150,6 +239,29 @@
 | 
			
		|||
  pruneopts = "UT"
 | 
			
		||||
  revision = "6283090d169f51a2410b4e260341a01c9a4c0ca7"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:7395b855a6078ad2e6c40311402a057a91125fb9f32cf228e1b32cdc57c33538"
 | 
			
		||||
  name = "github.com/shirou/gopsutil"
 | 
			
		||||
  packages = [
 | 
			
		||||
    "cpu",
 | 
			
		||||
    "host",
 | 
			
		||||
    "internal/common",
 | 
			
		||||
    "mem",
 | 
			
		||||
    "net",
 | 
			
		||||
    "process",
 | 
			
		||||
  ]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "8048a2e9c5773235122027dd585cf821b2af1249"
 | 
			
		||||
  version = "v2.18.07"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:99c6a6dab47067c9b898e8c8b13d130c6ab4ffbcc4b7cc6236c2cd0b1e344f5b"
 | 
			
		||||
  name = "github.com/shirou/w32"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "bb4de0191aa41b5507caa14b0650cdbddcd9280b"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83"
 | 
			
		||||
  name = "github.com/stretchr/testify"
 | 
			
		||||
| 
						 | 
				
			
			@ -159,14 +271,27 @@
 | 
			
		|||
  version = "v1.2.2"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:1ecf2a49df33be51e757d0033d5d51d5f784f35f68e5a38f797b2d3f03357d71"
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:68344dbfaa4179bb50a583eb8172ace3f1edaf3aebc24e68c03f549f6e6b60dc"
 | 
			
		||||
  name = "golang.org/x/crypto"
 | 
			
		||||
  packages = [
 | 
			
		||||
    "bcrypt",
 | 
			
		||||
    "blowfish",
 | 
			
		||||
    "md4",
 | 
			
		||||
  ]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "c126467f60eb25f8f27e5a981f32a87e3965053f"
 | 
			
		||||
  revision = "0709b304e793a5edb4a2c0145f281ecdc20838a4"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:7f4a61b989d94774dc61016b660cf8347f59eb0bed91a10b2f23fc72a38d45d4"
 | 
			
		||||
  name = "golang.org/x/sys"
 | 
			
		||||
  packages = [
 | 
			
		||||
    "unix",
 | 
			
		||||
    "windows",
 | 
			
		||||
  ]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "ebe1bf3edb3325c393447059974de898d5133eb8"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:c25289f43ac4a68d88b02245742347c94f1e108c534dda442188015ff80669b3"
 | 
			
		||||
| 
						 | 
				
			
			@ -185,12 +310,12 @@
 | 
			
		|||
  revision = "2caba252f4dc53eaf6b553000885530023f54623"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "v2"
 | 
			
		||||
  digest = "1:e096ada745e034a059752c202717baee0379b69db9473a90f59d103c973384cf"
 | 
			
		||||
  digest = "1:eebd52aee67d9f1e0af1859a584e14b1817581dd5f90d4585418c27b6a93c966"
 | 
			
		||||
  name = "gopkg.in/gomail.v2"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "81ebce5c23dfd25c6c67194b37d3dd3f338c98b1"
 | 
			
		||||
  revision = "41f3572897373c5538c50a2402db15db079fa4fd"
 | 
			
		||||
  version = "2.0.0"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:c805e517269b0ba4c21ded5836019ed7d16953d4026cb7d00041d039c7906be9"
 | 
			
		||||
| 
						 | 
				
			
			@ -201,25 +326,21 @@
 | 
			
		|||
  version = "v2.1"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:0d1f3aba6c5c26e67b090b4eed519582fba0dff24d3e486fcb011d84ca3e7806"
 | 
			
		||||
  digest = "1:0a6ab450a46e158a97e3daf7da9df3bfd4f84420047fab6a65fb70b1337ce026"
 | 
			
		||||
  name = "upper.io/db.v3"
 | 
			
		||||
  packages = [
 | 
			
		||||
    ".",
 | 
			
		||||
    "internal/cache",
 | 
			
		||||
    "internal/cache/hashstructure",
 | 
			
		||||
    "internal/immutable",
 | 
			
		||||
    "internal/sqladapter",
 | 
			
		||||
    "internal/sqladapter/compat",
 | 
			
		||||
    "internal/sqladapter/exql",
 | 
			
		||||
    "lib/reflectx",
 | 
			
		||||
    "lib/sqlbuilder",
 | 
			
		||||
    "mysql",
 | 
			
		||||
    "postgresql",
 | 
			
		||||
    "sqlite",
 | 
			
		||||
  ]
 | 
			
		||||
  pruneopts = "UT"
 | 
			
		||||
  revision = "d90922beee6de3f39c93ed677f6da82565d07154"
 | 
			
		||||
  version = "v3.5.3"
 | 
			
		||||
  revision = "199d13d76c7cfba05ea0327375056fdabc8bea80"
 | 
			
		||||
  version = "v3.5.4"
 | 
			
		||||
 | 
			
		||||
[solve-meta]
 | 
			
		||||
  analyzer-name = "dep"
 | 
			
		||||
| 
						 | 
				
			
			@ -230,20 +351,23 @@
 | 
			
		|||
    "github.com/ararog/timeago",
 | 
			
		||||
    "github.com/fatih/structs",
 | 
			
		||||
    "github.com/go-yaml/yaml",
 | 
			
		||||
    "github.com/gorilla/handlers",
 | 
			
		||||
    "github.com/gorilla/mux",
 | 
			
		||||
    "github.com/gorilla/sessions",
 | 
			
		||||
    "github.com/jinzhu/gorm",
 | 
			
		||||
    "github.com/jinzhu/gorm/dialects/mssql",
 | 
			
		||||
    "github.com/jinzhu/gorm/dialects/mysql",
 | 
			
		||||
    "github.com/jinzhu/gorm/dialects/postgres",
 | 
			
		||||
    "github.com/jinzhu/gorm/dialects/sqlite",
 | 
			
		||||
    "github.com/joho/godotenv",
 | 
			
		||||
    "github.com/mkevac/debugcharts",
 | 
			
		||||
    "github.com/pkg/errors",
 | 
			
		||||
    "github.com/rendon/testcli",
 | 
			
		||||
    "github.com/stretchr/testify/assert",
 | 
			
		||||
    "golang.org/x/crypto/bcrypt",
 | 
			
		||||
    "gopkg.in/gomail.v2",
 | 
			
		||||
    "gopkg.in/natefinch/lumberjack.v2",
 | 
			
		||||
    "upper.io/db.v3",
 | 
			
		||||
    "upper.io/db.v3/lib/sqlbuilder",
 | 
			
		||||
    "upper.io/db.v3/mysql",
 | 
			
		||||
    "upper.io/db.v3/postgresql",
 | 
			
		||||
    "upper.io/db.v3/sqlite",
 | 
			
		||||
  ]
 | 
			
		||||
  solver-name = "gps-cdcl"
 | 
			
		||||
  solver-version = 1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										32
									
								
								Gopkg.toml
								
								
								
								
							
							
						
						
									
										32
									
								
								Gopkg.toml
								
								
								
								
							| 
						 | 
				
			
			@ -30,28 +30,44 @@
 | 
			
		|||
  name = "github.com/GeertJohan/go.rice"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  name = "github.com/ararog/timeago"
 | 
			
		||||
  version = "0.0.1"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  name = "github.com/fatih/structs"
 | 
			
		||||
  version = "1.0.0"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "github.com/go-yaml/yaml"
 | 
			
		||||
  version = "2.2.1"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "github.com/gorilla/handlers"
 | 
			
		||||
  version = "1.4.0"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "github.com/gorilla/mux"
 | 
			
		||||
  version = "1.6.2"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "github.com/gorilla/sessions"
 | 
			
		||||
  version = "1.1.1"
 | 
			
		||||
  version = "1.1.2"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "github.com/jinzhu/gorm"
 | 
			
		||||
  version = "1.9.1"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  name = "github.com/joho/godotenv"
 | 
			
		||||
  version = "1.2.0"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  name = "github.com/mkevac/debugcharts"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "github.com/pkg/errors"
 | 
			
		||||
  version = "0.8.0"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
| 
						 | 
				
			
			@ -62,8 +78,12 @@
 | 
			
		|||
  version = "1.2.2"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  branch = "v2"
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  name = "golang.org/x/crypto"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "gopkg.in/gomail.v2"
 | 
			
		||||
  version = "2.0.0"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "gopkg.in/natefinch/lumberjack.v2"
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +91,7 @@
 | 
			
		|||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "upper.io/db.v3"
 | 
			
		||||
  version = "3.5.3"
 | 
			
		||||
  version = "3.5.4"
 | 
			
		||||
 | 
			
		||||
[prune]
 | 
			
		||||
  go-tests = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										7
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										7
									
								
								Makefile
								
								
								
								
							| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
VERSION=0.52
 | 
			
		||||
VERSION=0.54
 | 
			
		||||
BINARY_NAME=statup
 | 
			
		||||
GOPATH:=$(GOPATH)
 | 
			
		||||
GOCMD=go
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +26,10 @@ docker-build-all: docker-build-base docker-dev docker
 | 
			
		|||
 | 
			
		||||
docker-publish-all: docker-push-base docker-push-dev docker-push-latest
 | 
			
		||||
 | 
			
		||||
seed:
 | 
			
		||||
	rm -f statup.db
 | 
			
		||||
	cat dev/seed.sql | sqlite3 statup.db
 | 
			
		||||
 | 
			
		||||
build: compile
 | 
			
		||||
	$(GOBUILD) $(BUILDVERSION) -o $(BINARY_NAME) -v ./cmd
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -127,6 +131,7 @@ dep:
 | 
			
		|||
	dep ensure -vendor-only
 | 
			
		||||
 | 
			
		||||
dev-deps: dep
 | 
			
		||||
	$(GOGET) -u github.com/jinzhu/gorm/...
 | 
			
		||||
	$(GOGET) github.com/stretchr/testify/assert
 | 
			
		||||
	$(GOGET) golang.org/x/tools/cmd/cover
 | 
			
		||||
	$(GOGET) github.com/mattn/goveralls
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								cmd/cli.go
								
								
								
								
							
							
						
						
									
										24
									
								
								cmd/cli.go
								
								
								
								
							| 
						 | 
				
			
			@ -24,13 +24,12 @@ import (
 | 
			
		|||
	"github.com/hunterlong/statup/source"
 | 
			
		||||
	"github.com/hunterlong/statup/types"
 | 
			
		||||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
	"github.com/jinzhu/gorm"
 | 
			
		||||
	"github.com/joho/godotenv"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
	"upper.io/db.v3/sqlite"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +44,8 @@ func CatchCLI(args []string) error {
 | 
			
		|||
	LoadDotEnvs()
 | 
			
		||||
 | 
			
		||||
	switch args[0] {
 | 
			
		||||
	case "seed":
 | 
			
		||||
		handlers.DesktopInit(ipAddress, port)
 | 
			
		||||
	case "app":
 | 
			
		||||
		handlers.DesktopInit(ipAddress, port)
 | 
			
		||||
	case "version":
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +95,7 @@ func CatchCLI(args []string) error {
 | 
			
		|||
	case "export":
 | 
			
		||||
		var err error
 | 
			
		||||
		fmt.Printf("Statup v%v Exporting Static 'index.html' page...\n", VERSION)
 | 
			
		||||
		core.Configs, err = core.LoadConfig()
 | 
			
		||||
		core.Configs, err = core.LoadConfig(dir)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.Log(4, "config.yml file not found")
 | 
			
		||||
			return err
 | 
			
		||||
| 
						 | 
				
			
			@ -132,11 +133,11 @@ func CatchCLI(args []string) error {
 | 
			
		|||
 | 
			
		||||
func RunOnce() {
 | 
			
		||||
	var err error
 | 
			
		||||
	core.Configs, err = core.LoadConfig()
 | 
			
		||||
	core.Configs, err = core.LoadConfig(utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, "config.yml file not found")
 | 
			
		||||
	}
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, utils.Directory)
 | 
			
		||||
	err = core.Configs.Connect(false, utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -234,21 +235,10 @@ func FakeSeed(plug types.PluginActions) {
 | 
			
		|||
	fmt.Printf("\n" + BRAKER)
 | 
			
		||||
 | 
			
		||||
	fmt.Println("\nCreating a SQLite database for testing, will be deleted automatically...")
 | 
			
		||||
	sqlFake := sqlite.ConnectionURL{
 | 
			
		||||
		Database: "./.plugin_test.db",
 | 
			
		||||
	}
 | 
			
		||||
	core.DbSession, err = sqlite.Open(sqlFake)
 | 
			
		||||
	core.DbSession, err = gorm.Open("sqlite", "./.plugin_test.db")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
	}
 | 
			
		||||
	up, _ := source.SqlBox.String("sqlite_up.sql")
 | 
			
		||||
	requests := strings.Split(up, ";")
 | 
			
		||||
	for _, request := range requests {
 | 
			
		||||
		_, err := core.DbSession.Exec(request)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.Log(2, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("Finished creating Test SQLite database")
 | 
			
		||||
	fmt.Println("Inserting example services into test database...")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								cmd/main.go
								
								
								
								
							
							
						
						
									
										22
									
								
								cmd/main.go
								
								
								
								
							| 
						 | 
				
			
			@ -55,6 +55,8 @@ func parseFlags() {
 | 
			
		|||
func main() {
 | 
			
		||||
	var err error
 | 
			
		||||
	parseFlags()
 | 
			
		||||
	LoadDotEnvs()
 | 
			
		||||
	source.Assets()
 | 
			
		||||
	utils.InitLogs()
 | 
			
		||||
	args := flag.Args()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -68,13 +70,8 @@ func main() {
 | 
			
		|||
			os.Exit(1)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	source.Assets()
 | 
			
		||||
	LoadDotEnvs()
 | 
			
		||||
 | 
			
		||||
	utils.Log(1, fmt.Sprintf("Starting Statup v%v", VERSION))
 | 
			
		||||
 | 
			
		||||
	core.Configs, err = core.LoadConfig()
 | 
			
		||||
	core.Configs, err = core.LoadConfig(utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		core.SetupMode = true
 | 
			
		||||
| 
						 | 
				
			
			@ -94,15 +91,18 @@ func LoadDotEnvs() error {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func mainProcess() {
 | 
			
		||||
	dir := utils.Directory
 | 
			
		||||
	var err error
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, utils.Directory)
 | 
			
		||||
	core.Configs, err = core.LoadConfig(dir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, fmt.Sprintf("could not load config.yml %v", err))
 | 
			
		||||
	}
 | 
			
		||||
	err = core.Configs.Connect(false, dir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, fmt.Sprintf("could not connect to database: %v", err))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	core.RunDatabaseUpgrades()
 | 
			
		||||
	core.Configs.MigrateDatabase()
 | 
			
		||||
	core.InitApp()
 | 
			
		||||
 | 
			
		||||
	if !core.SetupMode {
 | 
			
		||||
		LoadPlugins(false)
 | 
			
		||||
		fmt.Println(handlers.RunHTTPServer(ipAddress, port))
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +170,7 @@ func LoadPlugins(debug bool) {
 | 
			
		|||
		if debug {
 | 
			
		||||
			TestPlugin(plugActions)
 | 
			
		||||
		} else {
 | 
			
		||||
			plugActions.OnLoad(core.DbSession)
 | 
			
		||||
			plugActions.OnLoad(*core.DbSession)
 | 
			
		||||
			core.CoreApp.Plugins = append(core.CoreApp.Plugins, plugActions.GetInfo())
 | 
			
		||||
			core.CoreApp.AllPlugins = append(core.CoreApp.AllPlugins, plugActions)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										188
									
								
								cmd/main_test.go
								
								
								
								
							
							
						
						
									
										188
									
								
								cmd/main_test.go
								
								
								
								
							| 
						 | 
				
			
			@ -31,27 +31,30 @@ import (
 | 
			
		|||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	route       *mux.Router
 | 
			
		||||
	testSession *sessions.Session
 | 
			
		||||
	dir         string
 | 
			
		||||
	route            *mux.Router
 | 
			
		||||
	testSession      *sessions.Session
 | 
			
		||||
	dir              string
 | 
			
		||||
	SERVICE_SINCE, _ = time.Parse(time.RFC3339, "2018-08-30T10:42:08-07:00")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	dir = utils.Directory
 | 
			
		||||
	os.Remove(dir + "/statup.db")
 | 
			
		||||
	//os.Remove(gopath+"/cmd/config.yml")
 | 
			
		||||
	os.RemoveAll(dir + "/cmd/assets")
 | 
			
		||||
	os.RemoveAll(dir + "/logs")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Clean() {
 | 
			
		||||
	utils.DeleteFile(dir + "/config.yml")
 | 
			
		||||
	utils.DeleteFile(dir + "/statup.db")
 | 
			
		||||
	utils.DeleteDirectory(dir + "/assets")
 | 
			
		||||
	utils.DeleteDirectory(dir + "/logs")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunInit(t *testing.T) {
 | 
			
		||||
	source.Assets()
 | 
			
		||||
	os.Remove(dir + "/statup.db")
 | 
			
		||||
	os.Remove(dir + "/cmd/config.yml")
 | 
			
		||||
	os.Remove(dir + "/cmd/index.html")
 | 
			
		||||
	Clean()
 | 
			
		||||
	route = handlers.Router()
 | 
			
		||||
	LoadDotEnvs()
 | 
			
		||||
	core.CoreApp = core.NewCore()
 | 
			
		||||
| 
						 | 
				
			
			@ -60,35 +63,55 @@ func RunInit(t *testing.T) {
 | 
			
		|||
func TestRunAll(t *testing.T) {
 | 
			
		||||
	//t.Parallel()
 | 
			
		||||
 | 
			
		||||
	databases := []string{"sqlite", "postgres", "mysql"}
 | 
			
		||||
	databases := []string{"postgres", "sqlite", "mysql"}
 | 
			
		||||
	if os.Getenv("ONLY_DB") != "" {
 | 
			
		||||
		databases = []string{os.Getenv("ONLY_DB")}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, dbt := range databases {
 | 
			
		||||
 | 
			
		||||
		t.Run(dbt+" init", func(t *testing.T) {
 | 
			
		||||
			RunInit(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" load database config", func(t *testing.T) {
 | 
			
		||||
			RunMakeDatabaseConfig(t, dbt)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" run database migrations", func(t *testing.T) {
 | 
			
		||||
			RunDatabaseMigrations(t, dbt)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Sample Data", func(t *testing.T) {
 | 
			
		||||
			RunInsertSampleData(t)
 | 
			
		||||
		t.Run(dbt+" Save Config", func(t *testing.T) {
 | 
			
		||||
			RunSaveConfig(t, dbt)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Load Configs", func(t *testing.T) {
 | 
			
		||||
			RunLoadConfig(t)
 | 
			
		||||
			t.Log(core.Configs)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Connect to Database", func(t *testing.T) {
 | 
			
		||||
			err := core.Configs.Connect(false, dir)
 | 
			
		||||
			assert.Nil(t, err)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Drop Database", func(t *testing.T) {
 | 
			
		||||
			RunDropDatabase(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Connect to Database Again", func(t *testing.T) {
 | 
			
		||||
			err := core.Configs.Connect(false, dir)
 | 
			
		||||
			assert.Nil(t, err)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Inserting Database Structure", func(t *testing.T) {
 | 
			
		||||
			RunCreateSchema(t, dbt)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Inserting Seed Data", func(t *testing.T) {
 | 
			
		||||
			RunInsertSampleData(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Connect to Database Again", func(t *testing.T) {
 | 
			
		||||
			err := core.Configs.Connect(false, dir)
 | 
			
		||||
			assert.Nil(t, err)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Run Database Migrations", func(t *testing.T) {
 | 
			
		||||
			RunDatabaseMigrations(t, dbt)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Select Core", func(t *testing.T) {
 | 
			
		||||
			RunSelectCoreMYQL(t, dbt)
 | 
			
		||||
			t.Log(core.CoreApp)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Select Services", func(t *testing.T) {
 | 
			
		||||
			RunSelectAllMysqlServices(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Select Comms", func(t *testing.T) {
 | 
			
		||||
			t.SkipNow()
 | 
			
		||||
			RunSelectAllMysqlCommunications(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Create Users", func(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +154,7 @@ func TestRunAll(t *testing.T) {
 | 
			
		|||
		t.Run(dbt+" Create Failing Service", func(t *testing.T) {
 | 
			
		||||
			RunBadService_Create(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Check Service", func(t *testing.T) {
 | 
			
		||||
		t.Run(dbt+" Check Bad Service", func(t *testing.T) {
 | 
			
		||||
			RunBadService_Check(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Select Hits", func(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -183,35 +206,24 @@ func TestRunAll(t *testing.T) {
 | 
			
		|||
			RunSettingsHandler(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Cleanup", func(t *testing.T) {
 | 
			
		||||
			//Cleanup(t)
 | 
			
		||||
			core.Configs.Close()
 | 
			
		||||
			core.DbSession = nil
 | 
			
		||||
			//Clean()
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		//<-done
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Cleanup(t *testing.T) {
 | 
			
		||||
	core.DbSession.ClearCache()
 | 
			
		||||
	err := core.DbSession.Close()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunMakeDatabaseConfig(t *testing.T, db string) {
 | 
			
		||||
func RunSaveConfig(t *testing.T, db string) {
 | 
			
		||||
	var err error
 | 
			
		||||
	port := 5432
 | 
			
		||||
	if db == "mysql" {
 | 
			
		||||
		port = 3306
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//Project     string `yaml:"-"`
 | 
			
		||||
	//Description string `yaml:"-"`
 | 
			
		||||
	//Domain      string `yaml:"-"`
 | 
			
		||||
	//Username    string `yaml:"-"`
 | 
			
		||||
	//Password    string `yaml:"-"`
 | 
			
		||||
	//Email       string `yaml:"-"`
 | 
			
		||||
	//Error       error  `yaml:"-"`
 | 
			
		||||
	//Location    string `yaml:"location"`
 | 
			
		||||
 | 
			
		||||
	config := &core.DbConfig{&types.DbConfig{
 | 
			
		||||
	core.Configs = &core.DbConfig{DbConfig: &types.DbConfig{
 | 
			
		||||
		DbConn:      db,
 | 
			
		||||
		DbHost:      os.Getenv("DB_HOST"),
 | 
			
		||||
		DbUser:      os.Getenv("DB_USER"),
 | 
			
		||||
| 
						 | 
				
			
			@ -227,39 +239,49 @@ func RunMakeDatabaseConfig(t *testing.T, db string) {
 | 
			
		|||
		Error:       nil,
 | 
			
		||||
		Location:    dir,
 | 
			
		||||
	}}
 | 
			
		||||
	err := config.Save()
 | 
			
		||||
	core.Configs, err = core.Configs.Save()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	_, err = core.LoadConfig()
 | 
			
		||||
func RunCreateSchema(t *testing.T, db string) {
 | 
			
		||||
	err := core.Configs.Connect(false, dir)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, db, core.Configs.Connection)
 | 
			
		||||
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, dir)
 | 
			
		||||
	err = core.Configs.CreateDatabase()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunDatabaseMigrations(t *testing.T, db string) {
 | 
			
		||||
	err := core.RunDatabaseUpgrades()
 | 
			
		||||
	err := core.Configs.MigrateDatabase()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunInsertSampleData(t *testing.T) {
 | 
			
		||||
	err := core.LoadSampleData()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	core.Configs.SeedDatabase()
 | 
			
		||||
	//assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunLoadConfig(t *testing.T) {
 | 
			
		||||
	var err error
 | 
			
		||||
	core.Configs, err = core.LoadConfig()
 | 
			
		||||
	core.Configs, err = core.LoadConfig(dir)
 | 
			
		||||
	t.Log(core.Configs)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotNil(t, core.Configs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunDropDatabase(t *testing.T) {
 | 
			
		||||
	err := core.Configs.DropDatabase()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunSelectCoreMYQL(t *testing.T, db string) {
 | 
			
		||||
	var err error
 | 
			
		||||
	core.CoreApp, err = core.SelectCore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.FailNow()
 | 
			
		||||
	}
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, "Testing "+db, core.CoreApp.Name)
 | 
			
		||||
	t.Log("core: ", core.CoreApp.Core)
 | 
			
		||||
	assert.Equal(t, "Awesome Status", core.CoreApp.Name)
 | 
			
		||||
	assert.Equal(t, db, core.CoreApp.DbConnection)
 | 
			
		||||
	assert.NotEmpty(t, core.CoreApp.ApiKey)
 | 
			
		||||
	assert.NotEmpty(t, core.CoreApp.ApiSecret)
 | 
			
		||||
| 
						 | 
				
			
			@ -270,12 +292,12 @@ func RunSelectAllMysqlServices(t *testing.T) {
 | 
			
		|||
	var err error
 | 
			
		||||
	services, err := core.CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 5, len(services))
 | 
			
		||||
	assert.Equal(t, 18, len(services))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunSelectAllMysqlCommunications(t *testing.T) {
 | 
			
		||||
	var err error
 | 
			
		||||
	notifiers.Collections = core.DbSession.Collection("communication")
 | 
			
		||||
	notifiers.Collections = core.DbSession.Table("communication").Model(¬ifiers.Notification{})
 | 
			
		||||
	comms := notifiers.Load()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 3, len(comms))
 | 
			
		||||
| 
						 | 
				
			
			@ -284,19 +306,19 @@ func RunSelectAllMysqlCommunications(t *testing.T) {
 | 
			
		|||
func RunUser_SelectAll(t *testing.T) {
 | 
			
		||||
	users, err := core.SelectAllUsers()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 2, len(users))
 | 
			
		||||
	assert.Equal(t, 3, len(users))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunUser_Create(t *testing.T) {
 | 
			
		||||
	user := core.ReturnUser(&types.User{
 | 
			
		||||
		Username: "admin",
 | 
			
		||||
		Password: "admin",
 | 
			
		||||
		Email:    "info@testuser.com",
 | 
			
		||||
		Username: "hunterlong",
 | 
			
		||||
		Password: "password123",
 | 
			
		||||
		Email:    "info@gmail.com",
 | 
			
		||||
		Admin:    true,
 | 
			
		||||
	})
 | 
			
		||||
	id, err := user.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, int64(1), id)
 | 
			
		||||
	assert.Equal(t, int64(2), id)
 | 
			
		||||
	user2 := core.ReturnUser(&types.User{
 | 
			
		||||
		Username: "superadmin",
 | 
			
		||||
		Password: "admin",
 | 
			
		||||
| 
						 | 
				
			
			@ -305,7 +327,7 @@ func RunUser_Create(t *testing.T) {
 | 
			
		|||
	})
 | 
			
		||||
	id, err = user2.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, int64(2), id)
 | 
			
		||||
	assert.Equal(t, int64(3), id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunUser_Update(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -342,7 +364,10 @@ func RunSelectAllServices(t *testing.T) {
 | 
			
		|||
	var err error
 | 
			
		||||
	services, err := core.CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 5, len(services))
 | 
			
		||||
	assert.Equal(t, 18, len(services))
 | 
			
		||||
	for _, s := range services {
 | 
			
		||||
		assert.NotEmpty(t, s.CreatedAt)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunOneService_Check(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -365,8 +390,7 @@ func RunService_Create(t *testing.T) {
 | 
			
		|||
	})
 | 
			
		||||
	id, err := service.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, int64(6), id)
 | 
			
		||||
	t.Log(service)
 | 
			
		||||
	assert.Equal(t, int64(19), id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunService_ToJSON(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -379,15 +403,20 @@ func RunService_ToJSON(t *testing.T) {
 | 
			
		|||
func RunService_AvgTime(t *testing.T) {
 | 
			
		||||
	service := core.SelectService(1)
 | 
			
		||||
	assert.NotNil(t, service)
 | 
			
		||||
	avg := service.AvgUptime()
 | 
			
		||||
	avg := service.AvgUptime24()
 | 
			
		||||
	assert.Equal(t, "100", avg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunService_Online24(t *testing.T) {
 | 
			
		||||
	service := core.SelectService(1)
 | 
			
		||||
	assert.NotNil(t, service)
 | 
			
		||||
	online := service.Online24()
 | 
			
		||||
	assert.Equal(t, float32(100), online)
 | 
			
		||||
	online := service.OnlineSince(SERVICE_SINCE)
 | 
			
		||||
	assert.Equal(t, float32(80), online)
 | 
			
		||||
 | 
			
		||||
	service = core.SelectService(18)
 | 
			
		||||
	assert.NotNil(t, service)
 | 
			
		||||
	online = service.OnlineSince(SERVICE_SINCE)
 | 
			
		||||
	assert.Equal(t, float32(0), online)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunService_GraphData(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -413,13 +442,13 @@ func RunBadService_Create(t *testing.T) {
 | 
			
		|||
	})
 | 
			
		||||
	id, err := service.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, int64(7), id)
 | 
			
		||||
	assert.Equal(t, int64(20), id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunBadService_Check(t *testing.T) {
 | 
			
		||||
	service := core.SelectService(7)
 | 
			
		||||
	service := core.SelectService(18)
 | 
			
		||||
	assert.NotNil(t, service)
 | 
			
		||||
	assert.Equal(t, "Bad Service", service.Name)
 | 
			
		||||
	assert.Equal(t, "Failing URL", service.Name)
 | 
			
		||||
	for i := 0; i <= 10; i++ {
 | 
			
		||||
		service.Check(true)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -431,9 +460,7 @@ func RunDeleteService(t *testing.T) {
 | 
			
		|||
	assert.NotNil(t, service)
 | 
			
		||||
	assert.Equal(t, "JSON API Tester", service.Name)
 | 
			
		||||
	assert.True(t, service.IsRunning())
 | 
			
		||||
	t.Log(service.Running)
 | 
			
		||||
	err := service.Delete()
 | 
			
		||||
	t.Log(service.Running)
 | 
			
		||||
	assert.False(t, service.IsRunning())
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -441,13 +468,10 @@ func RunDeleteService(t *testing.T) {
 | 
			
		|||
func RunCreateService_Hits(t *testing.T) {
 | 
			
		||||
	services := core.CoreApp.Services()
 | 
			
		||||
	assert.NotNil(t, services)
 | 
			
		||||
	assert.Equal(t, 6, len(services))
 | 
			
		||||
	for i := 0; i <= 15; i++ {
 | 
			
		||||
		for _, s := range services {
 | 
			
		||||
			var service *core.Service
 | 
			
		||||
			service = s.Check(true)
 | 
			
		||||
			assert.NotNil(t, service)
 | 
			
		||||
		}
 | 
			
		||||
	assert.Equal(t, 19, len(services))
 | 
			
		||||
	for _, s := range services {
 | 
			
		||||
		service := s.Check(true)
 | 
			
		||||
		assert.NotNil(t, service)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -460,10 +484,10 @@ func RunService_Hits(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func RunService_Failures(t *testing.T) {
 | 
			
		||||
	service := core.SelectService(7)
 | 
			
		||||
	service := core.SelectService(18)
 | 
			
		||||
	assert.NotNil(t, service)
 | 
			
		||||
	assert.Equal(t, "Bad Service", service.Name)
 | 
			
		||||
	assert.NotEmpty(t, service.Failures)
 | 
			
		||||
	assert.Equal(t, "Failing URL", service.Name)
 | 
			
		||||
	assert.NotEmpty(t, service.AllFailures())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunService_LimitedHits(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -479,7 +503,7 @@ func RunIndexHandler(t *testing.T) {
 | 
			
		|||
	assert.Nil(t, err)
 | 
			
		||||
	rr := httptest.NewRecorder()
 | 
			
		||||
	route.ServeHTTP(rr, req)
 | 
			
		||||
	assert.True(t, strings.Contains(rr.Body.String(), "This is a test of Statup.io!"))
 | 
			
		||||
	assert.True(t, strings.Contains(rr.Body.String(), "Awesome"))
 | 
			
		||||
	assert.True(t, strings.Contains(rr.Body.String(), "footer"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -499,7 +523,7 @@ func RunPrometheusHandler(t *testing.T) {
 | 
			
		|||
	rr := httptest.NewRecorder()
 | 
			
		||||
	route.ServeHTTP(rr, req)
 | 
			
		||||
	t.Log(rr.Body.String())
 | 
			
		||||
	assert.True(t, strings.Contains(rr.Body.String(), "statup_total_services 6"))
 | 
			
		||||
	assert.True(t, strings.Contains(rr.Body.String(), "statup_total_services 19"))
 | 
			
		||||
	assert.True(t, handlers.IsAuthenticated(req))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -515,7 +539,7 @@ func RunFailingPrometheusHandler(t *testing.T) {
 | 
			
		|||
func RunLoginHandler(t *testing.T) {
 | 
			
		||||
	form := url.Values{}
 | 
			
		||||
	form.Add("username", "admin")
 | 
			
		||||
	form.Add("password", "admin")
 | 
			
		||||
	form.Add("password", "password123")
 | 
			
		||||
	req, err := http.NewRequest("POST", "/dashboard", strings.NewReader(form.Encode()))
 | 
			
		||||
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -210,7 +210,9 @@ func RecordSuccess(s *Service) {
 | 
			
		|||
	s.Online = true
 | 
			
		||||
	s.LastOnline = time.Now()
 | 
			
		||||
	data := &types.Hit{
 | 
			
		||||
		Latency: s.Latency,
 | 
			
		||||
		Service:   s.Id,
 | 
			
		||||
		Latency:   s.Latency,
 | 
			
		||||
		CreatedAt: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
	utils.Log(1, fmt.Sprintf("Service %v Successful: %0.2f ms", s.Name, data.Latency*1000))
 | 
			
		||||
	s.CreateHit(data)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,26 +48,25 @@ func FindCheckin(api string) *types.Checkin {
 | 
			
		|||
 | 
			
		||||
func (s *Service) AllCheckins() []*types.Checkin {
 | 
			
		||||
	var checkins []*types.Checkin
 | 
			
		||||
	col := DbSession.Collection("checkins").Find("service", s.Id).OrderBy("-id")
 | 
			
		||||
	col.All(&checkins)
 | 
			
		||||
	col := checkinDB().Where("service = ?", s.Id).Order("id desc")
 | 
			
		||||
	col.Find(&checkins)
 | 
			
		||||
	s.Checkins = checkins
 | 
			
		||||
	return checkins
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *Checkin) Create() (int64, error) {
 | 
			
		||||
	u.CreatedAt = time.Now()
 | 
			
		||||
	uuid, err := DbSession.Collection("checkins").Insert(u)
 | 
			
		||||
	if uuid == nil {
 | 
			
		||||
		utils.Log(2, err)
 | 
			
		||||
		return 0, err
 | 
			
		||||
	row := checkinDB().Create(u)
 | 
			
		||||
	if row.Error == nil {
 | 
			
		||||
		utils.Log(2, row.Error)
 | 
			
		||||
		return 0, row.Error
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println("new checkin: ", uuid)
 | 
			
		||||
	return uuid.(int64), err
 | 
			
		||||
	return u.Id, row.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectCheckinApi(api string) *Checkin {
 | 
			
		||||
	var checkin *Checkin
 | 
			
		||||
	DbSession.Collection("checkins").Find("api", api).One(&checkin)
 | 
			
		||||
	checkinDB().Where("api = ?", api).Find(&checkin)
 | 
			
		||||
	return checkin
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,29 +23,28 @@ import (
 | 
			
		|||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func LoadConfig() (*types.Config, error) {
 | 
			
		||||
func LoadConfig(directory string) (*DbConfig, error) {
 | 
			
		||||
	var configs *types.DbConfig
 | 
			
		||||
	if os.Getenv("DB_CONN") != "" {
 | 
			
		||||
		utils.Log(1, "DB_CONN environment variable was found, waiting for database...")
 | 
			
		||||
		return LoadUsingEnv()
 | 
			
		||||
	}
 | 
			
		||||
	Configs = new(types.Config)
 | 
			
		||||
	file, err := ioutil.ReadFile(utils.Directory + "/config.yml")
 | 
			
		||||
	file, err := ioutil.ReadFile(directory + "/config.yml")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("config.yml file not found - starting in setup mode")
 | 
			
		||||
		return nil, errors.New("config.yml file not found at " + directory + "/config.yml - starting in setup mode")
 | 
			
		||||
	}
 | 
			
		||||
	err = yaml.Unmarshal(file, &Configs)
 | 
			
		||||
	err = yaml.Unmarshal(file, &configs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	CoreApp.DbConnection = Configs.Connection
 | 
			
		||||
	Configs = &DbConfig{configs}
 | 
			
		||||
	return Configs, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LoadUsingEnv() (*types.Config, error) {
 | 
			
		||||
	Configs = new(types.Config)
 | 
			
		||||
func LoadUsingEnv() (*DbConfig, error) {
 | 
			
		||||
	Configs = new(DbConfig)
 | 
			
		||||
	if os.Getenv("DB_CONN") == "" {
 | 
			
		||||
		return nil, errors.New("Missing DB_CONN environment variable")
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -61,12 +60,12 @@ func LoadUsingEnv() (*types.Config, error) {
 | 
			
		|||
	if os.Getenv("DB_DATABASE") == "" {
 | 
			
		||||
		return nil, errors.New("Missing DB_DATABASE environment variable")
 | 
			
		||||
	}
 | 
			
		||||
	Configs.Connection = os.Getenv("DB_CONN")
 | 
			
		||||
	Configs.Host = os.Getenv("DB_HOST")
 | 
			
		||||
	Configs.Port = os.Getenv("DB_PORT")
 | 
			
		||||
	Configs.User = os.Getenv("DB_USER")
 | 
			
		||||
	Configs.DbConn = os.Getenv("DB_CONN")
 | 
			
		||||
	Configs.DbHost = os.Getenv("DB_HOST")
 | 
			
		||||
	Configs.DbPort = int(utils.StringInt(os.Getenv("DB_PORT")))
 | 
			
		||||
	Configs.DbUser = os.Getenv("DB_USER")
 | 
			
		||||
	Configs.Password = os.Getenv("DB_PASS")
 | 
			
		||||
	Configs.Database = os.Getenv("DB_DATABASE")
 | 
			
		||||
	Configs.DbData = os.Getenv("DB_DATABASE")
 | 
			
		||||
	CoreApp.DbConnection = os.Getenv("DB_CONN")
 | 
			
		||||
	CoreApp.Name = os.Getenv("NAME")
 | 
			
		||||
	CoreApp.Domain = os.Getenv("DOMAIN")
 | 
			
		||||
| 
						 | 
				
			
			@ -89,32 +88,19 @@ func LoadUsingEnv() (*types.Config, error) {
 | 
			
		|||
		Email:       "info@localhost.com",
 | 
			
		||||
	}}
 | 
			
		||||
 | 
			
		||||
	err := DbConnection(dbConfig.DbConn, true, utils.Directory)
 | 
			
		||||
	err := dbConfig.Connect(true, utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	exists, err := DbSession.Collection("core").Find().Exists()
 | 
			
		||||
	exists := DbSession.HasTable("core")
 | 
			
		||||
	if !exists {
 | 
			
		||||
 | 
			
		||||
		utils.Log(1, fmt.Sprintf("Core database does not exist, creating now!"))
 | 
			
		||||
		DropDatabase()
 | 
			
		||||
		CreateDatabase()
 | 
			
		||||
		dbConfig.DropDatabase()
 | 
			
		||||
		dbConfig.CreateDatabase()
 | 
			
		||||
 | 
			
		||||
		CoreApp = &Core{Core: &types.Core{
 | 
			
		||||
			Name:        dbConfig.Project,
 | 
			
		||||
			Description: dbConfig.Description,
 | 
			
		||||
			Config:      "config.yml",
 | 
			
		||||
			ApiKey:      utils.NewSHA1Hash(9),
 | 
			
		||||
			ApiSecret:   utils.NewSHA1Hash(16),
 | 
			
		||||
			Domain:      dbConfig.Domain,
 | 
			
		||||
			MigrationId: time.Now().Unix(),
 | 
			
		||||
		}}
 | 
			
		||||
 | 
			
		||||
		CoreApp.DbConnection = dbConfig.DbConn
 | 
			
		||||
 | 
			
		||||
		err := InsertCore(CoreApp)
 | 
			
		||||
		CoreApp, err = dbConfig.InsertCore()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.Log(3, err)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										63
									
								
								core/core.go
								
								
								
								
							
							
						
						
									
										63
									
								
								core/core.go
								
								
								
								
							| 
						 | 
				
			
			@ -34,10 +34,10 @@ type Core struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	Configs   *types.Config
 | 
			
		||||
	CoreApp   *Core
 | 
			
		||||
	SetupMode bool
 | 
			
		||||
	VERSION   string
 | 
			
		||||
	Configs   *DbConfig // Configs holds all of the config.yml and database info
 | 
			
		||||
	CoreApp   *Core     // CoreApp is a global variable that contains many elements
 | 
			
		||||
	SetupMode bool      // SetupMode will be true if Statup does not have a database connection
 | 
			
		||||
	VERSION   string    // VERSION is set on build automatically by setting a -ldflag
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
| 
						 | 
				
			
			@ -51,12 +51,6 @@ func NewCore() *Core {
 | 
			
		|||
	return CoreApp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InsertCore(c *Core) error {
 | 
			
		||||
	col := DbSession.Collection("core")
 | 
			
		||||
	_, err := col.Insert(c.Core)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Core) ToCore() *types.Core {
 | 
			
		||||
	return c.Core
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -72,25 +66,27 @@ func InitApp() {
 | 
			
		|||
 | 
			
		||||
func InsertNotifierDB() error {
 | 
			
		||||
	if DbSession == nil {
 | 
			
		||||
		err := DbConnection(CoreApp.DbConnection, false, utils.Directory)
 | 
			
		||||
		err := Configs.Connect(false, utils.Directory)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.New("database connection has not been created")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	notifiers.Collections = DbSession.Collection("communication")
 | 
			
		||||
	notifiers.Collections = commDB()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateCore will update the CoreApp variable inside of the 'core' table in database
 | 
			
		||||
func UpdateCore(c *Core) (*Core, error) {
 | 
			
		||||
	res := DbSession.Collection("core").Find().Limit(1)
 | 
			
		||||
	err := res.Update(c.Core)
 | 
			
		||||
	return c, err
 | 
			
		||||
	db := coreDB().Update(&c)
 | 
			
		||||
	return c, db.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UsingAssets will return true if /assets folder is present
 | 
			
		||||
func (c Core) UsingAssets() bool {
 | 
			
		||||
	return source.UsingAssets(utils.Directory)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SassVars opens the file /assets/scss/variables.scss to be edited in Theme
 | 
			
		||||
func (c Core) SassVars() string {
 | 
			
		||||
	if !source.UsingAssets(utils.Directory) {
 | 
			
		||||
		return ""
 | 
			
		||||
| 
						 | 
				
			
			@ -98,6 +94,7 @@ func (c Core) SassVars() string {
 | 
			
		|||
	return source.OpenAsset(utils.Directory, "scss/variables.scss")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BaseSASS is the base design , this opens the file /assets/scss/base.scss to be edited in Theme
 | 
			
		||||
func (c Core) BaseSASS() string {
 | 
			
		||||
	if !source.UsingAssets(utils.Directory) {
 | 
			
		||||
		return ""
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +102,8 @@ func (c Core) BaseSASS() string {
 | 
			
		|||
	return source.OpenAsset(utils.Directory, "scss/base.scss")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MobileSASS is the -webkit responsive custom css designs. This opens the
 | 
			
		||||
// file /assets/scss/mobile.scss to be edited in Theme
 | 
			
		||||
func (c Core) MobileSASS() string {
 | 
			
		||||
	if !source.UsingAssets(utils.Directory) {
 | 
			
		||||
		return ""
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +111,7 @@ func (c Core) MobileSASS() string {
 | 
			
		|||
	return source.OpenAsset(utils.Directory, "scss/mobile.scss")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AllOnline will be true if all services are online
 | 
			
		||||
func (c Core) AllOnline() bool {
 | 
			
		||||
	for _, s := range CoreApp.Services() {
 | 
			
		||||
		if !s.Online {
 | 
			
		||||
| 
						 | 
				
			
			@ -121,49 +121,42 @@ func (c Core) AllOnline() bool {
 | 
			
		|||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectLastMigration() (int64, error) {
 | 
			
		||||
	var c *types.Core
 | 
			
		||||
	if DbSession == nil {
 | 
			
		||||
		return 0, errors.New("Database connection has not been created yet")
 | 
			
		||||
	}
 | 
			
		||||
	err := DbSession.Collection("core").Find().One(&c)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return c.MigrationId, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SelectCore will return the CoreApp global variable and the settings/configs for Statup
 | 
			
		||||
func SelectCore() (*Core, error) {
 | 
			
		||||
	var c *types.Core
 | 
			
		||||
	exists := DbSession.Collection("core").Exists()
 | 
			
		||||
	if DbSession == nil {
 | 
			
		||||
		return nil, errors.New("database has not been initiated yet.")
 | 
			
		||||
	}
 | 
			
		||||
	exists := DbSession.HasTable("core")
 | 
			
		||||
	if !exists {
 | 
			
		||||
		return nil, errors.New("core database has not been setup yet.")
 | 
			
		||||
	}
 | 
			
		||||
	err := DbSession.Collection("core").Find().One(&c)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	db := coreDB().First(&CoreApp)
 | 
			
		||||
	if db.Error != nil {
 | 
			
		||||
		return nil, db.Error
 | 
			
		||||
	}
 | 
			
		||||
	CoreApp.Core = c
 | 
			
		||||
	CoreApp.DbConnection = Configs.Connection
 | 
			
		||||
	CoreApp.DbConnection = Configs.DbConn
 | 
			
		||||
	CoreApp.Version = VERSION
 | 
			
		||||
	CoreApp.SelectAllServices()
 | 
			
		||||
	if os.Getenv("USE_CDN") == "true" {
 | 
			
		||||
		CoreApp.UseCdn = true
 | 
			
		||||
	}
 | 
			
		||||
	//store = sessions.NewCookieStore([]byte(core.ApiSecret))
 | 
			
		||||
	return CoreApp, err
 | 
			
		||||
	return CoreApp, db.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServiceOrder will reorder the services based on 'order_id' (Order)
 | 
			
		||||
type ServiceOrder []*types.Service
 | 
			
		||||
 | 
			
		||||
func (c ServiceOrder) Len() int           { return len(c) }
 | 
			
		||||
func (c ServiceOrder) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
 | 
			
		||||
func (c ServiceOrder) Less(i, j int) bool { return c[i].Order < c[j].Order }
 | 
			
		||||
 | 
			
		||||
// Services returns each Service that is attached to this instance
 | 
			
		||||
func (c *Core) Services() []*Service {
 | 
			
		||||
	var services []*Service
 | 
			
		||||
	servs := CoreApp.GetServices()
 | 
			
		||||
	sort.Sort(ServiceOrder(servs))
 | 
			
		||||
	CoreApp.SetServices(servs)
 | 
			
		||||
	for _, ser := range servs {
 | 
			
		||||
		services = append(services, ReturnService(ser))
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,9 +24,11 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	testCore   *Core
 | 
			
		||||
	testConfig *DbConfig
 | 
			
		||||
	dir        string
 | 
			
		||||
	dir string
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	SERVICE_SINCE = "2018-08-30T10:42:08-07:00" // "2006-01-02T15:04:05Z07:00"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
| 
						 | 
				
			
			@ -36,51 +38,68 @@ func init() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestNewCore(t *testing.T) {
 | 
			
		||||
	testCore = NewCore()
 | 
			
		||||
	assert.NotNil(t, testCore)
 | 
			
		||||
	testCore.Name = "Tester"
 | 
			
		||||
	utils.DeleteFile(dir + "/config.yml")
 | 
			
		||||
	utils.DeleteFile(dir + "/statup.db")
 | 
			
		||||
	CoreApp = NewCore()
 | 
			
		||||
	assert.NotNil(t, CoreApp)
 | 
			
		||||
	CoreApp.Name = "Tester"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDbConfig_Save(t *testing.T) {
 | 
			
		||||
	testConfig = &DbConfig{&types.DbConfig{
 | 
			
		||||
	var err error
 | 
			
		||||
	Configs = &DbConfig{&types.DbConfig{
 | 
			
		||||
		DbConn:   "sqlite",
 | 
			
		||||
		Project:  "Tester",
 | 
			
		||||
		Location: dir,
 | 
			
		||||
	}}
 | 
			
		||||
	err := testConfig.Save()
 | 
			
		||||
	Configs, err = Configs.Save()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, "sqlite", Configs.DbConn)
 | 
			
		||||
	assert.NotEmpty(t, Configs.ApiKey)
 | 
			
		||||
	assert.NotEmpty(t, Configs.ApiSecret)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLoadDbConfig(t *testing.T) {
 | 
			
		||||
	Configs, err := LoadConfig(dir)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, "sqlite", Configs.DbConn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDbConnection(t *testing.T) {
 | 
			
		||||
	err := DbConnection(testConfig.DbConn, false, dir)
 | 
			
		||||
	err := Configs.Connect(false, dir)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateDatabase(t *testing.T) {
 | 
			
		||||
	err := CreateDatabase()
 | 
			
		||||
func TestDropDatabase(t *testing.T) {
 | 
			
		||||
	err := Configs.DropDatabase()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInsertCore(t *testing.T) {
 | 
			
		||||
	err := InsertCore(testCore)
 | 
			
		||||
func TestSeedSchemaDatabase(t *testing.T) {
 | 
			
		||||
	err := Configs.CreateDatabase()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMigrateDatabase(t *testing.T) {
 | 
			
		||||
	err := Configs.MigrateDatabase()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSeedDatabase(t *testing.T) {
 | 
			
		||||
	_, _, err := Configs.SeedDatabase()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestReLoadDbConfig(t *testing.T) {
 | 
			
		||||
	err := Configs.Connect(false, dir)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, "sqlite", Configs.DbConn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSelectCore(t *testing.T) {
 | 
			
		||||
	core, err := SelectCore()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, "Tester", core.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSampleData(t *testing.T) {
 | 
			
		||||
	err := LoadSampleData()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSelectLastMigration(t *testing.T) {
 | 
			
		||||
	id, err := SelectLastMigration()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotZero(t, id)
 | 
			
		||||
	assert.Equal(t, "Awesome Status", core.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInsertNotifierDB(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										398
									
								
								core/database.go
								
								
								
								
							
							
						
						
									
										398
									
								
								core/database.go
								
								
								
								
							| 
						 | 
				
			
			@ -18,95 +18,161 @@ package core
 | 
			
		|||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/go-yaml/yaml"
 | 
			
		||||
	"github.com/hunterlong/statup/source"
 | 
			
		||||
	"github.com/hunterlong/statup/notifiers"
 | 
			
		||||
	"github.com/hunterlong/statup/types"
 | 
			
		||||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
	"github.com/jinzhu/gorm"
 | 
			
		||||
	_ "github.com/jinzhu/gorm/dialects/mssql"
 | 
			
		||||
	_ "github.com/jinzhu/gorm/dialects/mysql"
 | 
			
		||||
	_ "github.com/jinzhu/gorm/dialects/postgres"
 | 
			
		||||
	_ "github.com/jinzhu/gorm/dialects/sqlite"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
	"upper.io/db.v3"
 | 
			
		||||
	"upper.io/db.v3/lib/sqlbuilder"
 | 
			
		||||
	"upper.io/db.v3/mysql"
 | 
			
		||||
	"upper.io/db.v3/postgresql"
 | 
			
		||||
	"upper.io/db.v3/sqlite"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	sqliteSettings   sqlite.ConnectionURL
 | 
			
		||||
	postgresSettings postgresql.ConnectionURL
 | 
			
		||||
	mysqlSettings    mysql.ConnectionURL
 | 
			
		||||
	DbSession        sqlbuilder.Database
 | 
			
		||||
	currentMigration int64
 | 
			
		||||
	DbSession *gorm.DB
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func failuresDB() *gorm.DB {
 | 
			
		||||
	db := DbSession.Model(&types.Failure{})
 | 
			
		||||
	if os.Getenv("GO_ENV") == "test" {
 | 
			
		||||
		return db.Debug()
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) allHits() *gorm.DB {
 | 
			
		||||
	var hits []*Hit
 | 
			
		||||
	return servicesDB().Find(s).Related(&hits)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hitsDB() *gorm.DB {
 | 
			
		||||
	db := DbSession.Model(&types.Hit{})
 | 
			
		||||
	if os.Getenv("GO_ENV") == "test" {
 | 
			
		||||
		return db.Debug()
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func servicesDB() *gorm.DB {
 | 
			
		||||
	db := DbSession.Model(&types.Service{})
 | 
			
		||||
	if os.Getenv("GO_ENV") == "test" {
 | 
			
		||||
		return db.Debug()
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func coreDB() *gorm.DB {
 | 
			
		||||
	db := DbSession.Table("core").Model(&CoreApp)
 | 
			
		||||
	if os.Getenv("GO_ENV") == "test" {
 | 
			
		||||
		return db.Debug()
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func usersDB() *gorm.DB {
 | 
			
		||||
	db := DbSession.Model(&types.User{})
 | 
			
		||||
	if os.Getenv("GO_ENV") == "test" {
 | 
			
		||||
		return db.Debug()
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func commDB() *gorm.DB {
 | 
			
		||||
	db := DbSession.Table("communication").Model(¬ifiers.Notification{})
 | 
			
		||||
	if os.Getenv("GO_ENV") == "test" {
 | 
			
		||||
		return db.Debug()
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkinDB() *gorm.DB {
 | 
			
		||||
	if os.Getenv("GO_ENV") == "test" {
 | 
			
		||||
		return DbSession.Model(&types.Checkin{}).Debug()
 | 
			
		||||
	}
 | 
			
		||||
	return DbSession.Model(&types.Checkin{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DbConfig struct {
 | 
			
		||||
	*types.DbConfig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DbConnection(dbType string, retry bool, location string) error {
 | 
			
		||||
// Close shutsdown the database connection
 | 
			
		||||
func (db *DbConfig) Close() error {
 | 
			
		||||
	return DbSession.DB().Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InsertCore create the single row for the Core settings in Statup
 | 
			
		||||
func (db *DbConfig) InsertCore() (*Core, error) {
 | 
			
		||||
	CoreApp = &Core{Core: &types.Core{
 | 
			
		||||
		Name:        db.Project,
 | 
			
		||||
		Description: db.Description,
 | 
			
		||||
		Config:      "config.yml",
 | 
			
		||||
		ApiKey:      utils.NewSHA1Hash(9),
 | 
			
		||||
		ApiSecret:   utils.NewSHA1Hash(16),
 | 
			
		||||
		Domain:      db.Domain,
 | 
			
		||||
		MigrationId: time.Now().Unix(),
 | 
			
		||||
	}}
 | 
			
		||||
	CoreApp.DbConnection = db.DbConn
 | 
			
		||||
	query := coreDB().Create(&CoreApp)
 | 
			
		||||
	return CoreApp, query.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Connect will attempt to connect to the sqlite, postgres, or mysql database
 | 
			
		||||
func (db *DbConfig) Connect(retry bool, location string) error {
 | 
			
		||||
	var err error
 | 
			
		||||
	if dbType == "sqlite" {
 | 
			
		||||
		sqliteSettings = sqlite.ConnectionURL{
 | 
			
		||||
			Database: location + "/statup.db",
 | 
			
		||||
	if DbSession != nil {
 | 
			
		||||
		DbSession = nil
 | 
			
		||||
	}
 | 
			
		||||
	var conn, dbType string
 | 
			
		||||
	dbType = Configs.DbConn
 | 
			
		||||
	switch dbType {
 | 
			
		||||
	case "sqlite":
 | 
			
		||||
		conn = utils.Directory + "/statup.db"
 | 
			
		||||
		dbType = "sqlite3"
 | 
			
		||||
	case "mysql":
 | 
			
		||||
		if Configs.DbPort == 0 {
 | 
			
		||||
			Configs.DbPort = 3306
 | 
			
		||||
		}
 | 
			
		||||
		DbSession, err = sqlite.Open(sqliteSettings)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
		host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort)
 | 
			
		||||
		conn = fmt.Sprintf("%v:%v@tcp(%v)/%v?charset=utf8&parseTime=True&loc=Local", Configs.DbUser, Configs.DbPass, host, Configs.DbData)
 | 
			
		||||
	case "postgres":
 | 
			
		||||
		if Configs.DbPort == 0 {
 | 
			
		||||
			Configs.DbPort = 5432
 | 
			
		||||
		}
 | 
			
		||||
		conn = fmt.Sprintf("host=%v port=%v user=%v dbname=%v password=%v sslmode=disable", Configs.DbHost, Configs.DbPort, Configs.DbUser, Configs.DbData, Configs.DbPass)
 | 
			
		||||
	case "mssql":
 | 
			
		||||
		if Configs.DbPort == 0 {
 | 
			
		||||
			Configs.DbPort = 1433
 | 
			
		||||
		}
 | 
			
		||||
		host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort)
 | 
			
		||||
		conn = fmt.Sprintf("sqlserver://%v:%v@%v?database=%v", Configs.DbUser, Configs.DbPass, host, Configs.DbData)
 | 
			
		||||
	}
 | 
			
		||||
	DbSession, err = gorm.Open(dbType, conn)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if retry {
 | 
			
		||||
			utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", Configs.DbHost))
 | 
			
		||||
			return db.waitForDb()
 | 
			
		||||
		} else {
 | 
			
		||||
			fmt.Println("ERROR:", err)
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else if dbType == "mysql" {
 | 
			
		||||
		if Configs.Port == "" {
 | 
			
		||||
			Configs.Port = "3306"
 | 
			
		||||
		}
 | 
			
		||||
		host := fmt.Sprintf("%v:%v", Configs.Host, Configs.Port)
 | 
			
		||||
		mysqlSettings = mysql.ConnectionURL{
 | 
			
		||||
			Database: Configs.Database,
 | 
			
		||||
			Host:     host,
 | 
			
		||||
			User:     Configs.User,
 | 
			
		||||
			Password: Configs.Password,
 | 
			
		||||
			Options:  map[string]string{"parseTime": "true", "charset": "utf8"},
 | 
			
		||||
		}
 | 
			
		||||
		DbSession, err = mysql.Open(mysqlSettings)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if retry {
 | 
			
		||||
				utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host))
 | 
			
		||||
				return waitForDb(dbType)
 | 
			
		||||
			} else {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if Configs.Port == "" {
 | 
			
		||||
			Configs.Port = "5432"
 | 
			
		||||
		}
 | 
			
		||||
		host := fmt.Sprintf("%v:%v", Configs.Host, Configs.Port)
 | 
			
		||||
		postgresSettings = postgresql.ConnectionURL{
 | 
			
		||||
			Database: Configs.Database,
 | 
			
		||||
			Host:     host,
 | 
			
		||||
			User:     Configs.User,
 | 
			
		||||
			Password: Configs.Password,
 | 
			
		||||
		}
 | 
			
		||||
		DbSession, err = postgresql.Open(postgresSettings)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if retry {
 | 
			
		||||
				utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host))
 | 
			
		||||
				return waitForDb(dbType)
 | 
			
		||||
			} else {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	err = DbSession.Ping()
 | 
			
		||||
	err = DbSession.DB().Ping()
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		utils.Log(1, fmt.Sprintf("Database connection to '%v' was successful.", DbSession.Name()))
 | 
			
		||||
		utils.Log(1, fmt.Sprintf("Database connection to '%v' was successful.", Configs.DbData))
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func waitForDb(dbType string) error {
 | 
			
		||||
func (db *DbConfig) waitForDb() error {
 | 
			
		||||
	time.Sleep(5 * time.Second)
 | 
			
		||||
	return DbConnection(dbType, true, utils.Directory)
 | 
			
		||||
	return db.Connect(true, utils.Directory)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DatabaseMaintence will automatically delete old records from 'failures' and 'hits'
 | 
			
		||||
// this function is currently set to delete records 7+ days old every 60 minutes
 | 
			
		||||
func DatabaseMaintence() {
 | 
			
		||||
	for range time.Tick(60 * time.Minute) {
 | 
			
		||||
		utils.Log(1, "Checking for database records older than 7 days...")
 | 
			
		||||
| 
						 | 
				
			
			@ -116,14 +182,17 @@ func DatabaseMaintence() {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteAllSince will delete a specific table's records based on a time.
 | 
			
		||||
func DeleteAllSince(table string, date time.Time) {
 | 
			
		||||
	sql := fmt.Sprintf("DELETE FROM %v WHERE created_at < '%v';", table, date.Format("2006-01-02"))
 | 
			
		||||
	_, err := DbSession.Exec(db.Raw(sql))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(2, err)
 | 
			
		||||
	db := DbSession.Raw(sql)
 | 
			
		||||
	defer db.Close()
 | 
			
		||||
	if db.Error != nil {
 | 
			
		||||
		utils.Log(2, db.Error)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update will save the config.yml file
 | 
			
		||||
func (c *DbConfig) Update() error {
 | 
			
		||||
	var err error
 | 
			
		||||
	config, err := os.Create(utils.Directory + "/config.yml")
 | 
			
		||||
| 
						 | 
				
			
			@ -141,162 +210,115 @@ func (c *DbConfig) Update() error {
 | 
			
		|||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *DbConfig) Save() error {
 | 
			
		||||
// Save will initially create the config.yml file
 | 
			
		||||
func (c *DbConfig) Save() (*DbConfig, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	config, err := os.Create(utils.Directory + "/config.yml")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
		return err
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	c.ApiKey = utils.NewSHA1Hash(16)
 | 
			
		||||
	c.ApiSecret = utils.NewSHA1Hash(16)
 | 
			
		||||
	data, err := yaml.Marshal(c.DbConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		return err
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	config.WriteString(string(data))
 | 
			
		||||
	config.Close()
 | 
			
		||||
 | 
			
		||||
	Configs, err = LoadConfig()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = DbConnection(Configs.Connection, false, c.Location)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	DropDatabase()
 | 
			
		||||
	CreateDatabase()
 | 
			
		||||
	defer config.Close()
 | 
			
		||||
	return c, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateCore will initialize the global variable 'CoreApp". This global variable contains most of Statup app.
 | 
			
		||||
func (c *DbConfig) CreateCore() *Core {
 | 
			
		||||
	newCore := &types.Core{
 | 
			
		||||
		Name:        c.Project,
 | 
			
		||||
		Description: c.Description,
 | 
			
		||||
		Config:      "config.yml",
 | 
			
		||||
		ApiKey:      utils.NewSHA1Hash(9),
 | 
			
		||||
		ApiSecret:   utils.NewSHA1Hash(16),
 | 
			
		||||
		ApiKey:      c.ApiKey,
 | 
			
		||||
		ApiSecret:   c.ApiSecret,
 | 
			
		||||
		Domain:      c.Domain,
 | 
			
		||||
		MigrationId: time.Now().Unix(),
 | 
			
		||||
	}
 | 
			
		||||
	col := DbSession.Collection("core")
 | 
			
		||||
	_, err = col.Insert(newCore)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
	db := coreDB().Create(&newCore)
 | 
			
		||||
	if db.Error == nil {
 | 
			
		||||
		CoreApp = &Core{Core: newCore}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	CoreApp, err = SelectCore()
 | 
			
		||||
	CoreApp, err := SelectCore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
	}
 | 
			
		||||
	CoreApp.DbConnection = c.DbConn
 | 
			
		||||
	c.ApiKey = CoreApp.ApiKey
 | 
			
		||||
	c.ApiSecret = CoreApp.ApiSecret
 | 
			
		||||
	return err
 | 
			
		||||
	return CoreApp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func versionHigher(migrate int64) bool {
 | 
			
		||||
	if CoreApp.MigrationId < migrate {
 | 
			
		||||
		return true
 | 
			
		||||
// SeedDatabase will insert many elements into the database. This is only ran in Dev/Test move
 | 
			
		||||
func (db *DbConfig) SeedDatabase() (string, string, error) {
 | 
			
		||||
	utils.Log(1, "Seeding Database with Dummy Data...")
 | 
			
		||||
	dir := utils.Directory
 | 
			
		||||
	var cmd string
 | 
			
		||||
	switch db.DbConn {
 | 
			
		||||
	case "sqlite":
 | 
			
		||||
		cmd = fmt.Sprintf("cat %v/dev/sqlite_seed.sql | sqlite3 %v/statup.db", dir, dir)
 | 
			
		||||
	case "mysql":
 | 
			
		||||
		cmd = fmt.Sprintf("mysql -h %v -P %v -u %v --password=%v %v < %v/dev/mysql_seed.sql", Configs.DbHost, 3306, Configs.DbUser, Configs.DbPass, Configs.DbData, dir)
 | 
			
		||||
	case "postgres":
 | 
			
		||||
		cmd = fmt.Sprintf("PGPASSWORD=%v psql -U %v -h %v -d %v -1 -f %v/dev/postgres_seed.sql", db.DbPass, db.DbUser, db.DbHost, db.DbData, dir)
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
	out, outErr, err := utils.Command(cmd)
 | 
			
		||||
	return out, outErr, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func reverseSlice(s []string) []string {
 | 
			
		||||
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
 | 
			
		||||
		s[i], s[j] = s[j], s[i]
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunDatabaseUpgrades() error {
 | 
			
		||||
	var err error
 | 
			
		||||
	currentMigration, err = SelectLastMigration()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	utils.Log(1, fmt.Sprintf("Checking for Database Upgrades since #%v", currentMigration))
 | 
			
		||||
	upgrade, _ := source.SqlBox.String(CoreApp.DbConnection + "_upgrade.sql")
 | 
			
		||||
	// parse db version and upgrade file
 | 
			
		||||
	ups := strings.Split(upgrade, "=========================================== ")
 | 
			
		||||
	ups = reverseSlice(ups)
 | 
			
		||||
	var ran int
 | 
			
		||||
	var lastMigration int64
 | 
			
		||||
	for _, v := range ups {
 | 
			
		||||
		if len(v) == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		vers := strings.Split(v, "\n")
 | 
			
		||||
		lastMigration = utils.StringInt(vers[0])
 | 
			
		||||
		data := vers[1:]
 | 
			
		||||
 | 
			
		||||
		//fmt.Printf("Checking Migration from v%v to v%v - %v\n", CoreApp.Version, version, versionHigher(version))
 | 
			
		||||
		if currentMigration >= lastMigration {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		utils.Log(1, fmt.Sprintf("Migrating Database from #%v to #%v", currentMigration, lastMigration))
 | 
			
		||||
		for _, m := range data {
 | 
			
		||||
			if m == "" {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			utils.Log(1, fmt.Sprintf("Running Query: %v", m))
 | 
			
		||||
			_, err := DbSession.Exec(db.Raw(m + ";"))
 | 
			
		||||
			ran++
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				utils.Log(2, err)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		currentMigration = lastMigration
 | 
			
		||||
	}
 | 
			
		||||
	if ran > 0 {
 | 
			
		||||
		utils.Log(1, fmt.Sprintf("Database Upgraded %v queries ran, current #%v", ran, currentMigration))
 | 
			
		||||
		CoreApp, err = SelectCore()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		CoreApp.MigrationId = currentMigration
 | 
			
		||||
		UpdateCore(CoreApp)
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DropDatabase() error {
 | 
			
		||||
// DropDatabase will DROP each table Statup created
 | 
			
		||||
func (db *DbConfig) DropDatabase() error {
 | 
			
		||||
	utils.Log(1, "Dropping Database Tables...")
 | 
			
		||||
	down, err := source.SqlBox.String("down.sql")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	requests := strings.Split(down, ";")
 | 
			
		||||
	for _, request := range requests {
 | 
			
		||||
		_, err := DbSession.Exec(request)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.Log(2, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
	err := DbSession.DropTableIfExists("checkins")
 | 
			
		||||
	err = DbSession.DropTableIfExists("communication")
 | 
			
		||||
	err = DbSession.DropTableIfExists("core")
 | 
			
		||||
	err = DbSession.DropTableIfExists("failures")
 | 
			
		||||
	err = DbSession.DropTableIfExists("hits")
 | 
			
		||||
	err = DbSession.DropTableIfExists("services")
 | 
			
		||||
	err = DbSession.DropTableIfExists("users")
 | 
			
		||||
	return err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CreateDatabase() error {
 | 
			
		||||
// CreateDatabase will CREATE TABLES for each of the Statup elements
 | 
			
		||||
func (db *DbConfig) CreateDatabase() error {
 | 
			
		||||
	utils.Log(1, "Creating Database Tables...")
 | 
			
		||||
	sql := "postgres_up.sql"
 | 
			
		||||
	if CoreApp.DbConnection == "mysql" {
 | 
			
		||||
		sql = "mysql_up.sql"
 | 
			
		||||
	} else if CoreApp.DbConnection == "sqlite" {
 | 
			
		||||
		sql = "sqlite_up.sql"
 | 
			
		||||
	}
 | 
			
		||||
	up, err := source.SqlBox.String(sql)
 | 
			
		||||
	requests := strings.Split(up, ";")
 | 
			
		||||
	for _, request := range requests {
 | 
			
		||||
		_, err := DbSession.Exec(request)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.Log(2, err)
 | 
			
		||||
	err := DbSession.CreateTable(&types.Checkin{})
 | 
			
		||||
	err = DbSession.Table("communication").CreateTable(¬ifiers.Notification{})
 | 
			
		||||
	err = DbSession.Table("core").CreateTable(&types.Core{})
 | 
			
		||||
	err = DbSession.CreateTable(&types.Failure{})
 | 
			
		||||
	err = DbSession.CreateTable(&types.Hit{})
 | 
			
		||||
	err = DbSession.CreateTable(&types.Service{})
 | 
			
		||||
	err = DbSession.CreateTable(&types.User{})
 | 
			
		||||
	utils.Log(1, "Statup Database Created")
 | 
			
		||||
	return err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MigrateDatabase will migrate the database structure to current version.
 | 
			
		||||
// This function will NOT remove previous records, tables or columns from the database.
 | 
			
		||||
// If this function has an issue, it will ROLLBACK to the previous state.
 | 
			
		||||
func (db *DbConfig) MigrateDatabase() error {
 | 
			
		||||
	utils.Log(1, "Migrating Database Tables...")
 | 
			
		||||
 | 
			
		||||
	tx := DbSession.Begin()
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if r := recover(); r != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	if tx.Error != nil {
 | 
			
		||||
		return tx.Error
 | 
			
		||||
	}
 | 
			
		||||
	//secret := NewSHA1Hash()
 | 
			
		||||
	//db.QueryRow("INSERT INTO core (secret, version) VALUES ($1, $2);", secret, VERSION).Scan()
 | 
			
		||||
	utils.Log(1, "Database Created")
 | 
			
		||||
	//SampleData()
 | 
			
		||||
	return err
 | 
			
		||||
	tx = tx.AutoMigrate(&types.Service{}, &types.User{}, &types.Hit{}, &types.Failure{}, &types.Checkin{}).Table("core").AutoMigrate(&types.Core{}).Table("communication").AutoMigrate(¬ifiers.Notification{})
 | 
			
		||||
	if tx.Error != nil {
 | 
			
		||||
		tx.Rollback()
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Statup Database could not be migrated: %v", tx.Error))
 | 
			
		||||
		return tx.Error
 | 
			
		||||
	}
 | 
			
		||||
	utils.Log(1, "Statup Database Migrated")
 | 
			
		||||
	return tx.Commit().Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *DbConfig) Clean() *DbConfig {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,12 +19,12 @@ import (
 | 
			
		|||
	"github.com/fatih/structs"
 | 
			
		||||
	"github.com/hunterlong/statup/notifiers"
 | 
			
		||||
	"github.com/hunterlong/statup/types"
 | 
			
		||||
	"upper.io/db.v3/lib/sqlbuilder"
 | 
			
		||||
	"github.com/jinzhu/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func OnLoad(db sqlbuilder.Database) {
 | 
			
		||||
func OnLoad(db *gorm.DB) {
 | 
			
		||||
	for _, p := range CoreApp.AllPlugins {
 | 
			
		||||
		p.OnLoad(db)
 | 
			
		||||
		p.OnLoad(*db)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,11 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
func injectDatabase() {
 | 
			
		||||
	DbConnection(Configs.Connection, false, utils.Directory)
 | 
			
		||||
	Configs.Connect(false, utils.Directory)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GenerateSeed() {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ExportIndexHTML() string {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,23 +32,19 @@ func (s *Service) CreateFailure(f *types.Failure) (int64, error) {
 | 
			
		|||
	f.CreatedAt = time.Now()
 | 
			
		||||
	f.Service = s.Id
 | 
			
		||||
	s.Failures = append(s.Failures, f)
 | 
			
		||||
	col := DbSession.Collection("failures")
 | 
			
		||||
	uuid, err := col.Insert(f)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		return 0, err
 | 
			
		||||
	row := failuresDB().Create(f)
 | 
			
		||||
	if row.Error != nil {
 | 
			
		||||
		utils.Log(3, row.Error)
 | 
			
		||||
		return 0, row.Error
 | 
			
		||||
	}
 | 
			
		||||
	if uuid == nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return uuid.(int64), err
 | 
			
		||||
	return f.Id, row.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) AllFailures() []*types.Failure {
 | 
			
		||||
	var fails []*types.Failure
 | 
			
		||||
	col := DbSession.Collection("failures").Find("service", s.Id).OrderBy("-id")
 | 
			
		||||
	err := col.All(&fails)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	col := failuresDB().Where("service = ?", s.Id).Order("id desc")
 | 
			
		||||
	err := col.Find(&fails)
 | 
			
		||||
	if err.Error != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Issue getting failures for service %v, %v", s.Name, err))
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -56,8 +52,8 @@ func (s *Service) AllFailures() []*types.Failure {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (u *Service) DeleteFailures() {
 | 
			
		||||
	_, err := DbSession.Exec(`DELETE FROM failures WHERE service = ?`, u.Id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	err := DbSession.Exec(`DELETE FROM failures WHERE service = ?`, u.Id)
 | 
			
		||||
	if err.Error != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("failed to delete all failures: %v", err))
 | 
			
		||||
	}
 | 
			
		||||
	u.Failures = nil
 | 
			
		||||
| 
						 | 
				
			
			@ -65,48 +61,48 @@ func (u *Service) DeleteFailures() {
 | 
			
		|||
 | 
			
		||||
func (s *Service) LimitedFailures() []*Failure {
 | 
			
		||||
	var failArr []*Failure
 | 
			
		||||
	col := DbSession.Collection("failures").Find("service", s.Id).OrderBy("-id").Limit(10)
 | 
			
		||||
	col.All(&failArr)
 | 
			
		||||
	col := failuresDB().Where("service = ?", s.Id).Order("id desc").Limit(10)
 | 
			
		||||
	col.Find(&failArr)
 | 
			
		||||
	return failArr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func reverseFailures(input []*Failure) []*Failure {
 | 
			
		||||
	if len(input) == 0 {
 | 
			
		||||
		return input
 | 
			
		||||
	}
 | 
			
		||||
	return append(reverseFailures(input[1:]), input[0])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *Failure) Ago() string {
 | 
			
		||||
	got, _ := timeago.TimeAgoWithTime(time.Now(), f.CreatedAt)
 | 
			
		||||
	return got
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *Failure) Delete() error {
 | 
			
		||||
	col := DbSession.Collection("failures").Find("id", f.Id)
 | 
			
		||||
	return col.Delete()
 | 
			
		||||
	db := failuresDB().Delete(f)
 | 
			
		||||
	return db.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CountFailures() uint64 {
 | 
			
		||||
	col := DbSession.Collection("failures").Find()
 | 
			
		||||
	amount, err := col.Count()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(2, err)
 | 
			
		||||
	var count uint64
 | 
			
		||||
	err := failuresDB().Count(&count)
 | 
			
		||||
	if err.Error != nil {
 | 
			
		||||
		utils.Log(2, err.Error)
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return amount
 | 
			
		||||
	return count
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) TotalFailures24() (uint64, error) {
 | 
			
		||||
	ago := time.Now().Add(-24 * time.Hour)
 | 
			
		||||
	return s.TotalFailuresSince(ago)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) TotalFailures() (uint64, error) {
 | 
			
		||||
	col := DbSession.Collection("failures").Find("service", s.Id)
 | 
			
		||||
	amount, err := col.Count()
 | 
			
		||||
	return amount, err
 | 
			
		||||
	var count uint64
 | 
			
		||||
	rows := failuresDB().Where("service = ?", s.Id)
 | 
			
		||||
	err := rows.Count(&count)
 | 
			
		||||
	return count, err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) TotalFailures24Hours() (uint64, error) {
 | 
			
		||||
	col := DbSession.Collection("failures").Find("service", s.Id)
 | 
			
		||||
	amount, err := col.Count()
 | 
			
		||||
	return amount, err
 | 
			
		||||
func (s *Service) TotalFailuresSince(ago time.Time) (uint64, error) {
 | 
			
		||||
	var count uint64
 | 
			
		||||
	rows := failuresDB().Where("service = ? AND created_at > ?", s.Id, ago.Format("2006-01-02 15:04:05"))
 | 
			
		||||
	err := rows.Count(&count)
 | 
			
		||||
	return count, err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *Failure) ParseError() string {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								core/hits.go
								
								
								
								
							
							
						
						
									
										49
									
								
								core/hits.go
								
								
								
								
							| 
						 | 
				
			
			@ -19,40 +19,33 @@ import (
 | 
			
		|||
	"github.com/hunterlong/statup/types"
 | 
			
		||||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
	"time"
 | 
			
		||||
	"upper.io/db.v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Hit struct {
 | 
			
		||||
	*types.Hit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hitCol() db.Collection {
 | 
			
		||||
	return DbSession.Collection("hits")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) CreateHit(h *types.Hit) (int64, error) {
 | 
			
		||||
	h.CreatedAt = time.Now()
 | 
			
		||||
	h.Service = s.Id
 | 
			
		||||
	uuid, err := hitCol().Insert(h)
 | 
			
		||||
	if uuid == nil {
 | 
			
		||||
		utils.Log(2, err)
 | 
			
		||||
		return 0, err
 | 
			
		||||
	db := hitsDB().Create(h)
 | 
			
		||||
	if db.Error != nil {
 | 
			
		||||
		utils.Log(2, db.Error)
 | 
			
		||||
		return 0, db.Error
 | 
			
		||||
	}
 | 
			
		||||
	return uuid.(int64), err
 | 
			
		||||
	return h.Id, db.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) Hits() ([]*Hit, error) {
 | 
			
		||||
	var hits []*Hit
 | 
			
		||||
	col := hitCol().Find("service", s.Id).OrderBy("-id")
 | 
			
		||||
	err := col.All(&hits)
 | 
			
		||||
	return hits, err
 | 
			
		||||
	col := hitsDB().Where("service = ?", s.Id).Order("id desc")
 | 
			
		||||
	err := col.Find(&hits)
 | 
			
		||||
	return hits, err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) LimitedHits() ([]*Hit, error) {
 | 
			
		||||
	var hits []*Hit
 | 
			
		||||
	col := hitCol().Find("service", s.Id).OrderBy("-id").Limit(1024)
 | 
			
		||||
	err := col.All(&hits)
 | 
			
		||||
	return reverseHits(hits), err
 | 
			
		||||
	col := hitsDB().Where("service = ?", s.Id).Order("id desc").Limit(1024)
 | 
			
		||||
	err := col.Find(&hits)
 | 
			
		||||
	return reverseHits(hits), err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func reverseHits(input []*Hit) []*Hit {
 | 
			
		||||
| 
						 | 
				
			
			@ -64,15 +57,23 @@ func reverseHits(input []*Hit) []*Hit {
 | 
			
		|||
 | 
			
		||||
func (s *Service) SelectHitsGroupBy(group string) ([]*Hit, error) {
 | 
			
		||||
	var hits []*Hit
 | 
			
		||||
	col := hitCol().Find("service", s.Id)
 | 
			
		||||
	err := col.All(&hits)
 | 
			
		||||
	return hits, err
 | 
			
		||||
	col := hitsDB().Where("service = ?", s.Id)
 | 
			
		||||
	err := col.Find(&hits)
 | 
			
		||||
	return hits, err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) TotalHits() (uint64, error) {
 | 
			
		||||
	col := hitCol().Find("service", s.Id)
 | 
			
		||||
	amount, err := col.Count()
 | 
			
		||||
	return amount, err
 | 
			
		||||
	var count uint64
 | 
			
		||||
	col := hitsDB().Where("service = ?", s.Id)
 | 
			
		||||
	err := col.Count(&count)
 | 
			
		||||
	return count, err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) TotalHitsSince(ago time.Time) (uint64, error) {
 | 
			
		||||
	var count uint64
 | 
			
		||||
	rows := hitsDB().Where("service = ? AND created_at > ?", s.Id, ago.Format("2006-01-02 15:04:05"))
 | 
			
		||||
	err := rows.Count(&count)
 | 
			
		||||
	return count, err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) Sum() (float64, error) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										111
									
								
								core/services.go
								
								
								
								
							
							
						
						
									
										111
									
								
								core/services.go
								
								
								
								
							| 
						 | 
				
			
			@ -22,7 +22,6 @@ import (
 | 
			
		|||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
	"upper.io/db.v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Service struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -30,16 +29,12 @@ type Service struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func ReturnService(s *types.Service) *Service {
 | 
			
		||||
	return &Service{Service: s}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serviceCol() db.Collection {
 | 
			
		||||
	return DbSession.Collection("services")
 | 
			
		||||
	return &Service{s}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectService(id int64) *Service {
 | 
			
		||||
	for _, s := range CoreApp.Services() {
 | 
			
		||||
		if s.Id == id {
 | 
			
		||||
		if s.Service.Id == id {
 | 
			
		||||
			return s
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -49,11 +44,10 @@ func SelectService(id int64) *Service {
 | 
			
		|||
func (c *Core) SelectAllServices() ([]*types.Service, error) {
 | 
			
		||||
	var services []*types.Service
 | 
			
		||||
	var servs []*types.Service
 | 
			
		||||
	col := serviceCol().Find().OrderBy("order_id")
 | 
			
		||||
	err := col.All(&services)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("service error: %v", err))
 | 
			
		||||
		return nil, err
 | 
			
		||||
	db := servicesDB().Find(&services).Order("order_id desc")
 | 
			
		||||
	if db.Error != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("service error: %v", db.Error))
 | 
			
		||||
		return nil, db.Error
 | 
			
		||||
	}
 | 
			
		||||
	for _, ser := range services {
 | 
			
		||||
		single := ReturnService(ser)
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +57,7 @@ func (c *Core) SelectAllServices() ([]*types.Service, error) {
 | 
			
		|||
		servs = append(servs, single.Service)
 | 
			
		||||
	}
 | 
			
		||||
	CoreApp.SetServices(servs)
 | 
			
		||||
	return services, err
 | 
			
		||||
	return services, db.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) ToJSON() string {
 | 
			
		||||
| 
						 | 
				
			
			@ -84,12 +78,17 @@ func (s *Service) AvgTime() float64 {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) Online24() float32 {
 | 
			
		||||
	total, _ := s.TotalHits()
 | 
			
		||||
	failed, _ := s.TotalFailures24Hours()
 | 
			
		||||
	ago := time.Now().Add(-24 * time.Hour)
 | 
			
		||||
	return s.OnlineSince(ago)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) OnlineSince(ago time.Time) float32 {
 | 
			
		||||
	failed, _ := s.TotalFailuresSince(ago)
 | 
			
		||||
	if failed == 0 {
 | 
			
		||||
		s.Online24Hours = 100.00
 | 
			
		||||
		return s.Online24Hours
 | 
			
		||||
	}
 | 
			
		||||
	total, _ := s.TotalHitsSince(ago)
 | 
			
		||||
	if total == 0 {
 | 
			
		||||
		s.Online24Hours = 0
 | 
			
		||||
		return s.Online24Hours
 | 
			
		||||
| 
						 | 
				
			
			@ -150,16 +149,17 @@ func (s *Service) GraphData() string {
 | 
			
		|||
	var d []*DateScan
 | 
			
		||||
	since := time.Now().Add(time.Hour*-24 + time.Minute*0 + time.Second*0)
 | 
			
		||||
	sql := GroupDataBy("hits", s.Id, since, "minute")
 | 
			
		||||
	dated, err := DbSession.Query(db.Raw(sql))
 | 
			
		||||
	rows, err := DbSession.Raw(sql).Rows()
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(2, err)
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	for dated.Next() {
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		gd := new(DateScan)
 | 
			
		||||
		var tt string
 | 
			
		||||
		var ff float64
 | 
			
		||||
		err := dated.Scan(&tt, &ff)
 | 
			
		||||
		err := rows.Scan(&tt, &ff)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.Log(2, fmt.Sprintf("Issue loading chart data for service %v, %v", s.Name, err))
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -178,27 +178,45 @@ func (s *Service) GraphData() string {
 | 
			
		|||
	return string(data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) AvgUptime() string {
 | 
			
		||||
	failed, _ := s.TotalFailures()
 | 
			
		||||
	total, _ := s.TotalHits()
 | 
			
		||||
func (s *Service) AvgUptime24() string {
 | 
			
		||||
	ago := time.Now().Add(-24 * time.Hour)
 | 
			
		||||
	return s.AvgUptime(ago)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) AvgUptime(ago time.Time) string {
 | 
			
		||||
	failed, _ := s.TotalFailuresSince(ago)
 | 
			
		||||
	if failed == 0 {
 | 
			
		||||
		s.TotalUptime = "100"
 | 
			
		||||
		return s.TotalUptime
 | 
			
		||||
		return "100"
 | 
			
		||||
	}
 | 
			
		||||
	total, _ := s.TotalHitsSince(ago)
 | 
			
		||||
	if total == 0 {
 | 
			
		||||
		s.TotalUptime = "0"
 | 
			
		||||
		return s.TotalUptime
 | 
			
		||||
		return "0"
 | 
			
		||||
	}
 | 
			
		||||
	percent := float64(failed) / float64(total) * 100
 | 
			
		||||
	percent = 100 - percent
 | 
			
		||||
	if percent < 0 {
 | 
			
		||||
		percent = 0
 | 
			
		||||
	}
 | 
			
		||||
	s.TotalUptime = fmt.Sprintf("%0.2f", percent)
 | 
			
		||||
	if s.TotalUptime == "100.00" {
 | 
			
		||||
		s.TotalUptime = "100"
 | 
			
		||||
	amount := fmt.Sprintf("%0.2f", percent)
 | 
			
		||||
	if amount == "100.00" {
 | 
			
		||||
		amount = "100"
 | 
			
		||||
	}
 | 
			
		||||
	return s.TotalUptime
 | 
			
		||||
	return amount
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) TotalUptime() string {
 | 
			
		||||
	hits, _ := s.TotalHits()
 | 
			
		||||
	failures, _ := s.TotalFailures()
 | 
			
		||||
	percent := float64(failures) / float64(hits) * 100
 | 
			
		||||
	percent = 100 - percent
 | 
			
		||||
	if percent < 0 {
 | 
			
		||||
		percent = 0
 | 
			
		||||
	}
 | 
			
		||||
	amount := fmt.Sprintf("%0.2f", percent)
 | 
			
		||||
	if amount == "100.00" {
 | 
			
		||||
		amount = "100"
 | 
			
		||||
	}
 | 
			
		||||
	return amount
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) index() int {
 | 
			
		||||
| 
						 | 
				
			
			@ -217,25 +235,27 @@ func updateService(service *Service) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (u *Service) Delete() error {
 | 
			
		||||
	res := serviceCol().Find("id", u.Id)
 | 
			
		||||
	err := res.Delete()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to delete service %v. %v", u.Name, err))
 | 
			
		||||
		return err
 | 
			
		||||
	err := servicesDB().Delete(u)
 | 
			
		||||
	if err.Error != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to delete service %v. %v", u.Name, err.Error))
 | 
			
		||||
		return err.Error
 | 
			
		||||
	}
 | 
			
		||||
	u.Close()
 | 
			
		||||
	CoreApp.RemoveService(u.index())
 | 
			
		||||
	OnDeletedService(u)
 | 
			
		||||
	return err
 | 
			
		||||
	return err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *Service) UpdateSingle(attr ...interface{}) error {
 | 
			
		||||
	return servicesDB().Model(u).Update(attr).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *Service) Update(restart bool) error {
 | 
			
		||||
	u.CreatedAt = time.Now()
 | 
			
		||||
	res := serviceCol().Find("id", u.Id)
 | 
			
		||||
	err := res.Update(u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	err := servicesDB().Update(u)
 | 
			
		||||
	if err.Error != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to update service %v. %v", u.Name, err))
 | 
			
		||||
		return err
 | 
			
		||||
		return err.Error
 | 
			
		||||
	}
 | 
			
		||||
	if restart {
 | 
			
		||||
		u.Close()
 | 
			
		||||
| 
						 | 
				
			
			@ -245,20 +265,19 @@ func (u *Service) Update(restart bool) error {
 | 
			
		|||
		go u.CheckQueue(true)
 | 
			
		||||
	}
 | 
			
		||||
	OnUpdateService(u)
 | 
			
		||||
	return err
 | 
			
		||||
	return err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *Service) Create() (int64, error) {
 | 
			
		||||
	u.CreatedAt = time.Now()
 | 
			
		||||
	uuid, err := serviceCol().Insert(u)
 | 
			
		||||
	if uuid == nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to create service %v. %v", u.Name, err))
 | 
			
		||||
		return 0, err
 | 
			
		||||
	db := servicesDB().Create(u)
 | 
			
		||||
	if db.Error != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to create service %v #%v: %v", u.Name, u.Id, db.Error))
 | 
			
		||||
		return 0, db.Error
 | 
			
		||||
	}
 | 
			
		||||
	u.Id = uuid.(int64)
 | 
			
		||||
	u.Start()
 | 
			
		||||
	CoreApp.AddService(u.Service)
 | 
			
		||||
	return uuid.(int64), err
 | 
			
		||||
	return u.Id, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CountOnline() int {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,23 +26,29 @@ var (
 | 
			
		|||
	newServiceId int64
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestSelectHTTPService(t *testing.T) {
 | 
			
		||||
	services, err := CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 18, len(services))
 | 
			
		||||
	assert.Equal(t, "Google", services[0].Name)
 | 
			
		||||
	assert.Equal(t, "http", services[0].Type)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSelectAllServices(t *testing.T) {
 | 
			
		||||
	services := CoreApp.Services()
 | 
			
		||||
	for _, s := range services {
 | 
			
		||||
		service := s.Check(true)
 | 
			
		||||
		assert.True(t, service.Online)
 | 
			
		||||
		assert.True(t, service.IsRunning())
 | 
			
		||||
		t.Logf("ID: %v %v\n", s.Id, s.Name)
 | 
			
		||||
	}
 | 
			
		||||
	assert.Equal(t, 5, len(services))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSelectHTTPService(t *testing.T) {
 | 
			
		||||
	service := SelectService(1)
 | 
			
		||||
	assert.Equal(t, "Google", service.Name)
 | 
			
		||||
	assert.Equal(t, "http", service.Type)
 | 
			
		||||
	assert.Equal(t, 18, len(services))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSelectTCPService(t *testing.T) {
 | 
			
		||||
	services := CoreApp.Services()
 | 
			
		||||
	assert.Equal(t, 18, len(services))
 | 
			
		||||
	service := SelectService(5)
 | 
			
		||||
	assert.NotNil(t, service)
 | 
			
		||||
	assert.Equal(t, "Google DNS", service.Name)
 | 
			
		||||
	assert.Equal(t, "tcp", service.Type)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -105,9 +111,14 @@ func TestCheckTCPService(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceOnline24Hours(t *testing.T) {
 | 
			
		||||
	service := SelectService(5)
 | 
			
		||||
	amount := service.Online24()
 | 
			
		||||
	assert.Equal(t, float32(100), amount)
 | 
			
		||||
	since, err := time.Parse(time.RFC3339, SERVICE_SINCE)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	service := SelectService(1)
 | 
			
		||||
	assert.Equal(t, float32(83.33), service.OnlineSince(since))
 | 
			
		||||
	service2 := SelectService(5)
 | 
			
		||||
	assert.Equal(t, float32(100), service2.OnlineSince(since))
 | 
			
		||||
	service3 := SelectService(18)
 | 
			
		||||
	assert.Equal(t, float32(0), service3.OnlineSince(since))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceSmallText(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -117,30 +128,35 @@ func TestServiceSmallText(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceAvgUptime(t *testing.T) {
 | 
			
		||||
	service := SelectService(5)
 | 
			
		||||
	uptime := service.AvgUptime()
 | 
			
		||||
	assert.Equal(t, "100", uptime)
 | 
			
		||||
	since, err := time.Parse(time.RFC3339, SERVICE_SINCE)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	service := SelectService(1)
 | 
			
		||||
	assert.Equal(t, "83.33", service.AvgUptime(since))
 | 
			
		||||
	service2 := SelectService(5)
 | 
			
		||||
	assert.Equal(t, "100", service2.AvgUptime(since))
 | 
			
		||||
	service3 := SelectService(18)
 | 
			
		||||
	assert.Equal(t, "0.00", service3.AvgUptime(since))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceHits(t *testing.T) {
 | 
			
		||||
	service := SelectService(5)
 | 
			
		||||
	hits, err := service.Hits()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, int(2), len(hits))
 | 
			
		||||
	assert.Equal(t, int(5), len(hits))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceLimitedHits(t *testing.T) {
 | 
			
		||||
	service := SelectService(5)
 | 
			
		||||
	hits, err := service.LimitedHits()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, int(2), len(hits))
 | 
			
		||||
	assert.Equal(t, int(5), len(hits))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceTotalHits(t *testing.T) {
 | 
			
		||||
	service := SelectService(5)
 | 
			
		||||
	hits, err := service.TotalHits()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, uint64(0x2), hits)
 | 
			
		||||
	assert.Equal(t, uint64(0x5), hits)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceSum(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +192,6 @@ func TestCreateService(t *testing.T) {
 | 
			
		|||
func TestViewNewService(t *testing.T) {
 | 
			
		||||
	newService := SelectService(newServiceId)
 | 
			
		||||
	assert.Equal(t, "That'll do 🐢", newService.Name)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateFailingHTTPService(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -195,10 +210,12 @@ func TestCreateFailingHTTPService(t *testing.T) {
 | 
			
		|||
	assert.NotZero(t, newServiceId)
 | 
			
		||||
	newService := SelectService(newServiceId)
 | 
			
		||||
	assert.Equal(t, "Bad URL", newService.Name)
 | 
			
		||||
	t.Log("new service ID: ", newServiceId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceFailedCheck(t *testing.T) {
 | 
			
		||||
	service := SelectService(7)
 | 
			
		||||
	service := SelectService(20)
 | 
			
		||||
	assert.Equal(t, "Bad URL", service.Name)
 | 
			
		||||
	checked := service.Check(true)
 | 
			
		||||
	assert.Equal(t, "Bad URL", checked.Name)
 | 
			
		||||
	assert.False(t, checked.Online)
 | 
			
		||||
| 
						 | 
				
			
			@ -219,10 +236,11 @@ func TestCreateFailingTCPService(t *testing.T) {
 | 
			
		|||
	assert.NotZero(t, newServiceId)
 | 
			
		||||
	newService := SelectService(newServiceId)
 | 
			
		||||
	assert.Equal(t, "Bad TCP", newService.Name)
 | 
			
		||||
	t.Log("new failing tcp service ID: ", newServiceId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceFailedTCPCheck(t *testing.T) {
 | 
			
		||||
	service := SelectService(8)
 | 
			
		||||
	service := SelectService(21)
 | 
			
		||||
	checked := service.Check(true)
 | 
			
		||||
	assert.Equal(t, "Bad TCP", checked.Name)
 | 
			
		||||
	assert.False(t, checked.Online)
 | 
			
		||||
| 
						 | 
				
			
			@ -244,13 +262,13 @@ func TestDeleteService(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	count, err := CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 8, len(count))
 | 
			
		||||
	assert.Equal(t, 21, len(count))
 | 
			
		||||
 | 
			
		||||
	err = service.Delete()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
 | 
			
		||||
	services := CoreApp.Services()
 | 
			
		||||
	assert.Equal(t, 7, len(services))
 | 
			
		||||
	assert.Equal(t, 20, len(services))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceCloseRoutine(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,36 +28,29 @@ type User struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func ReturnUser(u *types.User) *User {
 | 
			
		||||
	return &User{User: u}
 | 
			
		||||
	return &User{u}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectUser(id int64) (*User, error) {
 | 
			
		||||
	var user *User
 | 
			
		||||
	col := DbSession.Collection("users")
 | 
			
		||||
	res := col.Find("id", id)
 | 
			
		||||
	err := res.One(&user)
 | 
			
		||||
	return user, err
 | 
			
		||||
	var user User
 | 
			
		||||
	err := usersDB().First(&user, id)
 | 
			
		||||
	return &user, err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectUsername(username string) (*User, error) {
 | 
			
		||||
	var user *User
 | 
			
		||||
	col := DbSession.Collection("users")
 | 
			
		||||
	res := col.Find("username", username)
 | 
			
		||||
	err := res.One(&user)
 | 
			
		||||
	return user, err
 | 
			
		||||
	var user User
 | 
			
		||||
	res := usersDB().Where("username = ?", username)
 | 
			
		||||
	err := res.First(&user)
 | 
			
		||||
	return &user, err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *User) Delete() error {
 | 
			
		||||
	col := DbSession.Collection("users")
 | 
			
		||||
	user := col.Find("id", u.Id)
 | 
			
		||||
	return user.Delete()
 | 
			
		||||
	return usersDB().Delete(u).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *User) Update() error {
 | 
			
		||||
	u.CreatedAt = time.Now()
 | 
			
		||||
	col := DbSession.Collection("users")
 | 
			
		||||
	user := col.Find("id", u.Id)
 | 
			
		||||
	return user.Update(u)
 | 
			
		||||
	return usersDB().Update(u).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *User) Create() (int64, error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -65,39 +58,36 @@ func (u *User) Create() (int64, error) {
 | 
			
		|||
	u.Password = utils.HashPassword(u.Password)
 | 
			
		||||
	u.ApiKey = utils.NewSHA1Hash(5)
 | 
			
		||||
	u.ApiSecret = utils.NewSHA1Hash(10)
 | 
			
		||||
	col := DbSession.Collection("users")
 | 
			
		||||
	uuid, err := col.Insert(u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	db := usersDB().Create(u)
 | 
			
		||||
	if db.Error != nil {
 | 
			
		||||
		return 0, db.Error
 | 
			
		||||
	}
 | 
			
		||||
	if uuid == nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to create user %v. %v", u.Username, err))
 | 
			
		||||
		return 0, err
 | 
			
		||||
	if u.Id == 0 {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to create user %v. %v", u.Username, db.Error))
 | 
			
		||||
		return 0, db.Error
 | 
			
		||||
	}
 | 
			
		||||
	return uuid.(int64), err
 | 
			
		||||
	return u.Id, db.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectAllUsers() ([]*User, error) {
 | 
			
		||||
	var users []*User
 | 
			
		||||
	col := DbSession.Collection("users").Find()
 | 
			
		||||
	err := col.All(&users)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to load all users. %v", err))
 | 
			
		||||
	db := usersDB().Find(&users)
 | 
			
		||||
	if db.Error != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to load all users. %v", db.Error))
 | 
			
		||||
	}
 | 
			
		||||
	return users, err
 | 
			
		||||
	return users, db.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AuthUser(username, password string) (*User, bool) {
 | 
			
		||||
	var auth bool
 | 
			
		||||
	user, err := SelectUsername(username)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(2, err)
 | 
			
		||||
		return nil, false
 | 
			
		||||
	}
 | 
			
		||||
	if CheckHash(password, user.Password) {
 | 
			
		||||
		auth = true
 | 
			
		||||
		return user, true
 | 
			
		||||
	}
 | 
			
		||||
	return user, auth
 | 
			
		||||
	return nil, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CheckHash(password, hash string) bool {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,13 +36,13 @@ func TestCreateUser(t *testing.T) {
 | 
			
		|||
func TestSelectAllUsers(t *testing.T) {
 | 
			
		||||
	users, err := SelectAllUsers()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 1, len(users))
 | 
			
		||||
	assert.Equal(t, 2, len(users))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSelectUser(t *testing.T) {
 | 
			
		||||
	user, err := SelectUser(1)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, "test@email.com", user.Email)
 | 
			
		||||
	assert.Equal(t, "info@statup.io", user.Email)
 | 
			
		||||
	assert.True(t, user.Admin)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ func TestSelectUsername(t *testing.T) {
 | 
			
		|||
	user, err := SelectUsername("hunter")
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, "test@email.com", user.Email)
 | 
			
		||||
	assert.Equal(t, int64(1), user.Id)
 | 
			
		||||
	assert.Equal(t, int64(2), user.Id)
 | 
			
		||||
	assert.True(t, user.Admin)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +80,7 @@ func TestCreateUser2(t *testing.T) {
 | 
			
		|||
func TestSelectAllUsersAgain(t *testing.T) {
 | 
			
		||||
	users, err := SelectAllUsers()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 2, len(users))
 | 
			
		||||
	assert.Equal(t, 3, len(users))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAuthUser(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -88,12 +88,12 @@ func TestAuthUser(t *testing.T) {
 | 
			
		|||
	assert.True(t, auth)
 | 
			
		||||
	assert.NotNil(t, user)
 | 
			
		||||
	assert.Equal(t, "user@email.com", user.Email)
 | 
			
		||||
	assert.Equal(t, int64(2), user.Id)
 | 
			
		||||
	assert.Equal(t, int64(3), user.Id)
 | 
			
		||||
	assert.True(t, user.Admin)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestFailedAuthUser(t *testing.T) {
 | 
			
		||||
	user, auth := AuthUser("hunter", "wrongpassword")
 | 
			
		||||
	user, auth := AuthUser("hunterlong", "wrongpassword")
 | 
			
		||||
	assert.False(t, auth)
 | 
			
		||||
	assert.Nil(t, user)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -111,3 +111,8 @@ func TestDeleteUser(t *testing.T) {
 | 
			
		|||
	err = user.Delete()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDbConfig_Close(t *testing.T) {
 | 
			
		||||
	err := Configs.Close()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,142 @@
 | 
			
		|||
INSERT INTO core (name,description,config,api_key,api_secret,style,footer,domain,version,migration_id,use_cdn) VALUES ('Awesome Status','This is from the seed file!','config.yml','d2fead3e459bd14f570cf08527175b88b32d7faa','e351393306ea245de5f9588cbe8627c74db007c6','','Created by Hunter Long','','',0,false);
 | 
			
		||||
INSERT INTO services (name,domain,check_type,method,port,expected,expected_status,check_interval,post_data,order_id,timeout,created_at) VALUES
 | 
			
		||||
 ('Google','https://google.com','http','GET',0,'',200,10,'',0,10,'2018-08-31 10:42:08'),
 | 
			
		||||
 ('Statup Github','https://github.com/hunterlong/statup','http','GET',0,'',200,30,'',0,20,'2018-08-31 10:42:08'),
 | 
			
		||||
 ('JSON Users Test','https://jsonplaceholder.typicode.com/users','http','GET',0,'',200,60,'',0,30,'2018-08-31 10:42:08'),
 | 
			
		||||
 ('JSON API Tester','https://jsonplaceholder.typicode.com/posts','http','POST',0,'(title)": "((\\"|[statup])*)"',201,30,'{ "title": "statup", "body": "bar", "userId": 19999 }',0,30,'2018-08-31 10:42:08'),
 | 
			
		||||
 ('Google DNS','8.8.8.8','tcp','',53,'',0,20,'',0,120,'2018-08-31 10:42:08'),
 | 
			
		||||
 ('The Bravery - An Honest Mistake','https://www.youtube.com/watch?v=O8vzbezVru4','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14'),
 | 
			
		||||
 ('Upper.io','https://upper.io/db.v3/','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14'),
 | 
			
		||||
 ('CoinApp Status','https://status.coinapp.io','http','GET',0,'',200,1,'',0,30,'2018-08-31 10:42:16'),
 | 
			
		||||
 ('Demo Page','https://demo.statup.io','http','GET',0,'',200,2,'',0,30,'2018-08-31 10:42:16'),
 | 
			
		||||
 ('Golang','https://golang.org','http','GET',0,'',200,3,'',0,30,'2018-08-31 10:42:16'),
 | 
			
		||||
 ('Github','https://github.com/hunterlong','http','GET',0,'',200,4,'',0,30,'2018-08-31 10:42:17'),
 | 
			
		||||
 ('Santa Monica','https://www.santamonica.com','http','GET',0,'',200,5,'',0,30,'2018-08-31 10:42:17'),
 | 
			
		||||
 ('Oeschs Die Dritten','https://www.oeschs-die-dritten.ch/en/','http','GET',0,'',200,6,'',0,30,'2018-08-31 10:42:18'),
 | 
			
		||||
 ('EtherScan.io','https://etherscan.io','http','GET',0,'',200,7,'',0,30,'2018-08-31 10:42:20'),
 | 
			
		||||
 ('Test Service 7','https://www.youtube.com/watch?v=ipvEIZMMILA','http','GET',0,'',200,8,'',0,30,'2018-08-31 10:42:20'),
 | 
			
		||||
 ('Test Service 8','https://www.youtube.com/watch?v=UdaYVxYF1Ok','http','GET',0,'',200,9,'',0,30,'2018-08-31 10:42:20'),
 | 
			
		||||
 ('Test Service 9','https://www.youtube.com/watch?v=yydZbVoCbn0&t=870s','http','GET',0,'',200,10,'',0,30,'2018-08-31 10:42:20'),
 | 
			
		||||
 ('Failing URL','http://failingdomainsarenofunatall.com','http','GET',0,'',200,11,'',0,30,'2018-08-31 10:42:20');
 | 
			
		||||
INSERT INTO users (username,password,email,api_key,api_secret,administrator,created_at) VALUES
 | 
			
		||||
 ('admin','$2a$14$Aye3yHae0ml6WRtvdgkRnO19OFze0IKF6IOHrdLpETtwLjnPelMUm','info@statup.io','27aa701119fb561d734eb4469cf13ba2550007e2','29de07014d32fbbbb80053ef3c19b464b2b72f64',1,'2018-08-31 10:42:07');
 | 
			
		||||
INSERT INTO hits (service,latency,created_at) VALUES
 | 
			
		||||
 (5,0.006504081,'2018-08-29 10:42:08'),
 | 
			
		||||
 (3,0.202164333,'2018-08-29 10:42:08'),
 | 
			
		||||
 (4,0.376675172,'2018-08-29 10:42:09'),
 | 
			
		||||
 (1,0.413912204,'2018-08-29 10:42:09'),
 | 
			
		||||
 (1,0.473912204,'2018-08-29 10:42:09'),
 | 
			
		||||
 (2,0.528427935,'2018-08-29 10:42:09'),
 | 
			
		||||
 (6,0.11930188,'2018-08-29 10:42:09'),
 | 
			
		||||
 (7,0.001062722,'2018-08-29 10:42:09'),
 | 
			
		||||
 (7,0.004046882,'2018-08-29 10:42:09'),
 | 
			
		||||
 (6,0.063360069,'2018-08-29 10:42:09'),
 | 
			
		||||
 (8,0.168951416,'2018-08-29 10:42:16'),
 | 
			
		||||
 (8,0.069032763,'2018-08-29 10:42:16'),
 | 
			
		||||
 (9,0.47712966,'2018-08-29 10:42:16'),
 | 
			
		||||
 (10,0.104510482,'2018-08-29 10:42:17'),
 | 
			
		||||
 (10,0.062536146,'2018-08-29 10:42:17'),
 | 
			
		||||
 (9,0.352823197,'2018-08-29 10:42:09'),
 | 
			
		||||
 (8,0.38226374,'2018-08-29 10:42:09'),
 | 
			
		||||
 (11,0.857324393,'2018-08-29 10:42:17'),
 | 
			
		||||
 (12,0.113320285,'2018-08-29 10:42:18'),
 | 
			
		||||
 (12,0.038532321,'2018-08-29 10:42:18'),
 | 
			
		||||
 (8,0.123430059,'2018-08-29 10:42:18'),
 | 
			
		||||
 (11,0.625290389,'2018-08-29 10:42:18'),
 | 
			
		||||
 (1,0.091823417,'2018-08-29 10:42:18'),
 | 
			
		||||
 (9,0.246651097,'2018-08-29 10:42:19'),
 | 
			
		||||
 (8,0.222901604,'2018-08-29 10:42:19'),
 | 
			
		||||
 (13,1.600367041,'2018-08-29 10:42:20'),
 | 
			
		||||
 (10,0.050076397,'2018-08-29 10:42:20'),
 | 
			
		||||
 (14,0.460363958,'2018-08-29 10:42:20'),
 | 
			
		||||
 (8,0.252590543,'2018-08-29 10:42:20'),
 | 
			
		||||
 (15,0.144109113,'2018-08-29 10:42:20'),
 | 
			
		||||
 (15,0.059993314,'2018-08-29 10:42:20'),
 | 
			
		||||
 (16,0.058810662,'2018-08-29 10:42:20'),
 | 
			
		||||
 (17,0.061824594,'2018-08-29 10:42:20'),
 | 
			
		||||
 (16,0.074584583,'2018-08-29 10:42:20'),
 | 
			
		||||
 (17,0.057086551,'2018-08-29 10:42:20'),
 | 
			
		||||
 (18,0.020983572,'2018-08-29 10:42:20'),
 | 
			
		||||
 (5,0.006504081,'2018-08-30 10:42:08'),
 | 
			
		||||
 (3,0.202164333,'2018-08-30 10:42:08'),
 | 
			
		||||
 (4,0.376675172,'2018-08-30 10:42:09'),
 | 
			
		||||
 (1,0.413912204,'2018-08-30 10:42:09'),
 | 
			
		||||
 (2,0.528427935,'2018-08-30 10:42:09'),
 | 
			
		||||
 (6,0.11930188,'2018-08-30 10:42:14'),
 | 
			
		||||
 (7,0.001062722,'2018-08-30 10:42:14'),
 | 
			
		||||
 (7,0.004046882,'2018-08-30 10:42:14'),
 | 
			
		||||
 (6,0.063360069,'2018-08-30 10:42:14'),
 | 
			
		||||
 (8,0.168951416,'2018-08-30 10:42:16'),
 | 
			
		||||
 (8,0.069032763,'2018-08-30 10:42:16'),
 | 
			
		||||
 (9,0.47712966,'2018-08-30 10:42:16'),
 | 
			
		||||
 (10,0.104510482,'2018-08-30 10:42:17'),
 | 
			
		||||
 (10,0.062536146,'2018-08-30 10:42:17'),
 | 
			
		||||
 (9,0.352823197,'2018-08-30 10:42:17'),
 | 
			
		||||
 (8,0.38226374,'2018-08-30 10:42:17'),
 | 
			
		||||
 (11,0.857324393,'2018-08-30 10:42:17'),
 | 
			
		||||
 (12,0.113320285,'2018-08-30 10:42:18'),
 | 
			
		||||
 (12,0.038532321,'2018-08-30 10:42:18'),
 | 
			
		||||
 (8,0.123430059,'2018-08-30 10:42:18'),
 | 
			
		||||
 (11,0.625290389,'2018-08-30 10:42:18'),
 | 
			
		||||
 (1,0.091823417,'2018-08-30 10:42:18'),
 | 
			
		||||
 (9,0.246651097,'2018-08-30 10:42:19'),
 | 
			
		||||
 (8,0.222901604,'2018-08-30 10:42:19'),
 | 
			
		||||
 (13,1.600367041,'2018-08-30 10:42:20'),
 | 
			
		||||
 (10,0.050076397,'2018-08-30 10:42:20'),
 | 
			
		||||
 (14,0.460363958,'2018-08-30 10:42:20'),
 | 
			
		||||
 (8,0.252590543,'2018-08-30 10:42:20'),
 | 
			
		||||
 (15,0.144109113,'2018-08-30 10:42:20'),
 | 
			
		||||
 (15,0.059993314,'2018-08-30 10:42:20'),
 | 
			
		||||
 (16,0.058810662,'2018-08-30 10:42:20'),
 | 
			
		||||
 (17,0.061824594,'2018-08-30 10:42:20'),
 | 
			
		||||
 (16,0.074584583,'2018-08-30 10:42:20'),
 | 
			
		||||
 (17,0.057086551,'2018-08-30 10:42:20'),
 | 
			
		||||
 (18,0.020983572,'2018-08-30 10:42:20'),
 | 
			
		||||
 (5,0.006504081,'2018-08-31 10:42:08'),
 | 
			
		||||
 (3,0.202164333,'2018-08-31 10:42:08'),
 | 
			
		||||
 (4,0.376675172,'2018-08-31 10:42:09'),
 | 
			
		||||
 (1,0.413912204,'2018-08-31 10:42:09'),
 | 
			
		||||
 (2,0.528427935,'2018-08-31 10:42:09'),
 | 
			
		||||
 (6,0.11930188,'2018-08-31 10:42:14'),
 | 
			
		||||
 (7,0.001062722,'2018-08-31 10:42:14'),
 | 
			
		||||
 (7,0.004046882,'2018-08-31 10:42:14'),
 | 
			
		||||
 (6,0.063360069,'2018-08-31 10:42:14'),
 | 
			
		||||
 (8,0.168951416,'2018-08-31 10:42:16'),
 | 
			
		||||
 (8,0.069032763,'2018-08-31 10:42:16'),
 | 
			
		||||
 (9,0.47712966,'2018-08-31 10:42:16'),
 | 
			
		||||
 (10,0.104510482,'2018-08-31 10:42:17'),
 | 
			
		||||
 (10,0.062536146,'2018-08-31 10:42:17'),
 | 
			
		||||
 (9,0.352823197,'2018-08-31 10:42:17'),
 | 
			
		||||
 (8,0.38226374,'2018-08-31 10:42:17'),
 | 
			
		||||
 (11,0.857324393,'2018-08-31 10:42:17'),
 | 
			
		||||
 (12,0.113320285,'2018-08-31 10:42:18'),
 | 
			
		||||
 (12,0.038532321,'2018-08-31 10:42:18'),
 | 
			
		||||
 (8,0.123430059,'2018-08-31 10:42:18'),
 | 
			
		||||
 (11,0.625290389,'2018-08-31 10:42:18'),
 | 
			
		||||
 (1,0.091823417,'2018-08-31 10:42:18'),
 | 
			
		||||
 (9,0.246651097,'2018-08-31 10:42:19'),
 | 
			
		||||
 (8,0.222901604,'2018-08-31 10:42:19'),
 | 
			
		||||
 (13,1.600367041,'2018-08-31 10:42:20'),
 | 
			
		||||
 (10,0.050076397,'2018-08-31 10:42:20'),
 | 
			
		||||
 (14,0.460363958,'2018-08-31 10:42:20'),
 | 
			
		||||
 (8,0.252590543,'2018-08-31 10:42:20'),
 | 
			
		||||
 (15,0.144109113,'2018-08-31 10:42:20'),
 | 
			
		||||
 (15,0.059993314,'2018-08-31 10:42:20'),
 | 
			
		||||
 (16,0.058810662,'2018-08-31 10:42:20'),
 | 
			
		||||
 (17,0.061824594,'2018-08-31 10:42:20'),
 | 
			
		||||
 (16,0.074584583,'2018-08-31 10:42:20'),
 | 
			
		||||
 (17,0.057086551,'2018-08-31 10:42:20'),
 | 
			
		||||
 (18,0.020983572,'2018-08-31 10:42:20');
 | 
			
		||||
INSERT INTO failures (issue,method,service,created_at) VALUES
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',18,'2018-08-28 10:42:14'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-28 10:42:14'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-29 10:42:14'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-30 10:42:14'),
 | 
			
		||||
 ('Incorrect Response','',1,'2018-08-31 10:40:14'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',18,'2018-08-31 10:42:14');
 | 
			
		||||
INSERT INTO communication (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
 | 
			
		||||
 (1,'email','smtp.emailer.com',587,'exampleuser','password123','info@betatude.com','sendto@gmail.com','','',1,0,7,'2018-08-31 10:42:15'),
 | 
			
		||||
 (2,'slack','https://webhooksurl.slack.com/***',0,'','','','','','',0,0,3,'2018-08-31 10:42:08'),
 | 
			
		||||
 (3,'twilio','',0,'','','','','','',0,0,3,'2018-08-31 10:42:08');
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,142 @@
 | 
			
		|||
INSERT INTO core (name,description,config,api_key,api_secret,style,footer,domain,version,migration_id,use_cdn) VALUES ('Awesome Status','This is from the seed file!','config.yml','d2fead3e459bd14f570cf08527175b88b32d7faa','e351393306ea245de5f9588cbe8627c74db007c6','','Created by Hunter Long','DEV','',0,false);
 | 
			
		||||
INSERT INTO services (name,domain,check_type,method,port,expected,expected_status,check_interval,post_data,order_id,timeout,created_at) VALUES
 | 
			
		||||
 ('Google','https://google.com','http','GET',0,'',200,10,'',0,10,'2018-08-31 10:42:08.76390584-07:00'),
 | 
			
		||||
 ('Statup Github','https://github.com/hunterlong/statup','http','GET',0,'',200,30,'',0,20,'2018-08-31 10:42:08.764977938-07:00'),
 | 
			
		||||
 ('JSON Users Test','https://jsonplaceholder.typicode.com/users','http','GET',0,'',200,60,'',0,30,'2018-08-31 10:42:08.765794226-07:00'),
 | 
			
		||||
 ('JSON API Tester','https://jsonplaceholder.typicode.com/posts','http','POST',0,'(title)": "((\\"|[statup])*)"',201,30,'{ "title": "statup", "body": "bar", "userId": 19999 }',0,30,'2018-08-31 10:42:08.766542311-07:00'),
 | 
			
		||||
 ('Google DNS','8.8.8.8','tcp','',53,'',0,20,'',0,120,'2018-08-31 10:42:08.767327346-07:00'),
 | 
			
		||||
 ('The Bravery - An Honest Mistake','https://www.youtube.com/watch?v=O8vzbezVru4','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14.201305666-07:00'),
 | 
			
		||||
 ('Upper.io','https://upper.io/db.v3/','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14.201305666-07:00'),
 | 
			
		||||
 ('CoinApp Status','https://status.coinapp.io','http','GET',0,'',200,1,'',0,30,'2018-08-31 10:42:16.097416218-07:00'),
 | 
			
		||||
 ('Demo Page','https://demo.statup.io','http','GET',0,'',200,2,'',0,30,'2018-08-31 10:42:16.360051225-07:00'),
 | 
			
		||||
 ('Golang','https://golang.org','http','GET',0,'',200,3,'',0,30,'2018-08-31 10:42:16.923478722-07:00'),
 | 
			
		||||
 ('Github','https://github.com/hunterlong','http','GET',0,'',200,4,'',0,30,'2018-08-31 10:42:17.075544885-07:00'),
 | 
			
		||||
 ('Santa Monica','https://www.santamonica.com','http','GET',0,'',200,5,'',0,30,'2018-08-31 10:42:17.946947674-07:00'),
 | 
			
		||||
 ('Oeschs Die Dritten','https://www.oeschs-die-dritten.ch/en/','http','GET',0,'',200,6,'',0,30,'2018-08-31 10:42:18.083709297-07:00'),
 | 
			
		||||
 ('EtherScan.io','https://etherscan.io','http','GET',0,'',200,7,'',0,30,'2018-08-31 10:42:20.020969513-07:00'),
 | 
			
		||||
 ('Test Service 7','https://www.youtube.com/watch?v=ipvEIZMMILA','http','GET',0,'',200,8,'',0,30,'2018-08-31 10:42:20.50135711-07:00'),
 | 
			
		||||
 ('Test Service 8','https://www.youtube.com/watch?v=UdaYVxYF1Ok','http','GET',0,'',200,9,'',0,30,'2018-08-31 10:42:20.651218082-07:00'),
 | 
			
		||||
 ('Test Service 9','https://www.youtube.com/watch?v=yydZbVoCbn0&t=870s','http','GET',0,'',200,10,'',0,30,'2018-08-31 10:42:20.725479695-07:00'),
 | 
			
		||||
 ('Failing URL','http://failingdomainsarenofunatall.com','http','GET',0,'',200,11,'',0,30,'2018-08-31 10:42:20.799471402-07:00');
 | 
			
		||||
INSERT INTO users (username,password,email,api_key,api_secret,administrator,created_at) VALUES
 | 
			
		||||
 ('admin','$2a$14$Aye3yHae0ml6WRtvdgkRnO19OFze0IKF6IOHrdLpETtwLjnPelMUm','info@statup.io','27aa701119fb561d734eb4469cf13ba2550007e2','29de07014d32fbbbb80053ef3c19b464b2b72f64',true,'2018-08-31 10:42:07.684406458-07:00');
 | 
			
		||||
INSERT INTO hits (service,latency,created_at) VALUES
 | 
			
		||||
 (5,0.006504081,'2018-08-29 10:42:08.779875117-07:00'),
 | 
			
		||||
 (3,0.202164333,'2018-08-29 10:42:08.977187173-07:00'),
 | 
			
		||||
 (4,0.376675172,'2018-08-29 10:42:09.151858662-07:00'),
 | 
			
		||||
 (1,0.413912204,'2018-08-29 10:42:09.188850317-07:00'),
 | 
			
		||||
 (1,0.473912204,'2018-08-29 10:42:10.118850317-07:00'),
 | 
			
		||||
 (2,0.528427935,'2018-08-29 10:42:09.310642068-07:00'),
 | 
			
		||||
 (6,0.11930188,'2018-08-29 10:42:14.133392018-07:00'),
 | 
			
		||||
 (7,0.001062722,'2018-08-29 10:42:14.148258553-07:00'),
 | 
			
		||||
 (7,0.004046882,'2018-08-29 10:42:14.156087817-07:00'),
 | 
			
		||||
 (6,0.063360069,'2018-08-29 10:42:14.205383358-07:00'),
 | 
			
		||||
 (8,0.168951416,'2018-08-29 10:42:16.346340211-07:00'),
 | 
			
		||||
 (8,0.069032763,'2018-08-29 10:42:16.421634189-07:00'),
 | 
			
		||||
 (9,0.47712966,'2018-08-29 10:42:16.91309317-07:00'),
 | 
			
		||||
 (10,0.104510482,'2018-08-29 10:42:17.065673146-07:00'),
 | 
			
		||||
 (10,0.062536146,'2018-08-29 10:42:17.134754949-07:00'),
 | 
			
		||||
 (9,0.352823197,'2018-08-29 10:42:17.272174866-07:00'),
 | 
			
		||||
 (8,0.38226374,'2018-08-29 10:42:17.738731999-07:00'),
 | 
			
		||||
 (11,0.857324393,'2018-08-29 10:42:17.939738264-07:00'),
 | 
			
		||||
 (12,0.113320285,'2018-08-29 10:42:18.073586363-07:00'),
 | 
			
		||||
 (12,0.038532321,'2018-08-29 10:42:18.119730063-07:00'),
 | 
			
		||||
 (8,0.123430059,'2018-08-29 10:42:18.479407581-07:00'),
 | 
			
		||||
 (11,0.625290389,'2018-08-29 10:42:18.5715553-07:00'),
 | 
			
		||||
 (1,0.091823417,'2018-08-29 10:42:18.868788983-07:00'),
 | 
			
		||||
 (9,0.246651097,'2018-08-29 10:42:19.165697332-07:00'),
 | 
			
		||||
 (8,0.222901604,'2018-08-29 10:42:19.57929225-07:00'),
 | 
			
		||||
 (13,1.600367041,'2018-08-29 10:42:20.010203546-07:00'),
 | 
			
		||||
 (10,0.050076397,'2018-08-29 10:42:20.12391038-07:00'),
 | 
			
		||||
 (14,0.460363958,'2018-08-29 10:42:20.495937751-07:00'),
 | 
			
		||||
 (8,0.252590543,'2018-08-29 10:42:20.609139136-07:00'),
 | 
			
		||||
 (15,0.144109113,'2018-08-29 10:42:20.64756516-07:00'),
 | 
			
		||||
 (15,0.059993314,'2018-08-29 10:42:20.710322678-07:00'),
 | 
			
		||||
 (16,0.058810662,'2018-08-29 10:42:20.712087274-07:00'),
 | 
			
		||||
 (17,0.061824594,'2018-08-29 10:42:20.791266761-07:00'),
 | 
			
		||||
 (16,0.074584583,'2018-08-29 10:42:20.797581163-07:00'),
 | 
			
		||||
 (17,0.057086551,'2018-08-29 10:42:20.854020864-07:00'),
 | 
			
		||||
 (18,0.020983572,'2018-08-29 10:42:20.864610424-07:00'),
 | 
			
		||||
 (5,0.006504081,'2018-08-30 10:42:08.779875117-07:00'),
 | 
			
		||||
 (3,0.202164333,'2018-08-30 10:42:08.977187173-07:00'),
 | 
			
		||||
 (4,0.376675172,'2018-08-30 10:42:09.151858662-07:00'),
 | 
			
		||||
 (1,0.413912204,'2018-08-30 10:42:09.188850317-07:00'),
 | 
			
		||||
 (2,0.528427935,'2018-08-30 10:42:09.310642068-07:00'),
 | 
			
		||||
 (6,0.11930188,'2018-08-30 10:42:14.133392018-07:00'),
 | 
			
		||||
 (7,0.001062722,'2018-08-30 10:42:14.148258553-07:00'),
 | 
			
		||||
 (7,0.004046882,'2018-08-30 10:42:14.156087817-07:00'),
 | 
			
		||||
 (6,0.063360069,'2018-08-30 10:42:14.205383358-07:00'),
 | 
			
		||||
 (8,0.168951416,'2018-08-30 10:42:16.346340211-07:00'),
 | 
			
		||||
 (8,0.069032763,'2018-08-30 10:42:16.421634189-07:00'),
 | 
			
		||||
 (9,0.47712966,'2018-08-30 10:42:16.91309317-07:00'),
 | 
			
		||||
 (10,0.104510482,'2018-08-30 10:42:17.065673146-07:00'),
 | 
			
		||||
 (10,0.062536146,'2018-08-30 10:42:17.134754949-07:00'),
 | 
			
		||||
 (9,0.352823197,'2018-08-30 10:42:17.272174866-07:00'),
 | 
			
		||||
 (8,0.38226374,'2018-08-30 10:42:17.738731999-07:00'),
 | 
			
		||||
 (11,0.857324393,'2018-08-30 10:42:17.939738264-07:00'),
 | 
			
		||||
 (12,0.113320285,'2018-08-30 10:42:18.073586363-07:00'),
 | 
			
		||||
 (12,0.038532321,'2018-08-30 10:42:18.119730063-07:00'),
 | 
			
		||||
 (8,0.123430059,'2018-08-30 10:42:18.479407581-07:00'),
 | 
			
		||||
 (11,0.625290389,'2018-08-30 10:42:18.5715553-07:00'),
 | 
			
		||||
 (1,0.091823417,'2018-08-30 10:42:18.868788983-07:00'),
 | 
			
		||||
 (9,0.246651097,'2018-08-30 10:42:19.165697332-07:00'),
 | 
			
		||||
 (8,0.222901604,'2018-08-30 10:42:19.57929225-07:00'),
 | 
			
		||||
 (13,1.600367041,'2018-08-30 10:42:20.010203546-07:00'),
 | 
			
		||||
 (10,0.050076397,'2018-08-30 10:42:20.12391038-07:00'),
 | 
			
		||||
 (14,0.460363958,'2018-08-30 10:42:20.495937751-07:00'),
 | 
			
		||||
 (8,0.252590543,'2018-08-30 10:42:20.609139136-07:00'),
 | 
			
		||||
 (15,0.144109113,'2018-08-30 10:42:20.64756516-07:00'),
 | 
			
		||||
 (15,0.059993314,'2018-08-30 10:42:20.710322678-07:00'),
 | 
			
		||||
 (16,0.058810662,'2018-08-30 10:42:20.712087274-07:00'),
 | 
			
		||||
 (17,0.061824594,'2018-08-30 10:42:20.791266761-07:00'),
 | 
			
		||||
 (16,0.074584583,'2018-08-30 10:42:20.797581163-07:00'),
 | 
			
		||||
 (17,0.057086551,'2018-08-30 10:42:20.854020864-07:00'),
 | 
			
		||||
 (18,0.020983572,'2018-08-30 10:42:20.864610424-07:00'),
 | 
			
		||||
 (5,0.006504081,'2018-08-31 10:42:08.779875117-07:00'),
 | 
			
		||||
 (3,0.202164333,'2018-08-31 10:42:08.977187173-07:00'),
 | 
			
		||||
 (4,0.376675172,'2018-08-31 10:42:09.151858662-07:00'),
 | 
			
		||||
 (1,0.413912204,'2018-08-31 10:42:09.188850317-07:00'),
 | 
			
		||||
 (2,0.528427935,'2018-08-31 10:42:09.310642068-07:00'),
 | 
			
		||||
 (6,0.11930188,'2018-08-31 10:42:14.133392018-07:00'),
 | 
			
		||||
 (7,0.001062722,'2018-08-31 10:42:14.148258553-07:00'),
 | 
			
		||||
 (7,0.004046882,'2018-08-31 10:42:14.156087817-07:00'),
 | 
			
		||||
 (6,0.063360069,'2018-08-31 10:42:14.205383358-07:00'),
 | 
			
		||||
 (8,0.168951416,'2018-08-31 10:42:16.346340211-07:00'),
 | 
			
		||||
 (8,0.069032763,'2018-08-31 10:42:16.421634189-07:00'),
 | 
			
		||||
 (9,0.47712966,'2018-08-31 10:42:16.91309317-07:00'),
 | 
			
		||||
 (10,0.104510482,'2018-08-31 10:42:17.065673146-07:00'),
 | 
			
		||||
 (10,0.062536146,'2018-08-31 10:42:17.134754949-07:00'),
 | 
			
		||||
 (9,0.352823197,'2018-08-31 10:42:17.272174866-07:00'),
 | 
			
		||||
 (8,0.38226374,'2018-08-31 10:42:17.738731999-07:00'),
 | 
			
		||||
 (11,0.857324393,'2018-08-31 10:42:17.939738264-07:00'),
 | 
			
		||||
 (12,0.113320285,'2018-08-31 10:42:18.073586363-07:00'),
 | 
			
		||||
 (12,0.038532321,'2018-08-31 10:42:18.119730063-07:00'),
 | 
			
		||||
 (8,0.123430059,'2018-08-31 10:42:18.479407581-07:00'),
 | 
			
		||||
 (11,0.625290389,'2018-08-31 10:42:18.5715553-07:00'),
 | 
			
		||||
 (1,0.091823417,'2018-08-31 10:42:18.868788983-07:00'),
 | 
			
		||||
 (9,0.246651097,'2018-08-31 10:42:19.165697332-07:00'),
 | 
			
		||||
 (8,0.222901604,'2018-08-31 10:42:19.57929225-07:00'),
 | 
			
		||||
 (13,1.600367041,'2018-08-31 10:42:20.010203546-07:00'),
 | 
			
		||||
 (10,0.050076397,'2018-08-31 10:42:20.12391038-07:00'),
 | 
			
		||||
 (14,0.460363958,'2018-08-31 10:42:20.495937751-07:00'),
 | 
			
		||||
 (8,0.252590543,'2018-08-31 10:42:20.609139136-07:00'),
 | 
			
		||||
 (15,0.144109113,'2018-08-31 10:42:20.64756516-07:00'),
 | 
			
		||||
 (15,0.059993314,'2018-08-31 10:42:20.710322678-07:00'),
 | 
			
		||||
 (16,0.058810662,'2018-08-31 10:42:20.712087274-07:00'),
 | 
			
		||||
 (17,0.061824594,'2018-08-31 10:42:20.791266761-07:00'),
 | 
			
		||||
 (16,0.074584583,'2018-08-31 10:42:20.797581163-07:00'),
 | 
			
		||||
 (17,0.057086551,'2018-08-31 10:42:20.854020864-07:00'),
 | 
			
		||||
 (18,0.020983572,'2018-08-31 10:42:20.864610424-07:00');
 | 
			
		||||
INSERT INTO failures (issue,method,service,created_at) VALUES
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',18,'2018-08-28 10:42:14.271162743-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-28 10:42:14.271162743-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-29 10:42:14.271162743-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-30 10:42:14.271162743-07:00'),
 | 
			
		||||
 ('Incorrect Response','',1,'2018-08-31 10:40:14.272209564-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.271162743-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.272209564-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',18,'2018-08-31 10:42:14.271162743-07:00');
 | 
			
		||||
INSERT INTO communication (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
 | 
			
		||||
 (1,'email','smtp.emailer.com',587,'exampleuser','password123','info@betatude.com','sendto@gmail.com','','',true,false,7,'2018-08-31 10:42:15.000829706-07:00'),
 | 
			
		||||
 (2,'slack','https://webhooksurl.slack.com/***',0,'','','','','','',false,false,3,'2018-08-31 10:42:08.775366824-07:00'),
 | 
			
		||||
 (3,'twilio','',0,'','','','','','',false,false,3,'2018-08-31 10:42:08.776944923-07:00');
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,142 @@
 | 
			
		|||
INSERT INTO core (name,description,config,api_key,api_secret,style,footer,domain,version,migration_id,use_cdn) VALUES ('Awesome Status','This is from the seed file!','config.yml','d2fead3e459bd14f570cf08527175b88b32d7faa','e351393306ea245de5f9588cbe8627c74db007c6','','Created by Hunter Long','','',0,0);
 | 
			
		||||
INSERT INTO services (id,name,domain,check_type,method,port,expected,expected_status,check_interval,post_data,order_id,timeout,created_at) VALUES
 | 
			
		||||
 (1,'Google','https://google.com','http','GET',0,'',200,10,'',0,10,'2018-08-31 10:42:08.76390584-07:00'),
 | 
			
		||||
 (2,'Statup Github','https://github.com/hunterlong/statup','http','GET',0,'',200,30,'',0,20,'2018-08-31 10:42:08.764977938-07:00'),
 | 
			
		||||
 (3,'JSON Users Test','https://jsonplaceholder.typicode.com/users','http','GET',0,'',200,60,'',0,30,'2018-08-31 10:42:08.765794226-07:00'),
 | 
			
		||||
 (4,'JSON API Tester','https://jsonplaceholder.typicode.com/posts','http','POST',0,'(title)": "((\\"|[statup])*)"',201,30,'{ "title": "statup", "body": "bar", "userId": 19999 }',0,30,'2018-08-31 10:42:08.766542311-07:00'),
 | 
			
		||||
 (5,'Google DNS','8.8.8.8','tcp','',53,'',0,20,'',0,120,'2018-08-31 10:42:08.767327346-07:00'),
 | 
			
		||||
 (6,'The Bravery - An Honest Mistake','https://www.youtube.com/watch?v=O8vzbezVru4','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14.201305666-07:00'),
 | 
			
		||||
 (7,'Upper.io','https://upper.io/db.v3/','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14.201305666-07:00'),
 | 
			
		||||
 (8,'CoinApp Status','https://status.coinapp.io','http','GET',0,'',200,1,'',0,30,'2018-08-31 10:42:16.097416218-07:00'),
 | 
			
		||||
 (9,'Demo Page','https://demo.statup.io','http','GET',0,'',200,2,'',0,30,'2018-08-31 10:42:16.360051225-07:00'),
 | 
			
		||||
 (10,'Golang','https://golang.org','http','GET',0,'',200,3,'',0,30,'2018-08-31 10:42:16.923478722-07:00'),
 | 
			
		||||
 (11,'Github','https://github.com/hunterlong','http','GET',0,'',200,4,'',0,30,'2018-08-31 10:42:17.075544885-07:00'),
 | 
			
		||||
 (12,'Santa Monica','https://www.santamonica.com','http','GET',0,'',200,5,'',0,30,'2018-08-31 10:42:17.946947674-07:00'),
 | 
			
		||||
 (13,'Oeschs Die Dritten','https://www.oeschs-die-dritten.ch/en/','http','GET',0,'',200,6,'',0,30,'2018-08-31 10:42:18.083709297-07:00'),
 | 
			
		||||
 (14,'EtherScan.io','https://etherscan.io','http','GET',0,'',200,7,'',0,30,'2018-08-31 10:42:20.020969513-07:00'),
 | 
			
		||||
 (15,'Test Service 7','https://www.youtube.com/watch?v=ipvEIZMMILA','http','GET',0,'',200,8,'',0,30,'2018-08-31 10:42:20.50135711-07:00'),
 | 
			
		||||
 (16,'Test Service 8','https://www.youtube.com/watch?v=UdaYVxYF1Ok','http','GET',0,'',200,9,'',0,30,'2018-08-31 10:42:20.651218082-07:00'),
 | 
			
		||||
 (17,'Test Service 9','https://www.youtube.com/watch?v=yydZbVoCbn0&t=870s','http','GET',0,'',200,10,'',0,30,'2018-08-31 10:42:20.725479695-07:00'),
 | 
			
		||||
 (18,'Failing URL','http://failingdomainsarenofunatall.com','http','GET',0,'',200,11,'',0,30,'2018-08-31 10:42:20.799471402-07:00');
 | 
			
		||||
INSERT INTO users (username,password,email,api_key,api_secret,administrator,created_at) VALUES
 | 
			
		||||
 ('admin','$2a$14$Aye3yHae0ml6WRtvdgkRnO19OFze0IKF6IOHrdLpETtwLjnPelMUm','info@statup.io','27aa701119fb561d734eb4469cf13ba2550007e2','29de07014d32fbbbb80053ef3c19b464b2b72f64',1,'2018-08-31 10:42:07.684406458-07:00');
 | 
			
		||||
INSERT INTO hits (service,latency,created_at) VALUES
 | 
			
		||||
 (5,0.006504081,'2018-08-29 10:42:08.779875117-07:00'),
 | 
			
		||||
 (3,0.202164333,'2018-08-29 10:42:08.977187173-07:00'),
 | 
			
		||||
 (4,0.376675172,'2018-08-29 10:42:09.151858662-07:00'),
 | 
			
		||||
 (1,0.413912204,'2018-08-29 10:42:09.188850317-07:00'),
 | 
			
		||||
 (1,0.473912204,'2018-08-29 10:42:10.118850317-07:00'),
 | 
			
		||||
 (2,0.528427935,'2018-08-29 10:42:09.310642068-07:00'),
 | 
			
		||||
 (6,0.11930188,'2018-08-29 10:42:14.133392018-07:00'),
 | 
			
		||||
 (7,0.001062722,'2018-08-29 10:42:14.148258553-07:00'),
 | 
			
		||||
 (7,0.004046882,'2018-08-29 10:42:14.156087817-07:00'),
 | 
			
		||||
 (6,0.063360069,'2018-08-29 10:42:14.205383358-07:00'),
 | 
			
		||||
 (8,0.168951416,'2018-08-29 10:42:16.346340211-07:00'),
 | 
			
		||||
 (8,0.069032763,'2018-08-29 10:42:16.421634189-07:00'),
 | 
			
		||||
 (9,0.47712966,'2018-08-29 10:42:16.91309317-07:00'),
 | 
			
		||||
 (10,0.104510482,'2018-08-29 10:42:17.065673146-07:00'),
 | 
			
		||||
 (10,0.062536146,'2018-08-29 10:42:17.134754949-07:00'),
 | 
			
		||||
 (9,0.352823197,'2018-08-29 10:42:17.272174866-07:00'),
 | 
			
		||||
 (8,0.38226374,'2018-08-29 10:42:17.738731999-07:00'),
 | 
			
		||||
 (11,0.857324393,'2018-08-29 10:42:17.939738264-07:00'),
 | 
			
		||||
 (12,0.113320285,'2018-08-29 10:42:18.073586363-07:00'),
 | 
			
		||||
 (12,0.038532321,'2018-08-29 10:42:18.119730063-07:00'),
 | 
			
		||||
 (8,0.123430059,'2018-08-29 10:42:18.479407581-07:00'),
 | 
			
		||||
 (11,0.625290389,'2018-08-29 10:42:18.5715553-07:00'),
 | 
			
		||||
 (1,0.091823417,'2018-08-29 10:42:18.868788983-07:00'),
 | 
			
		||||
 (9,0.246651097,'2018-08-29 10:42:19.165697332-07:00'),
 | 
			
		||||
 (8,0.222901604,'2018-08-29 10:42:19.57929225-07:00'),
 | 
			
		||||
 (13,1.600367041,'2018-08-29 10:42:20.010203546-07:00'),
 | 
			
		||||
 (10,0.050076397,'2018-08-29 10:42:20.12391038-07:00'),
 | 
			
		||||
 (14,0.460363958,'2018-08-29 10:42:20.495937751-07:00'),
 | 
			
		||||
 (8,0.252590543,'2018-08-29 10:42:20.609139136-07:00'),
 | 
			
		||||
 (15,0.144109113,'2018-08-29 10:42:20.64756516-07:00'),
 | 
			
		||||
 (15,0.059993314,'2018-08-29 10:42:20.710322678-07:00'),
 | 
			
		||||
 (16,0.058810662,'2018-08-29 10:42:20.712087274-07:00'),
 | 
			
		||||
 (17,0.061824594,'2018-08-29 10:42:20.791266761-07:00'),
 | 
			
		||||
 (16,0.074584583,'2018-08-29 10:42:20.797581163-07:00'),
 | 
			
		||||
 (17,0.057086551,'2018-08-29 10:42:20.854020864-07:00'),
 | 
			
		||||
 (18,0.020983572,'2018-08-29 10:42:20.864610424-07:00'),
 | 
			
		||||
 (5,0.006504081,'2018-08-30 10:42:08.779875117-07:00'),
 | 
			
		||||
 (3,0.202164333,'2018-08-30 10:42:08.977187173-07:00'),
 | 
			
		||||
 (4,0.376675172,'2018-08-30 10:42:09.151858662-07:00'),
 | 
			
		||||
 (1,0.413912204,'2018-08-30 10:42:09.188850317-07:00'),
 | 
			
		||||
 (2,0.528427935,'2018-08-30 10:42:09.310642068-07:00'),
 | 
			
		||||
 (6,0.11930188,'2018-08-30 10:42:14.133392018-07:00'),
 | 
			
		||||
 (7,0.001062722,'2018-08-30 10:42:14.148258553-07:00'),
 | 
			
		||||
 (7,0.004046882,'2018-08-30 10:42:14.156087817-07:00'),
 | 
			
		||||
 (6,0.063360069,'2018-08-30 10:42:14.205383358-07:00'),
 | 
			
		||||
 (8,0.168951416,'2018-08-30 10:42:16.346340211-07:00'),
 | 
			
		||||
 (8,0.069032763,'2018-08-30 10:42:16.421634189-07:00'),
 | 
			
		||||
 (9,0.47712966,'2018-08-30 10:42:16.91309317-07:00'),
 | 
			
		||||
 (10,0.104510482,'2018-08-30 10:42:17.065673146-07:00'),
 | 
			
		||||
 (10,0.062536146,'2018-08-30 10:42:17.134754949-07:00'),
 | 
			
		||||
 (9,0.352823197,'2018-08-30 10:42:17.272174866-07:00'),
 | 
			
		||||
 (8,0.38226374,'2018-08-30 10:42:17.738731999-07:00'),
 | 
			
		||||
 (11,0.857324393,'2018-08-30 10:42:17.939738264-07:00'),
 | 
			
		||||
 (12,0.113320285,'2018-08-30 10:42:18.073586363-07:00'),
 | 
			
		||||
 (12,0.038532321,'2018-08-30 10:42:18.119730063-07:00'),
 | 
			
		||||
 (8,0.123430059,'2018-08-30 10:42:18.479407581-07:00'),
 | 
			
		||||
 (11,0.625290389,'2018-08-30 10:42:18.5715553-07:00'),
 | 
			
		||||
 (1,0.091823417,'2018-08-30 10:42:18.868788983-07:00'),
 | 
			
		||||
 (9,0.246651097,'2018-08-30 10:42:19.165697332-07:00'),
 | 
			
		||||
 (8,0.222901604,'2018-08-30 10:42:19.57929225-07:00'),
 | 
			
		||||
 (13,1.600367041,'2018-08-30 10:42:20.010203546-07:00'),
 | 
			
		||||
 (10,0.050076397,'2018-08-30 10:42:20.12391038-07:00'),
 | 
			
		||||
 (14,0.460363958,'2018-08-30 10:42:20.495937751-07:00'),
 | 
			
		||||
 (8,0.252590543,'2018-08-30 10:42:20.609139136-07:00'),
 | 
			
		||||
 (15,0.144109113,'2018-08-30 10:42:20.64756516-07:00'),
 | 
			
		||||
 (15,0.059993314,'2018-08-30 10:42:20.710322678-07:00'),
 | 
			
		||||
 (16,0.058810662,'2018-08-30 10:42:20.712087274-07:00'),
 | 
			
		||||
 (17,0.061824594,'2018-08-30 10:42:20.791266761-07:00'),
 | 
			
		||||
 (16,0.074584583,'2018-08-30 10:42:20.797581163-07:00'),
 | 
			
		||||
 (17,0.057086551,'2018-08-30 10:42:20.854020864-07:00'),
 | 
			
		||||
 (18,0.020983572,'2018-08-30 10:42:20.864610424-07:00'),
 | 
			
		||||
 (5,0.006504081,'2018-08-31 10:42:08.779875117-07:00'),
 | 
			
		||||
 (3,0.202164333,'2018-08-31 10:42:08.977187173-07:00'),
 | 
			
		||||
 (4,0.376675172,'2018-08-31 10:42:09.151858662-07:00'),
 | 
			
		||||
 (1,0.413912204,'2018-08-31 10:42:09.188850317-07:00'),
 | 
			
		||||
 (2,0.528427935,'2018-08-31 10:42:09.310642068-07:00'),
 | 
			
		||||
 (6,0.11930188,'2018-08-31 10:42:14.133392018-07:00'),
 | 
			
		||||
 (7,0.001062722,'2018-08-31 10:42:14.148258553-07:00'),
 | 
			
		||||
 (7,0.004046882,'2018-08-31 10:42:14.156087817-07:00'),
 | 
			
		||||
 (6,0.063360069,'2018-08-31 10:42:14.205383358-07:00'),
 | 
			
		||||
 (8,0.168951416,'2018-08-31 10:42:16.346340211-07:00'),
 | 
			
		||||
 (8,0.069032763,'2018-08-31 10:42:16.421634189-07:00'),
 | 
			
		||||
 (9,0.47712966,'2018-08-31 10:42:16.91309317-07:00'),
 | 
			
		||||
 (10,0.104510482,'2018-08-31 10:42:17.065673146-07:00'),
 | 
			
		||||
 (10,0.062536146,'2018-08-31 10:42:17.134754949-07:00'),
 | 
			
		||||
 (9,0.352823197,'2018-08-31 10:42:17.272174866-07:00'),
 | 
			
		||||
 (8,0.38226374,'2018-08-31 10:42:17.738731999-07:00'),
 | 
			
		||||
 (11,0.857324393,'2018-08-31 10:42:17.939738264-07:00'),
 | 
			
		||||
 (12,0.113320285,'2018-08-31 10:42:18.073586363-07:00'),
 | 
			
		||||
 (12,0.038532321,'2018-08-31 10:42:18.119730063-07:00'),
 | 
			
		||||
 (8,0.123430059,'2018-08-31 10:42:18.479407581-07:00'),
 | 
			
		||||
 (11,0.625290389,'2018-08-31 10:42:18.5715553-07:00'),
 | 
			
		||||
 (1,0.091823417,'2018-08-31 10:42:18.868788983-07:00'),
 | 
			
		||||
 (9,0.246651097,'2018-08-31 10:42:19.165697332-07:00'),
 | 
			
		||||
 (8,0.222901604,'2018-08-31 10:42:19.57929225-07:00'),
 | 
			
		||||
 (13,1.600367041,'2018-08-31 10:42:20.010203546-07:00'),
 | 
			
		||||
 (10,0.050076397,'2018-08-31 10:42:20.12391038-07:00'),
 | 
			
		||||
 (14,0.460363958,'2018-08-31 10:42:20.495937751-07:00'),
 | 
			
		||||
 (8,0.252590543,'2018-08-31 10:42:20.609139136-07:00'),
 | 
			
		||||
 (15,0.144109113,'2018-08-31 10:42:20.64756516-07:00'),
 | 
			
		||||
 (15,0.059993314,'2018-08-31 10:42:20.710322678-07:00'),
 | 
			
		||||
 (16,0.058810662,'2018-08-31 10:42:20.712087274-07:00'),
 | 
			
		||||
 (17,0.061824594,'2018-08-31 10:42:20.791266761-07:00'),
 | 
			
		||||
 (16,0.074584583,'2018-08-31 10:42:20.797581163-07:00'),
 | 
			
		||||
 (17,0.057086551,'2018-08-31 10:42:20.854020864-07:00'),
 | 
			
		||||
 (18,0.020983572,'2018-08-31 10:42:20.864610424-07:00');
 | 
			
		||||
INSERT INTO failures (issue,method,service,created_at) VALUES
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',18,'2018-08-28 10:42:14.271162743-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-28 10:42:14.271162743-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-29 10:42:14.271162743-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-30 10:42:14.271162743-07:00'),
 | 
			
		||||
 ('Incorrect Response','',1,'2018-08-31 10:40:14.272209564-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.271162743-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.272209564-07:00'),
 | 
			
		||||
 ('HTTP Status Code 200 did not match 0','',18,'2018-08-31 10:42:14.271162743-07:00');
 | 
			
		||||
INSERT INTO communication (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
 | 
			
		||||
 (1,'email','smtp.emailer.com',587,'exampleuser','password123','info@betatude.com','sendto@gmail.com','','',1,0,7,'2018-08-31 10:42:15.000829706-07:00'),
 | 
			
		||||
 (2,'slack','https://webhooksurl.slack.com/***',0,'','','','','','',0,0,3,'2018-08-31 10:42:08.775366824-07:00'),
 | 
			
		||||
 (3,'twilio','',0,'','','','','','',0,0,3,'2018-08-31 10:42:08.776944923-07:00');
 | 
			
		||||
| 
						 | 
				
			
			@ -36,17 +36,23 @@ const (
 | 
			
		|||
 | 
			
		||||
func injectDatabase() {
 | 
			
		||||
	core.NewCore()
 | 
			
		||||
	core.Configs = new(types.Config)
 | 
			
		||||
	core.Configs.Connection = "sqlite"
 | 
			
		||||
	core.Configs = new(core.DbConfig)
 | 
			
		||||
	core.Configs.DbConn = "sqlite"
 | 
			
		||||
	core.CoreApp.DbConnection = "sqlite"
 | 
			
		||||
	core.CoreApp.Version = "DEV"
 | 
			
		||||
	core.DbConnection("sqlite", false, utils.Directory)
 | 
			
		||||
	core.Configs.Connect(false, utils.Directory)
 | 
			
		||||
	core.InitApp()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Clean() {
 | 
			
		||||
	utils.DeleteFile(dir + "/config.yml")
 | 
			
		||||
	utils.DeleteFile(dir + "/statup.db")
 | 
			
		||||
	utils.DeleteDirectory(dir + "/assets")
 | 
			
		||||
	utils.DeleteDirectory(dir + "/logs")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInit(t *testing.T) {
 | 
			
		||||
	t.SkipNow()
 | 
			
		||||
	injectDatabase()
 | 
			
		||||
	Clean()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func formatJSON(res string, out interface{}) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,6 +97,8 @@ func TestProcessSetupHandler(t *testing.T) {
 | 
			
		|||
	rr := httptest.NewRecorder()
 | 
			
		||||
	Router().ServeHTTP(rr, req)
 | 
			
		||||
	assert.Equal(t, 303, rr.Code)
 | 
			
		||||
	assert.FileExists(t, dir+"/config.yml")
 | 
			
		||||
	assert.FileExists(t, dir+"/statup.db")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCheckSetupHandler(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -143,7 +145,9 @@ func TestServiceChartHandler(t *testing.T) {
 | 
			
		|||
	assert.Equal(t, 200, rr.Code)
 | 
			
		||||
	t.Log(body)
 | 
			
		||||
	assert.Contains(t, body, "var ctx_1")
 | 
			
		||||
	assert.Contains(t, body, "var ctx_2")
 | 
			
		||||
	assert.Contains(t, body, "var ctx_3")
 | 
			
		||||
	assert.Contains(t, body, "var ctx_4")
 | 
			
		||||
	assert.Contains(t, body, "var ctx_5")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ type index struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func IndexHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if core.CoreApp.DbConnection == "" {
 | 
			
		||||
	if core.Configs == nil {
 | 
			
		||||
		http.Redirect(w, r, "/setup", http.StatusSeeOther)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -42,12 +42,12 @@ func DesktopInit(ip string, port int) {
 | 
			
		|||
	var err error
 | 
			
		||||
	exists := utils.FileExists(utils.Directory + "/statup.db")
 | 
			
		||||
	if exists {
 | 
			
		||||
		core.Configs, err = core.LoadConfig()
 | 
			
		||||
		core.Configs, err = core.LoadConfig(utils.Directory)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.Log(3, err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		err = core.DbConnection(core.Configs.Connection, false, utils.Directory)
 | 
			
		||||
		err = core.Configs.Connect(false, utils.Directory)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.Log(3, err)
 | 
			
		||||
			return
 | 
			
		||||
| 
						 | 
				
			
			@ -68,24 +68,28 @@ func DesktopInit(ip string, port int) {
 | 
			
		|||
		Location:    utils.Directory,
 | 
			
		||||
	}}
 | 
			
		||||
 | 
			
		||||
	err = config.Save()
 | 
			
		||||
	config, err = config.Save()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config.DropDatabase()
 | 
			
		||||
	config.CreateDatabase()
 | 
			
		||||
	core.CoreApp = config.CreateCore()
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	core.Configs, err = core.LoadConfig()
 | 
			
		||||
	core.Configs, err = core.LoadConfig(utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		config.Error = err
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, utils.Directory)
 | 
			
		||||
	err = core.Configs.Connect(false, utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		core.DeleteConfig()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,6 @@
 | 
			
		|||
package handlers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/hunterlong/statup/core"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -53,6 +52,6 @@ func PluginsDownloadHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	//vars := mux.Vars(router)
 | 
			
		||||
	//name := vars["name"]
 | 
			
		||||
	//DownloadPlugin(name)
 | 
			
		||||
	core.LoadConfig()
 | 
			
		||||
	//core.LoadConfig(utils.Directory)
 | 
			
		||||
	http.Redirect(w, r, "/plugins", http.StatusSeeOther)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,13 +61,6 @@ func PrometheusHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	w.Write([]byte(output))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ResetDbHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	utils.Log(1, fmt.Sprintf("Prometheus /metrics Request From IP: %v\n", r.RemoteAddr))
 | 
			
		||||
	core.DropDatabase()
 | 
			
		||||
	core.CoreApp = nil
 | 
			
		||||
	w.WriteHeader(http.StatusOK)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isAuthorized(r *http.Request) bool {
 | 
			
		||||
	var token string
 | 
			
		||||
	tokens, ok := r.Header["Authorization"]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,6 @@ func Router() *mux.Router {
 | 
			
		|||
	r.Handle("/setup", http.HandlerFunc(SetupHandler)).Methods("GET")
 | 
			
		||||
	r.Handle("/setup", http.HandlerFunc(ProcessSetupHandler)).Methods("POST")
 | 
			
		||||
	r.Handle("/dashboard", http.HandlerFunc(DashboardHandler)).Methods("GET")
 | 
			
		||||
	//r.Handle("/backups/create", http.HandlerFunc(BackupCreateHandler)).Methods("GET")
 | 
			
		||||
	r.Handle("/dashboard", http.HandlerFunc(LoginHandler)).Methods("POST")
 | 
			
		||||
	r.Handle("/logout", http.HandlerFunc(LogoutHandler))
 | 
			
		||||
	r.Handle("/services", http.HandlerFunc(ServicesHandler)).Methods("GET")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,6 +59,7 @@ func ReorderServiceHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	decoder := json.NewDecoder(r.Body)
 | 
			
		||||
	decoder.Decode(&newOrder)
 | 
			
		||||
	for _, s := range newOrder {
 | 
			
		||||
		fmt.Println("updating: ", s.Id, " to be order_id: ", s.Order)
 | 
			
		||||
		service := core.SelectService(s.Id)
 | 
			
		||||
		service.Order = s.Order
 | 
			
		||||
		service.Update(false)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,6 @@
 | 
			
		|||
package handlers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/hunterlong/statup/core"
 | 
			
		||||
	"github.com/hunterlong/statup/types"
 | 
			
		||||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +55,7 @@ func SetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	var err error
 | 
			
		||||
	if core.CoreApp.Services() != nil {
 | 
			
		||||
		http.Redirect(w, r, "/", http.StatusSeeOther)
 | 
			
		||||
		return
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,9 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	domain := r.PostForm.Get("domain")
 | 
			
		||||
	email := r.PostForm.Get("email")
 | 
			
		||||
 | 
			
		||||
	config := &core.DbConfig{&types.DbConfig{
 | 
			
		||||
	dir := utils.Directory
 | 
			
		||||
 | 
			
		||||
	config := &core.DbConfig{DbConfig: &types.DbConfig{
 | 
			
		||||
		DbConn:      dbConn,
 | 
			
		||||
		DbHost:      dbHost,
 | 
			
		||||
		DbUser:      dbUser,
 | 
			
		||||
| 
						 | 
				
			
			@ -92,13 +94,15 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		Location:    utils.Directory,
 | 
			
		||||
	}}
 | 
			
		||||
 | 
			
		||||
	fmt.Println(config)
 | 
			
		||||
 | 
			
		||||
	err := config.Save()
 | 
			
		||||
	core.Configs, err = config.Save()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
		config.Error = err
 | 
			
		||||
		SetupResponseError(w, r, config)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	core.Configs, err = core.LoadConfig(dir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		config.Error = err
 | 
			
		||||
| 
						 | 
				
			
			@ -106,23 +110,26 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	core.Configs, err = core.LoadConfig()
 | 
			
		||||
	err = core.Configs.Connect(false, dir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		config.Error = err
 | 
			
		||||
		SetupResponseError(w, r, config)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
		core.DeleteConfig()
 | 
			
		||||
		config.Error = err
 | 
			
		||||
		SetupResponseError(w, r, config)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config.DropDatabase()
 | 
			
		||||
	config.CreateDatabase()
 | 
			
		||||
 | 
			
		||||
	core.CoreApp, err = config.InsertCore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
		config.Error = err
 | 
			
		||||
		SetupResponseError(w, r, config)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	admin := core.ReturnUser(&types.User{
 | 
			
		||||
		Username: config.Username,
 | 
			
		||||
		Password: config.Password,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,7 +112,7 @@ func (u *Email) Init() error {
 | 
			
		|||
		if u.Enabled {
 | 
			
		||||
 | 
			
		||||
			utils.Log(1, fmt.Sprintf("Loading SMTP Emailer using host: %v:%v", u.Notification.Host, u.Notification.Port))
 | 
			
		||||
			mailer = gomail.NewDialer(u.Notification.Host, u.Notification.Port, u.Notification.Username, u.Notification.Password)
 | 
			
		||||
			mailer = gomail.NewPlainDialer(u.Notification.Host, u.Notification.Port, u.Notification.Username, u.Notification.Password)
 | 
			
		||||
			mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
 | 
			
		||||
 | 
			
		||||
			go u.Run()
 | 
			
		||||
| 
						 | 
				
			
			@ -215,7 +215,7 @@ func (u *Email) OnSave() error {
 | 
			
		|||
 | 
			
		||||
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
 | 
			
		||||
func (u *Email) Install() error {
 | 
			
		||||
	inDb, err := emailer.Notification.IsInDatabase()
 | 
			
		||||
	inDb := emailer.Notification.IsInDatabase()
 | 
			
		||||
	if !inDb {
 | 
			
		||||
		newNotifer, err := InsertDatabase(u.Notification)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -224,7 +224,7 @@ func (u *Email) Install() error {
 | 
			
		|||
		}
 | 
			
		||||
		utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method))
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *Email) dialSend(email *EmailOutgoing) error {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,34 +19,35 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
	"github.com/hunterlong/statup/types"
 | 
			
		||||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
	"github.com/jinzhu/gorm"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
	"upper.io/db.v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	AllCommunications []types.AllNotifiers
 | 
			
		||||
	Collections       db.Collection
 | 
			
		||||
	Collections       *gorm.DB
 | 
			
		||||
	Logs              []*NotificationLog
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Notification struct {
 | 
			
		||||
	Id        int64     `db:"id,omitempty" json:"id"`
 | 
			
		||||
	Method    string    `db:"method" json:"method"`
 | 
			
		||||
	Host      string    `db:"host" json:"-"`
 | 
			
		||||
	Port      int       `db:"port" json:"-"`
 | 
			
		||||
	Username  string    `db:"username" json:"-"`
 | 
			
		||||
	Password  string    `db:"password" json:"-"`
 | 
			
		||||
	Var1      string    `db:"var1" json:"-"`
 | 
			
		||||
	Var2      string    `db:"var2" json:"-"`
 | 
			
		||||
	ApiKey    string    `db:"api_key" json:"-"`
 | 
			
		||||
	ApiSecret string    `db:"api_secret" json:"-"`
 | 
			
		||||
	Enabled   bool      `db:"enabled" json:"enabled"`
 | 
			
		||||
	Limits    int       `db:"limits" json:"-"`
 | 
			
		||||
	Removable bool      `db:"removable" json:"-"`
 | 
			
		||||
	CreatedAt time.Time `db:"created_at" json:"created_at"`
 | 
			
		||||
	Form      []NotificationForm
 | 
			
		||||
	Routine   chan struct{}
 | 
			
		||||
	Id        int64              `gorm:"primary_key column:id" json:"id"`
 | 
			
		||||
	Method    string             `gorm:"column:method" json:"method"`
 | 
			
		||||
	Host      string             `gorm:"not null;column:host" json:"-"`
 | 
			
		||||
	Port      int                `gorm:"not null;column:port" json:"-"`
 | 
			
		||||
	Username  string             `gorm:"not null;column:username" json:"-"`
 | 
			
		||||
	Password  string             `gorm:"not null;column:password" json:"-"`
 | 
			
		||||
	Var1      string             `gorm:"not null;column:var1" json:"-"`
 | 
			
		||||
	Var2      string             `gorm:"not null;column:var2" json:"-"`
 | 
			
		||||
	ApiKey    string             `gorm:"not null;column:api_key" json:"-"`
 | 
			
		||||
	ApiSecret string             `gorm:"not null;column:api_secret" json:"-"`
 | 
			
		||||
	Enabled   bool               `gorm:"column:enabled;type:boolean;default:false" json:"enabled"`
 | 
			
		||||
	Limits    int                `gorm:"not null;column:limits" json:"-"`
 | 
			
		||||
	Removable bool               `gorm:"column:removable" json:"-"`
 | 
			
		||||
	CreatedAt time.Time          `gorm:"column:created_at" json:"created_at"`
 | 
			
		||||
	UpdatedAt time.Time          `gorm:"column:updated_at" json:"updated_at"`
 | 
			
		||||
	Form      []NotificationForm `gorm:"-" json:"-"`
 | 
			
		||||
	Routine   chan struct{}      `gorm:"-" json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Notifier interface {
 | 
			
		||||
| 
						 | 
				
			
			@ -115,30 +116,30 @@ func reverseLogs(input []*NotificationLog) []*NotificationLog {
 | 
			
		|||
	return append(reverseLogs(input[1:]), input[0])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *Notification) IsInDatabase() (bool, error) {
 | 
			
		||||
	return Collections.Find("id", n.Id).Exists()
 | 
			
		||||
func (n *Notification) IsInDatabase() bool {
 | 
			
		||||
	return !Collections.Find(n).RecordNotFound()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectNotification(id int64) (*Notification, error) {
 | 
			
		||||
	var notifier *Notification
 | 
			
		||||
	err := Collections.Find("id", id).One(¬ifier)
 | 
			
		||||
	return notifier, err
 | 
			
		||||
	var notifier Notification
 | 
			
		||||
	err := Collections.Find(¬ifier, id)
 | 
			
		||||
	return ¬ifier, err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *Notification) Update() (*Notification, error) {
 | 
			
		||||
	n.CreatedAt = time.Now()
 | 
			
		||||
	err := Collections.Find("id", n.Id).Update(n)
 | 
			
		||||
	return n, err
 | 
			
		||||
	err := Collections.Update(n)
 | 
			
		||||
	return n, err.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InsertDatabase(n *Notification) (int64, error) {
 | 
			
		||||
	n.CreatedAt = time.Now()
 | 
			
		||||
	n.Limits = 3
 | 
			
		||||
	newId, err := Collections.Insert(n)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	db := Collections.Create(n)
 | 
			
		||||
	if db.Error != nil {
 | 
			
		||||
		return 0, db.Error
 | 
			
		||||
	}
 | 
			
		||||
	return newId.(int64), err
 | 
			
		||||
	return n.Id, db.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectNotifier(id int64) Notifier {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,10 +18,11 @@ package notifiers
 | 
			
		|||
import (
 | 
			
		||||
	"github.com/hunterlong/statup/types"
 | 
			
		||||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
	"github.com/jinzhu/gorm"
 | 
			
		||||
	_ "github.com/jinzhu/gorm/dialects/sqlite"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"upper.io/db.v3/sqlite"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
| 
						 | 
				
			
			@ -67,11 +68,8 @@ func init() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func injectDatabase() {
 | 
			
		||||
	sqliteDb := sqlite.ConnectionURL{
 | 
			
		||||
		Database: dir + "/statup.db",
 | 
			
		||||
	}
 | 
			
		||||
	dbSession, _ := sqlite.Open(sqliteDb)
 | 
			
		||||
	Collections = dbSession.Collection("communication")
 | 
			
		||||
	dbSession, _ := gorm.Open("sqlite3", dir+"/statup.db")
 | 
			
		||||
	Collections = dbSession.Table("communication").Model(&Notification{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Tester struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -100,8 +98,7 @@ func TestAdd(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestIsInDatabase(t *testing.T) {
 | 
			
		||||
	in, err := testNotifier.IsInDatabase()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	in := testNotifier.IsInDatabase()
 | 
			
		||||
	assert.False(t, in)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -110,8 +107,7 @@ func TestInsertDatabase(t *testing.T) {
 | 
			
		|||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotZero(t, newId)
 | 
			
		||||
 | 
			
		||||
	in, err := testNotifier.IsInDatabase()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	in := testNotifier.IsInDatabase()
 | 
			
		||||
	assert.True(t, in)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -165,7 +165,7 @@ func (u *Slack) OnSave() error {
 | 
			
		|||
 | 
			
		||||
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
 | 
			
		||||
func (u *Slack) Install() error {
 | 
			
		||||
	inDb, err := slacker.Notification.IsInDatabase()
 | 
			
		||||
	inDb := slacker.Notification.IsInDatabase()
 | 
			
		||||
	if !inDb {
 | 
			
		||||
		newNotifer, err := InsertDatabase(u.Notification)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -174,5 +174,5 @@ func (u *Slack) Install() error {
 | 
			
		|||
		}
 | 
			
		||||
		utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method))
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,7 +179,7 @@ func (u *Twilio) OnSave() error {
 | 
			
		|||
 | 
			
		||||
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
 | 
			
		||||
func (u *Twilio) Install() error {
 | 
			
		||||
	inDb, err := twilio.Notification.IsInDatabase()
 | 
			
		||||
	inDb := twilio.Notification.IsInDatabase()
 | 
			
		||||
	if !inDb {
 | 
			
		||||
		newNotifer, err := InsertDatabase(u.Notification)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -188,5 +188,5 @@ func (u *Twilio) Install() error {
 | 
			
		|||
		}
 | 
			
		||||
		utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method))
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,6 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	SqlBox  *rice.Box
 | 
			
		||||
	CssBox  *rice.Box
 | 
			
		||||
	ScssBox *rice.Box
 | 
			
		||||
	JsBox   *rice.Box
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +34,6 @@ var (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
func Assets() {
 | 
			
		||||
	SqlBox = rice.MustFindBox("sql")
 | 
			
		||||
	CssBox = rice.MustFindBox("css")
 | 
			
		||||
	ScssBox = rice.MustFindBox("scss")
 | 
			
		||||
	JsBox = rice.MustFindBox("js")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +0,0 @@
 | 
			
		|||
DROP TABLE IF EXISTS core;
 | 
			
		||||
DROP TABLE IF EXISTS hits;
 | 
			
		||||
DROP TABLE IF EXISTS failures;
 | 
			
		||||
DROP TABLE IF EXISTS users;
 | 
			
		||||
DROP TABLE IF EXISTS checkins;
 | 
			
		||||
DROP TABLE IF EXISTS services;
 | 
			
		||||
DROP TABLE IF EXISTS communication;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,83 +0,0 @@
 | 
			
		|||
CREATE TABLE core (
 | 
			
		||||
    name VARCHAR(50),
 | 
			
		||||
    description text,
 | 
			
		||||
    config VARCHAR(50),
 | 
			
		||||
    api_key VARCHAR(50),
 | 
			
		||||
    api_secret VARCHAR(50),
 | 
			
		||||
    style text,
 | 
			
		||||
    footer text,
 | 
			
		||||
    domain text,
 | 
			
		||||
    version VARCHAR(50),
 | 
			
		||||
    migration_id INT(6) NOT NULL DEFAULT 0,
 | 
			
		||||
    use_cdn BOOL NOT NULL DEFAULT '0'
 | 
			
		||||
);
 | 
			
		||||
CREATE TABLE users (
 | 
			
		||||
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
 | 
			
		||||
    username VARCHAR(50) NOT NULL UNIQUE,
 | 
			
		||||
    password text,
 | 
			
		||||
    email VARCHAR (50),
 | 
			
		||||
    api_key VARCHAR(50),
 | 
			
		||||
    api_secret VARCHAR(50),
 | 
			
		||||
    administrator BOOL NOT NULL DEFAULT '0',
 | 
			
		||||
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    INDEX (id),
 | 
			
		||||
    UNIQUE (username, email)
 | 
			
		||||
);
 | 
			
		||||
CREATE TABLE services (
 | 
			
		||||
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
 | 
			
		||||
    name VARCHAR(50),
 | 
			
		||||
    domain text,
 | 
			
		||||
    check_type text,
 | 
			
		||||
    method VARCHAR(50),
 | 
			
		||||
    port INT(6),
 | 
			
		||||
    expected text,
 | 
			
		||||
    expected_status INT(6),
 | 
			
		||||
    check_interval int(11),
 | 
			
		||||
    post_data text,
 | 
			
		||||
    order_id integer default 0,
 | 
			
		||||
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    timeout INT(6) DEFAULT 30,
 | 
			
		||||
    INDEX (id)
 | 
			
		||||
);
 | 
			
		||||
CREATE TABLE hits (
 | 
			
		||||
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
 | 
			
		||||
    service INTEGER NOT NULL,
 | 
			
		||||
    latency float,
 | 
			
		||||
    created_at DATETIME,
 | 
			
		||||
    INDEX (id, service),
 | 
			
		||||
    FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
 | 
			
		||||
);
 | 
			
		||||
CREATE TABLE failures (
 | 
			
		||||
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
 | 
			
		||||
    issue text,
 | 
			
		||||
    method text,
 | 
			
		||||
    service INTEGER NOT NULL,
 | 
			
		||||
    created_at DATETIME,
 | 
			
		||||
    INDEX (id, service),
 | 
			
		||||
    FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
 | 
			
		||||
);
 | 
			
		||||
CREATE TABLE checkins (
 | 
			
		||||
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
 | 
			
		||||
    service INTEGER NOT NULL,
 | 
			
		||||
    check_interval integer,
 | 
			
		||||
    api text,
 | 
			
		||||
    created_at DATETIME,
 | 
			
		||||
    INDEX (id, service),
 | 
			
		||||
    FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
 | 
			
		||||
);
 | 
			
		||||
CREATE TABLE communication (
 | 
			
		||||
    id SERIAL PRIMARY KEY,
 | 
			
		||||
    method text,
 | 
			
		||||
    host text,
 | 
			
		||||
    port integer,
 | 
			
		||||
    username text,
 | 
			
		||||
    password text,
 | 
			
		||||
    var1 text,
 | 
			
		||||
    var2 text,
 | 
			
		||||
    api_key text,
 | 
			
		||||
    api_secret text,
 | 
			
		||||
    enabled BOOL NOT NULL DEFAULT '0',
 | 
			
		||||
    removable BOOL NOT NULL DEFAULT '0',
 | 
			
		||||
    limits integer,
 | 
			
		||||
    created_at DATETIME
 | 
			
		||||
);
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +0,0 @@
 | 
			
		|||
=========================================== 1534178020
 | 
			
		||||
UPDATE services SET order_id=0 WHERE order_id IS NULL;
 | 
			
		||||
=========================================== 1532068515
 | 
			
		||||
ALTER TABLE services ALTER COLUMN order_id integer DEFAULT 0;
 | 
			
		||||
ALTER TABLE services ADD COLUMN timeout integer DEFAULT 30;
 | 
			
		||||
=========================================== 1530841150
 | 
			
		||||
ALTER TABLE core ADD COLUMN use_cdn BOOL NOT NULL DEFAULT '0';
 | 
			
		||||
=========================================== 1
 | 
			
		||||
ALTER TABLE core ADD COLUMN migration_id INT(6) NOT NULL DEFAULT 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,84 +0,0 @@
 | 
			
		|||
CREATE TABLE core (
 | 
			
		||||
    name text,
 | 
			
		||||
    description text,
 | 
			
		||||
    config text,
 | 
			
		||||
    api_key text,
 | 
			
		||||
    api_secret text,
 | 
			
		||||
    style text,
 | 
			
		||||
    footer text,
 | 
			
		||||
    domain text,
 | 
			
		||||
    version text,
 | 
			
		||||
    migration_id integer default 0,
 | 
			
		||||
    use_cdn bool default false
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE users (
 | 
			
		||||
    id SERIAL PRIMARY KEY,
 | 
			
		||||
    username VARCHAR (50) UNIQUE,
 | 
			
		||||
    password text,
 | 
			
		||||
    email VARCHAR (50) UNIQUE,
 | 
			
		||||
    api_key text,
 | 
			
		||||
    api_secret text,
 | 
			
		||||
    administrator bool,
 | 
			
		||||
    created_at TIMESTAMP
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE services (
 | 
			
		||||
    id SERIAL PRIMARY KEY,
 | 
			
		||||
    name text,
 | 
			
		||||
    domain text,
 | 
			
		||||
    check_type text,
 | 
			
		||||
    method text,
 | 
			
		||||
    port integer,
 | 
			
		||||
    expected text,
 | 
			
		||||
    expected_status integer,
 | 
			
		||||
    check_interval integer,
 | 
			
		||||
    post_data text,
 | 
			
		||||
    order_id integer default 0,
 | 
			
		||||
    timeout integer default 30,
 | 
			
		||||
    created_at TIMESTAMP
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE hits (
 | 
			
		||||
    id SERIAL PRIMARY KEY,
 | 
			
		||||
    service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
 | 
			
		||||
    latency float,
 | 
			
		||||
    created_at TIMESTAMP
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE failures (
 | 
			
		||||
    id SERIAL PRIMARY KEY,
 | 
			
		||||
    issue text,
 | 
			
		||||
    method text,
 | 
			
		||||
    service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
 | 
			
		||||
    created_at TIMESTAMP
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE checkins (
 | 
			
		||||
    id SERIAL PRIMARY KEY,
 | 
			
		||||
    service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
 | 
			
		||||
    check_interval integer,
 | 
			
		||||
    api text,
 | 
			
		||||
    created_at TIMESTAMP
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE communication (
 | 
			
		||||
    id SERIAL PRIMARY KEY,
 | 
			
		||||
    method text,
 | 
			
		||||
    host text,
 | 
			
		||||
    port integer,
 | 
			
		||||
    username text,
 | 
			
		||||
    password text,
 | 
			
		||||
    var1 text,
 | 
			
		||||
    var2 text,
 | 
			
		||||
    api_key text,
 | 
			
		||||
    api_secret text,
 | 
			
		||||
    enabled boolean,
 | 
			
		||||
    removable boolean,
 | 
			
		||||
    limits integer,
 | 
			
		||||
    created_at TIMESTAMP
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX idx_hits ON hits(service);
 | 
			
		||||
CREATE INDEX idx_failures ON failures(service);
 | 
			
		||||
CREATE INDEX idx_checkins ON checkins(service);
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +0,0 @@
 | 
			
		|||
=========================================== 1534178020
 | 
			
		||||
UPDATE services SET order_id=0 WHERE order_id IS NULL;
 | 
			
		||||
=========================================== 1532068515
 | 
			
		||||
ALTER TABLE services ALTER COLUMN order_id integer DEFAULT 0;
 | 
			
		||||
ALTER TABLE services ADD COLUMN timeout integer DEFAULT 30;
 | 
			
		||||
=========================================== 1530841150
 | 
			
		||||
ALTER TABLE core ADD COLUMN use_cdn bool DEFAULT FALSE;
 | 
			
		||||
=========================================== 1
 | 
			
		||||
ALTER TABLE core ADD COLUMN migration_id integer default 0 NOT NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,86 +0,0 @@
 | 
			
		|||
CREATE TABLE core (
 | 
			
		||||
    name text,
 | 
			
		||||
    description text,
 | 
			
		||||
    config text,
 | 
			
		||||
    api_key text,
 | 
			
		||||
    api_secret text,
 | 
			
		||||
    style text,
 | 
			
		||||
    footer text,
 | 
			
		||||
    domain text,
 | 
			
		||||
    version text,
 | 
			
		||||
    migration_id integer default 0,
 | 
			
		||||
    use_cdn bool default false
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE users (
 | 
			
		||||
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
 | 
			
		||||
    username text NOT NULL UNIQUE,
 | 
			
		||||
    password text,
 | 
			
		||||
    email text,
 | 
			
		||||
    api_key text,
 | 
			
		||||
    api_secret text,
 | 
			
		||||
    administrator bool,
 | 
			
		||||
    created_at DATETIME,
 | 
			
		||||
    UNIQUE (username, email)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE services (
 | 
			
		||||
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
 | 
			
		||||
    name text,
 | 
			
		||||
    domain text,
 | 
			
		||||
    check_type text,
 | 
			
		||||
    method text,
 | 
			
		||||
    port integer,
 | 
			
		||||
    expected text,
 | 
			
		||||
    expected_status integer,
 | 
			
		||||
    check_interval integer,
 | 
			
		||||
    post_data text,
 | 
			
		||||
    order_id integer default 0,
 | 
			
		||||
    timeout integer default 30,
 | 
			
		||||
    created_at DATETIME
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE hits (
 | 
			
		||||
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
 | 
			
		||||
    service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
 | 
			
		||||
    latency float,
 | 
			
		||||
    created_at DATETIME
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE failures (
 | 
			
		||||
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
 | 
			
		||||
    issue text,
 | 
			
		||||
    method text,
 | 
			
		||||
    service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
 | 
			
		||||
    created_at DATETIME
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE checkins (
 | 
			
		||||
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
 | 
			
		||||
    service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
 | 
			
		||||
    check_interval integer,
 | 
			
		||||
    api text,
 | 
			
		||||
    created_at DATETIME
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE communication (
 | 
			
		||||
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
 | 
			
		||||
    method text,
 | 
			
		||||
    host text,
 | 
			
		||||
    port integer,
 | 
			
		||||
    username text,
 | 
			
		||||
    password text,
 | 
			
		||||
    var1 text,
 | 
			
		||||
    var2 text,
 | 
			
		||||
    api_key text,
 | 
			
		||||
    api_secret text,
 | 
			
		||||
    enabled boolean,
 | 
			
		||||
    removable boolean,
 | 
			
		||||
    limits integer,
 | 
			
		||||
    created_at DATETIME
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CREATE INDEX idx_hits ON hits(service);
 | 
			
		||||
CREATE INDEX idx_failures ON failures(service);
 | 
			
		||||
CREATE INDEX idx_checkins ON checkins(service);
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +0,0 @@
 | 
			
		|||
=========================================== 1534178020
 | 
			
		||||
UPDATE services SET order_id=0 WHERE order_id IS NULL;
 | 
			
		||||
=========================================== 1532068515
 | 
			
		||||
ALTER TABLE services ALTER COLUMN order_id integer DEFAULT 0;
 | 
			
		||||
ALTER TABLE services ADD COLUMN timeout integer DEFAULT 30;
 | 
			
		||||
=========================================== 1530841150
 | 
			
		||||
ALTER TABLE core ADD COLUMN use_cdn bool DEFAULT FALSE;
 | 
			
		||||
=========================================== 1
 | 
			
		||||
ALTER TABLE core ADD COLUMN migration_id integer NOT NULL DEFAULT 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
{{ define "footer"}}
 | 
			
		||||
    <div class="footer text-center mb-4">
 | 
			
		||||
    {{ if CoreApp.Footer }}
 | 
			
		||||
       {{ safe CoreApp.Footer }}
 | 
			
		||||
    {{ if ne CoreApp.Footer "" }}
 | 
			
		||||
        {{ safe CoreApp.Footer }}
 | 
			
		||||
    {{ else }}
 | 
			
		||||
        <a href="https://github.com/hunterlong/statup" target="_blank">Statup {{VERSION}} made with ❤️</a> | <a href="/dashboard">Dashboard</a>
 | 
			
		||||
    {{ end }}
 | 
			
		||||
    </div>
 | 
			
		||||
{{ end }}
 | 
			
		||||
{{ end }}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,14 +73,14 @@
 | 
			
		|||
                                Average Response
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div class="col-4">
 | 
			
		||||
                                <span class="lg_number">{{.AvgUptime}}%</span>
 | 
			
		||||
                                Total Uptime
 | 
			
		||||
                                <span class="lg_number">{{.AvgUptime24}}%</span>
 | 
			
		||||
                                Uptime last 24 Hours
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                {{ if .AvgTime }}
 | 
			
		||||
                {{ if .AvgUptime24 }}
 | 
			
		||||
                    <div class="chart-container">
 | 
			
		||||
                        <canvas id="service_{{ .Id }}"></canvas>
 | 
			
		||||
                    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -127,4 +127,4 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,7 @@
 | 
			
		|||
                            </div>
 | 
			
		||||
 | 
			
		||||
                            <div class="col-4">
 | 
			
		||||
                                <span class="lg_number">{{.AvgUptime}}%</span>
 | 
			
		||||
                                <span class="lg_number">{{.TotalUptime}}%</span>
 | 
			
		||||
                                Total Uptime
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -277,4 +277,4 @@
 | 
			
		|||
{{end}}
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -237,4 +237,4 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,16 @@
 | 
			
		|||
package types
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Checkin struct {
 | 
			
		||||
	Id               int       `db:"id,omitempty"`
 | 
			
		||||
	Service          int64     `db:"service"`
 | 
			
		||||
	Interval         int64     `db:"check_interval"`
 | 
			
		||||
	Api              string    `db:"api"`
 | 
			
		||||
	CreatedAt        time.Time `db:"created_at"`
 | 
			
		||||
	Id               int64     `gorm:"primary_key;column:id"`
 | 
			
		||||
	Service          int64     `gorm:"index;column:service"`
 | 
			
		||||
	Interval         int64     `gorm:"column:check_interval"`
 | 
			
		||||
	Api              string    `gorm:"column:api"`
 | 
			
		||||
	CreatedAt        time.Time `gorm:"column:created_at" json:"created_at"`
 | 
			
		||||
	UpdatedAt        time.Time `gorm:"column:updated_at" json:"updated_at"`
 | 
			
		||||
	Hits             int64     `json:"hits"`
 | 
			
		||||
	Last             time.Time `json:"last"`
 | 
			
		||||
	CheckinInterface `json:"-"`
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,30 +1,45 @@
 | 
			
		|||
package types
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
import (
 | 
			
		||||
	"sort"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Core struct contains all the required fields for Statup. All application settings
 | 
			
		||||
// will be saved into 1 row in the 'core' table. You can use the core.CoreApp
 | 
			
		||||
// global variable to interact with the attributes to the application, such as services.
 | 
			
		||||
type Core struct {
 | 
			
		||||
	Name           string          `db:"name" json:"name"`
 | 
			
		||||
	Description    string          `db:"description" json:"description,omitempty"`
 | 
			
		||||
	Config         string          `db:"config" json:"-"`
 | 
			
		||||
	ApiKey         string          `db:"api_key" json:"-"`
 | 
			
		||||
	ApiSecret      string          `db:"api_secret" json:"-"`
 | 
			
		||||
	Style          string          `db:"style" json:"style,omitempty"`
 | 
			
		||||
	Footer         string          `db:"footer" json:"footer,omitempty"`
 | 
			
		||||
	Domain         string          `db:"domain" json:"domain,omitempty"`
 | 
			
		||||
	Version        string          `db:"version" json:"version"`
 | 
			
		||||
	MigrationId    int64           `db:"migration_id" json:"migration_id,omitempty"`
 | 
			
		||||
	UseCdn         bool            `db:"use_cdn" json:"using_cdn,omitempty"`
 | 
			
		||||
	DbConnection   string          `json:"database"`
 | 
			
		||||
	Started        time.Time       `json:"started_on"`
 | 
			
		||||
	dbServices     []*Service      `json:"services,omitempty"`
 | 
			
		||||
	Plugins        []Info          `json:"-"`
 | 
			
		||||
	Repos          []PluginJSON    `json:"-"`
 | 
			
		||||
	AllPlugins     []PluginActions `json:"-"`
 | 
			
		||||
	Communications []AllNotifiers  `json:"-"`
 | 
			
		||||
	CoreInterface  `json:"-"`
 | 
			
		||||
	Name           string          `gorm:"not null;column:name" json:"name"`
 | 
			
		||||
	Description    string          `gorm:"not null;column:description" json:"description,omitempty"`
 | 
			
		||||
	Config         string          `gorm:"column:config" json:"-"`
 | 
			
		||||
	ApiKey         string          `gorm:"column:api_key" json:"-"`
 | 
			
		||||
	ApiSecret      string          `gorm:"column:api_secret" json:"-"`
 | 
			
		||||
	Style          string          `gorm:"not null;column:style" json:"style,omitempty"`
 | 
			
		||||
	Footer         string          `gorm:"not null;column:footer" json:"footer,omitempty"`
 | 
			
		||||
	Domain         string          `gorm:"not null;column:domain" json:"domain,omitempty"`
 | 
			
		||||
	Version        string          `gorm:"column:version" json:"version"`
 | 
			
		||||
	MigrationId    int64           `gorm:"column:migration_id" json:"migration_id,omitempty"`
 | 
			
		||||
	UseCdn         bool            `gorm:"column:use_cdn;default:false" json:"using_cdn,omitempty"`
 | 
			
		||||
	CreatedAt      time.Time       `gorm:"column:created_at" json:"created_at"`
 | 
			
		||||
	UpdatedAt      time.Time       `gorm:"column:updated_at" json:"updated_at"`
 | 
			
		||||
	DbConnection   string          `gorm:"-" json:"database"`
 | 
			
		||||
	Started        time.Time       `gorm:"-" json:"started_on"`
 | 
			
		||||
	dbServices     []*Service      `gorm:"-" json:"services,omitempty"`
 | 
			
		||||
	Plugins        []Info          `gorm:"-" json:"-"`
 | 
			
		||||
	Repos          []PluginJSON    `gorm:"-" json:"-"`
 | 
			
		||||
	AllPlugins     []PluginActions `gorm:"-" json:"-"`
 | 
			
		||||
	Communications []AllNotifiers  `gorm:"-" json:"-"`
 | 
			
		||||
	CoreInterface  `gorm:"-" json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ServiceOrder []*Service
 | 
			
		||||
 | 
			
		||||
func (c ServiceOrder) Len() int           { return len(c) }
 | 
			
		||||
func (c ServiceOrder) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
 | 
			
		||||
func (c ServiceOrder) Less(i, j int) bool { return c[i].Order < c[j].Order }
 | 
			
		||||
 | 
			
		||||
func (c *Core) SetServices(s []*Service) {
 | 
			
		||||
	sort.Sort(ServiceOrder(c.dbServices))
 | 
			
		||||
	c.dbServices = s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +1,16 @@
 | 
			
		|||
package types
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Failure struct {
 | 
			
		||||
	Id               int       `db:"id,omitempty" json:"id"`
 | 
			
		||||
	Issue            string    `db:"issue" json:"issue"`
 | 
			
		||||
	Method           string    `db:"method" json:"method,omitempty"`
 | 
			
		||||
	Service          int64     `db:"service" json:"service_id"`
 | 
			
		||||
	CreatedAt        time.Time `db:"created_at" json:"created_at"`
 | 
			
		||||
	FailureInterface `json:"-"`
 | 
			
		||||
	Id               int64     `gorm:"primary_key;column:id" json:"id"`
 | 
			
		||||
	Issue            string    `gorm:"column:issue" json:"issue"`
 | 
			
		||||
	Method           string    `gorm:"column:method" json:"method,omitempty"`
 | 
			
		||||
	Service          int64     `gorm:"index;column:service" json:"service_id"`
 | 
			
		||||
	CreatedAt        time.Time `gorm:"column:created_at" json:"created_at"`
 | 
			
		||||
	FailureInterface `gorm:"-" json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FailureInterface interface {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,33 +20,33 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
type Service struct {
 | 
			
		||||
	Id               int64      `db:"id,omitempty" json:"id"`
 | 
			
		||||
	Name             string     `db:"name" json:"name"`
 | 
			
		||||
	Domain           string     `db:"domain" json:"domain"`
 | 
			
		||||
	Expected         string     `db:"expected" json:"expected"`
 | 
			
		||||
	ExpectedStatus   int        `db:"expected_status" json:"expected_status"`
 | 
			
		||||
	Interval         int        `db:"check_interval" json:"check_interval"`
 | 
			
		||||
	Type             string     `db:"check_type" json:"type"`
 | 
			
		||||
	Method           string     `db:"method" json:"method"`
 | 
			
		||||
	PostData         string     `db:"post_data" json:"post_data"`
 | 
			
		||||
	Port             int        `db:"port" json:"port"`
 | 
			
		||||
	CreatedAt        time.Time  `db:"created_at" json:"created_at"`
 | 
			
		||||
	Timeout          int        `db:"timeout" json:"timeout"`
 | 
			
		||||
	Order            int        `db:"order_id" json:"order_id"`
 | 
			
		||||
	Online           bool       `json:"online"`
 | 
			
		||||
	Latency          float64    `json:"latency"`
 | 
			
		||||
	Online24Hours    float32    `json:"24_hours_online"`
 | 
			
		||||
	AvgResponse      string     `json:"avg_response"`
 | 
			
		||||
	TotalUptime      string     `json:"uptime"`
 | 
			
		||||
	Failures         []*Failure `json:"failures"`
 | 
			
		||||
	Checkins         []*Checkin `json:"checkins"`
 | 
			
		||||
	Running          chan bool  `json:"-"`
 | 
			
		||||
	Checkpoint       time.Time  `json:"-"`
 | 
			
		||||
	LastResponse     string     `json:"-"`
 | 
			
		||||
	LastStatusCode   int        `json:"status_code"`
 | 
			
		||||
	LastOnline       time.Time  `json:"last_online"`
 | 
			
		||||
	DnsLookup        float64    `json:"dns_lookup_time"`
 | 
			
		||||
	ServiceInterface `json:"-"`
 | 
			
		||||
	Id               int64      `gorm:"primary_key;column:id" json:"id"`
 | 
			
		||||
	Name             string     `gorm:"column:name" json:"name"`
 | 
			
		||||
	Domain           string     `gorm:"column:domain" json:"domain"`
 | 
			
		||||
	Expected         string     `gorm:"not null;column:expected" json:"expected"`
 | 
			
		||||
	ExpectedStatus   int        `gorm:"default:200;column:expected_status" json:"expected_status"`
 | 
			
		||||
	Interval         int        `gorm:"default:30;column:check_interval" json:"check_interval"`
 | 
			
		||||
	Type             string     `gorm:"column:check_type" json:"type"`
 | 
			
		||||
	Method           string     `gorm:"column:method" json:"method"`
 | 
			
		||||
	PostData         string     `gorm:"not null;column:post_data" json:"post_data"`
 | 
			
		||||
	Port             int        `gorm:"not null;column:port" json:"port"`
 | 
			
		||||
	Timeout          int        `gorm:"default:30;column:timeout" json:"timeout"`
 | 
			
		||||
	Order            int        `gorm:"default:0;column:order_id" json:"order_id"`
 | 
			
		||||
	CreatedAt        time.Time  `gorm:"column:created_at" json:"created_at"`
 | 
			
		||||
	UpdatedAt        time.Time  `gorm:"column:updated_at" json:"updated_at"`
 | 
			
		||||
	Online           bool       `gorm:"-" json:"online"`
 | 
			
		||||
	Latency          float64    `gorm:"-" json:"latency"`
 | 
			
		||||
	Online24Hours    float32    `gorm:"-" json:"24_hours_online"`
 | 
			
		||||
	AvgResponse      string     `gorm:"-" json:"avg_response"`
 | 
			
		||||
	Failures         []*Failure `gorm:"-" json:"failures"`
 | 
			
		||||
	Checkins         []*Checkin `gorm:"-" json:"checkins"`
 | 
			
		||||
	Running          chan bool  `gorm:"-" json:"-"`
 | 
			
		||||
	Checkpoint       time.Time  `gorm:"-" json:"-"`
 | 
			
		||||
	LastResponse     string     `gorm:"-" json:"-"`
 | 
			
		||||
	LastStatusCode   int        `gorm:"-" json:"status_code"`
 | 
			
		||||
	LastOnline       time.Time  `gorm:"-" json:"last_online"`
 | 
			
		||||
	DnsLookup        float64    `gorm:"-" json:"dns_lookup_time"`
 | 
			
		||||
	ServiceInterface `gorm:"-" json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ServiceInterface interface {
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +56,7 @@ type ServiceInterface interface {
 | 
			
		|||
	Delete() error
 | 
			
		||||
	// Basic Method functions
 | 
			
		||||
	AvgTime() float64
 | 
			
		||||
	OnlineSince(time.Time) float32
 | 
			
		||||
	Online24() float32
 | 
			
		||||
	SmallText() string
 | 
			
		||||
	GraphData() string
 | 
			
		||||
| 
						 | 
				
			
			@ -65,13 +66,15 @@ type ServiceInterface interface {
 | 
			
		|||
	CreateFailure(*Failure) (int64, error)
 | 
			
		||||
	LimitedFailures() []*Failure
 | 
			
		||||
	AllFailures() []*Failure
 | 
			
		||||
	TotalFailuresSince(time.Time) (uint64, error)
 | 
			
		||||
	TotalFailures24() (uint64, error)
 | 
			
		||||
	TotalFailures() (uint64, error)
 | 
			
		||||
	TotalFailures24Hours() (uint64, error)
 | 
			
		||||
	DeleteFailures()
 | 
			
		||||
	// Hits functions (successful responses)
 | 
			
		||||
	CreateHit(*Hit) (int64, error)
 | 
			
		||||
	Hits() ([]*Hit, error)
 | 
			
		||||
	TotalHits() (uint64, error)
 | 
			
		||||
	TotalHitsSince(time.Time) (uint64, error)
 | 
			
		||||
	Sum() (float64, error)
 | 
			
		||||
	LimitedHits() ([]*Hit, error)
 | 
			
		||||
	SelectHitsGroupBy(string) ([]*Hit, error)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,9 +16,9 @@
 | 
			
		|||
package types
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/jinzhu/gorm"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
	"upper.io/db.v3/lib/sqlbuilder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type PluginInfo struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ type Info struct {
 | 
			
		|||
type PluginActions interface {
 | 
			
		||||
	GetInfo() Info
 | 
			
		||||
	GetForm() string
 | 
			
		||||
	OnLoad(sqlbuilder.Database)
 | 
			
		||||
	OnLoad(db gorm.DB)
 | 
			
		||||
	SetInfo(map[string]interface{}) Info
 | 
			
		||||
	Routes() []Routing
 | 
			
		||||
	OnSave(map[string]interface{})
 | 
			
		||||
| 
						 | 
				
			
			@ -61,23 +61,15 @@ type PluginActions interface {
 | 
			
		|||
 | 
			
		||||
type AllNotifiers interface{}
 | 
			
		||||
 | 
			
		||||
// Hit struct is a 'successful' ping or web response entry for a service.
 | 
			
		||||
type Hit struct {
 | 
			
		||||
	Id        int       `db:"id,omitempty"`
 | 
			
		||||
	Service   int64     `db:"service"`
 | 
			
		||||
	Latency   float64   `db:"latency"`
 | 
			
		||||
	CreatedAt time.Time `db:"created_at"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	Connection string `yaml:"connection"`
 | 
			
		||||
	Host       string `yaml:"host"`
 | 
			
		||||
	Database   string `yaml:"database"`
 | 
			
		||||
	User       string `yaml:"user"`
 | 
			
		||||
	Password   string `yaml:"password"`
 | 
			
		||||
	Port       string `yaml:"port"`
 | 
			
		||||
	Secret     string `yaml:"secret"`
 | 
			
		||||
	Id        int64     `gorm:"primary_key;column:id"`
 | 
			
		||||
	Service   int64     `gorm:"index;column:service"`
 | 
			
		||||
	Latency   float64   `gorm:"column:latency"`
 | 
			
		||||
	CreatedAt time.Time `gorm:"column:created_at"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DbConfig struct is used for the database connection and creates the 'config.yml' file
 | 
			
		||||
type DbConfig struct {
 | 
			
		||||
	DbConn      string `yaml:"connection"`
 | 
			
		||||
	DbHost      string `yaml:"host"`
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +1,20 @@
 | 
			
		|||
package types
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type User struct {
 | 
			
		||||
	Id            int64     `db:"id,omitempty" json:"id"`
 | 
			
		||||
	Username      string    `db:"username" json:"username"`
 | 
			
		||||
	Password      string    `db:"password" json:"-"`
 | 
			
		||||
	Email         string    `db:"email" json:"-"`
 | 
			
		||||
	ApiKey        string    `db:"api_key" json:"api_key"`
 | 
			
		||||
	ApiSecret     string    `db:"api_secret" json:"-"`
 | 
			
		||||
	Admin         bool      `db:"administrator" json:"admin"`
 | 
			
		||||
	CreatedAt     time.Time `db:"created_at" json:"created_at"`
 | 
			
		||||
	UserInterface `json:"-"`
 | 
			
		||||
	Id            int64     `gorm:"primary_key;column:id" json:"id"`
 | 
			
		||||
	Username      string    `gorm:"type:varchar(100);unique;column:username;" json:"username"`
 | 
			
		||||
	Password      string    `gorm:"column:password" json:"-"`
 | 
			
		||||
	Email         string    `gorm:"type:varchar(100);unique;column:email" json:"-"`
 | 
			
		||||
	ApiKey        string    `gorm:"column:api_key" json:"api_key"`
 | 
			
		||||
	ApiSecret     string    `gorm:"column:api_secret" json:"-"`
 | 
			
		||||
	Admin         bool      `gorm:"column:administrator" json:"admin"`
 | 
			
		||||
	CreatedAt     time.Time `gorm:"column:created_at" json:"created_at"`
 | 
			
		||||
	UpdatedAt     time.Time `gorm:"column:updated_at" json:"updated_at"`
 | 
			
		||||
	UserInterface `gorm:"-" json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserInterface interface {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,10 @@ var (
 | 
			
		|||
	LockLines sync.Mutex
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Logger() *lumberjack.Logger {
 | 
			
		||||
	return ljLogger
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createLog(dir string) error {
 | 
			
		||||
	var err error
 | 
			
		||||
	_, err = os.Stat(dir + "/logs")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,8 +16,11 @@
 | 
			
		|||
package utils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/ararog/timeago"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
| 
						 | 
				
			
			@ -97,6 +100,7 @@ func FileExists(name string) bool {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func DeleteFile(file string) error {
 | 
			
		||||
	Log(1, "deleting file: "+file)
 | 
			
		||||
	err := os.Remove(file)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
| 
						 | 
				
			
			@ -107,3 +111,56 @@ func DeleteFile(file string) error {
 | 
			
		|||
func DeleteDirectory(directory string) error {
 | 
			
		||||
	return os.RemoveAll(directory)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Command(cmd string) (string, string, error) {
 | 
			
		||||
	Log(1, "running command: "+cmd)
 | 
			
		||||
	testCmd := exec.Command("sh", "-c", cmd)
 | 
			
		||||
	var stdout, stderr []byte
 | 
			
		||||
	var errStdout, errStderr error
 | 
			
		||||
	stdoutIn, _ := testCmd.StdoutPipe()
 | 
			
		||||
	stderrIn, _ := testCmd.StderrPipe()
 | 
			
		||||
	testCmd.Start()
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		stderr, errStderr = copyAndCapture(os.Stderr, stderrIn)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	err := testCmd.Wait()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if errStdout != nil || errStderr != nil {
 | 
			
		||||
		return "", "", errors.New("failed to capture stdout or stderr")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	outStr, errStr := string(stdout), string(stderr)
 | 
			
		||||
	return outStr, errStr, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) {
 | 
			
		||||
	var out []byte
 | 
			
		||||
	buf := make([]byte, 1024, 1024)
 | 
			
		||||
	for {
 | 
			
		||||
		n, err := r.Read(buf[:])
 | 
			
		||||
		if n > 0 {
 | 
			
		||||
			d := buf[:n]
 | 
			
		||||
			out = append(out, d...)
 | 
			
		||||
			_, err := w.Write(d)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return out, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// Read returns io.EOF at the end of file, which is not an error for us
 | 
			
		||||
			if err == io.EOF {
 | 
			
		||||
				err = nil
 | 
			
		||||
			}
 | 
			
		||||
			return out, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue