Add Wake On Lan Feature
This commit is contained in:
		
							parent
							
								
									7988015983
								
							
						
					
					
						commit
						9d5fc3f72b
					
				
							
								
								
									
										19
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										19
									
								
								go.mod
								
								
								
								
							|  | @ -5,27 +5,22 @@ go 1.14 | ||||||
| require ( | require ( | ||||||
| 	github.com/GeertJohan/go.rice v1.0.0 | 	github.com/GeertJohan/go.rice v1.0.0 | ||||||
| 	github.com/glendc/go-external-ip v0.0.0-20170425150139-139229dcdddd | 	github.com/glendc/go-external-ip v0.0.0-20170425150139-139229dcdddd | ||||||
|  | 	github.com/go-playground/universal-translator v0.17.0 // indirect | ||||||
| 	github.com/gorilla/sessions v1.2.0 | 	github.com/gorilla/sessions v1.2.0 | ||||||
|  | 	github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 // indirect | ||||||
| 	github.com/labstack/echo-contrib v0.9.0 | 	github.com/labstack/echo-contrib v0.9.0 | ||||||
| 	github.com/labstack/echo/v4 v4.1.16 | 	github.com/labstack/echo/v4 v4.1.16 | ||||||
| 	github.com/labstack/gommon v0.3.0 | 	github.com/labstack/gommon v0.3.0 | ||||||
|  | 	github.com/leodido/go-urn v1.2.0 // indirect | ||||||
| 	github.com/rs/xid v1.2.1 | 	github.com/rs/xid v1.2.1 | ||||||
| 	github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba | 	github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba | ||||||
|  | 	github.com/sendgrid/rest v2.6.4+incompatible // indirect | ||||||
| 	github.com/sendgrid/sendgrid-go v3.10.0+incompatible | 	github.com/sendgrid/sendgrid-go v3.10.0+incompatible | ||||||
| 	github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086 | 	github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086 | ||||||
| 	github.com/xhit/go-simple-mail/v2 v2.10.0 | 	github.com/xhit/go-simple-mail/v2 v2.10.0 | ||||||
|  | 	//golang.zx2c4.com/wireguard v0.0.20200121 // indirect | ||||||
| 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c | 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c | ||||||
| 	gopkg.in/go-playground/validator.v9 v9.31.0 |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| require ( |  | ||||||
| 	github.com/go-playground/universal-translator v0.17.0 // indirect |  | ||||||
| 	github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 // indirect |  | ||||||
| 	github.com/leodido/go-urn v1.2.0 // indirect |  | ||||||
| 	github.com/sendgrid/rest v2.6.4+incompatible // indirect |  | ||||||
| 	golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect |  | ||||||
| 	golang.org/x/net v0.0.0-20211215060638-4ddde0e984e9 // indirect |  | ||||||
| 	golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect |  | ||||||
| 	golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 // indirect |  | ||||||
| 	gopkg.in/go-playground/assert.v1 v1.2.1 // indirect | 	gopkg.in/go-playground/assert.v1 v1.2.1 // indirect | ||||||
|  | 	gopkg.in/go-playground/validator.v9 v9.31.0 | ||||||
|  | 	github.com/sabhiram/go-wol v0.0.0-20211224004021-c83b0c2f887d | ||||||
| ) | ) | ||||||
|  |  | ||||||
							
								
								
									
										50
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										50
									
								
								go.sum
								
								
								
								
							|  | @ -11,10 +11,10 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce | ||||||
| github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= | ||||||
| github.com/casbin/casbin/v2 v2.0.0/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= | github.com/casbin/casbin/v2 v2.0.0/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= | ||||||
| github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= | github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= | ||||||
|  | github.com/coreos/bbolt v1.3.1-coreos.6.0.20180223184059-4f5275f4ebbf/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= | ||||||
| github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= | github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= | ||||||
| github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= | github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= | ||||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |  | ||||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= | ||||||
| github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | ||||||
|  | @ -50,6 +50,7 @@ github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYb | ||||||
| github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= | github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= | ||||||
| github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 h1:EFT6MH3igZK/dIVqgGbTqWVvkZ7wJ5iGN03SVtvvdd8= | github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 h1:EFT6MH3igZK/dIVqgGbTqWVvkZ7wJ5iGN03SVtvvdd8= | ||||||
| github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25/go.mod h1:sWkGw/wsaHtRsT9zGQ/WyJCotGWG/Anow/9hsAcBWRw= | github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25/go.mod h1:sWkGw/wsaHtRsT9zGQ/WyJCotGWG/Anow/9hsAcBWRw= | ||||||
|  | github.com/jessevdk/go-flags v0.0.0-20150816100521-1acbbaff2f34/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= | ||||||
| github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= | ||||||
| github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= | github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= | ||||||
| github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= | github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= | ||||||
|  | @ -59,7 +60,6 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqo | ||||||
| github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= | github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= | ||||||
| github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= | github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= | ||||||
| github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= | github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= | ||||||
| github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b h1:c3NTyLNozICy8B4mlMXemD3z/gXgQzVXZS/HqT+i3do= |  | ||||||
| github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= | github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= | ||||||
| github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | ||||||
| github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||||
|  | @ -77,14 +77,15 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL | ||||||
| github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= | ||||||
| github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= | ||||||
| github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | ||||||
| github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= |  | ||||||
| github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= | ||||||
|  | github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= | ||||||
|  | github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= | ||||||
| github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | ||||||
| github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= | ||||||
| github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= |  | ||||||
| github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= | ||||||
|  | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= | ||||||
|  | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= | ||||||
| github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | ||||||
| github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY= |  | ||||||
| github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= | github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= | ||||||
| github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= | github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= | ||||||
| github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= | github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= | ||||||
|  | @ -98,7 +99,6 @@ github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnN | ||||||
| github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= | github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= | ||||||
| github.com/mdlayher/netlink v1.4.0 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0= | github.com/mdlayher/netlink v1.4.0 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0= | ||||||
| github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= | github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= | ||||||
| github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= |  | ||||||
| github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= | github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= | ||||||
| github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||||
|  | @ -109,7 +109,6 @@ github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYX | ||||||
| github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= | ||||||
| github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
| github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |  | ||||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
| github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= | ||||||
| github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= | ||||||
|  | @ -123,6 +122,9 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT | ||||||
| github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= | github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= | ||||||
| github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= | github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= | ||||||
| github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= | ||||||
|  | github.com/sabhiram/go-colorize v0.0.0-20210403184538-366f55d711cf/go.mod h1:GvlEbMJBpbAXFn06UajbdBlGZ18iLvHyuIrgG//L8uk= | ||||||
|  | github.com/sabhiram/go-wol v0.0.0-20211224004021-c83b0c2f887d h1:NDtoSmsxTpDYTqvUurn2ooAzDaYbJSB9/tOhLzaewgo= | ||||||
|  | github.com/sabhiram/go-wol v0.0.0-20211224004021-c83b0c2f887d/go.mod h1:SVPBBd492Gk7Cq5lPd6OAYtIGk2r1FsyH8KT3IB8h7c= | ||||||
| github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba h1:8QAc9wFAf2b/9cAXskm0wBylObZ0bTpRcaP7ThjLPVQ= | github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba h1:8QAc9wFAf2b/9cAXskm0wBylObZ0bTpRcaP7ThjLPVQ= | ||||||
| github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba/go.mod h1:W6zxGUBCXRR5QugSd/nFcFVmwoGnvpjiNY/JwT03Wew= | github.com/sdomino/scribble v0.0.0-20191024200645-4116320640ba/go.mod h1:W6zxGUBCXRR5QugSd/nFcFVmwoGnvpjiNY/JwT03Wew= | ||||||
| github.com/sendgrid/rest v2.6.4+incompatible h1:lq6gAQxLwVBf3mVyCCSHI6mgF+NfaJFJHjT0kl6SSo8= | github.com/sendgrid/rest v2.6.4+incompatible h1:lq6gAQxLwVBf3mVyCCSHI6mgF+NfaJFJHjT0kl6SSo8= | ||||||
|  | @ -135,9 +137,9 @@ github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086/go.mod h1:PLPIyL7i | ||||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
| github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= | ||||||
|  | github.com/stretchr/testify v0.0.0-20150929183540-2b15294402a8/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||||
| github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= |  | ||||||
| github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||||||
| github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= | github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= | ||||||
| github.com/uber/jaeger-client-go v2.19.1-0.20191002155754-0be28c34dabf+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= | github.com/uber/jaeger-client-go v2.19.1-0.20191002155754-0be28c34dabf+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= | ||||||
|  | @ -149,25 +151,20 @@ github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy | ||||||
| github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= | github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= | ||||||
| github.com/xhit/go-simple-mail/v2 v2.10.0 h1:nib6RaJ4qVh5HD9UE9QJqnUZyWp3upv+Z6CFxaMj0V8= | github.com/xhit/go-simple-mail/v2 v2.10.0 h1:nib6RaJ4qVh5HD9UE9QJqnUZyWp3upv+Z6CFxaMj0V8= | ||||||
| github.com/xhit/go-simple-mail/v2 v2.10.0/go.mod h1:kA1XbQfCI4JxQ9ccSN6VFyIEkkugOm7YiPkA5hKiQn4= | github.com/xhit/go-simple-mail/v2 v2.10.0/go.mod h1:kA1XbQfCI4JxQ9ccSN6VFyIEkkugOm7YiPkA5hKiQn4= | ||||||
| github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= |  | ||||||
| go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | ||||||
| golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||||
| golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||||
| golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |  | ||||||
| golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||||
| golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||||
| golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= | golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= | ||||||
|  | golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= | ||||||
| golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= | golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= | ||||||
| golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= |  | ||||||
| golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= |  | ||||||
| golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |  | ||||||
| golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||||
| golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||||
| golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
| golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
| golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |  | ||||||
| golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
| golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
| golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
|  | @ -178,15 +175,11 @@ golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v | ||||||
| golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||||||
| golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||||||
| golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||||||
|  | golang.org/x/net v0.0.0-20210504132125-bbd867fde50d h1:nTDGCTeAu2LhcsHTRzjyIUbZHCJ4QePArsm27Hka0UM= | ||||||
| golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||||||
| golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= |  | ||||||
| golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= |  | ||||||
| golang.org/x/net v0.0.0-20211215060638-4ddde0e984e9 h1:kmreh1vGI63l2FxOAYS3Yv6ATsi7lSTuwNSVbGfJV9I= |  | ||||||
| golang.org/x/net v0.0.0-20211215060638-4ddde0e984e9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= |  | ||||||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |  | ||||||
| golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
|  | @ -216,39 +209,30 @@ golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7w | ||||||
| golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4= | ||||||
| golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= | ||||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
| golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | ||||||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
|  | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= | ||||||
| golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
| golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y= |  | ||||||
| golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= |  | ||||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||||
| golang.org/x/tools v0.0.0-20190608022120-eacb66d2a7c3/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | golang.org/x/tools v0.0.0-20190608022120-eacb66d2a7c3/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||||||
| golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |  | ||||||
| golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= |  | ||||||
| golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |  | ||||||
| golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |  | ||||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= |  | ||||||
| golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b h1:XDLXhn7ryprJVo+Lpkiib6CIuXE2031GDwtfEm7vLjI= | golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b h1:XDLXhn7ryprJVo+Lpkiib6CIuXE2031GDwtfEm7vLjI= | ||||||
| golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= | golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= | ||||||
| golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c h1:ADNrRDI5NR23/TUCnEmlLZLt4u9DnZ2nwRkPrAcFvto= | golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c h1:ADNrRDI5NR23/TUCnEmlLZLt4u9DnZ2nwRkPrAcFvto= | ||||||
| golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ= | golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ= | ||||||
| gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= |  | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= |  | ||||||
| gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= | gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= | ||||||
| gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= | gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= | ||||||
| gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= | gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= | ||||||
| gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
| gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
| gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= |  | ||||||
| gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
|  |  | ||||||
|  | @ -4,7 +4,6 @@ import ( | ||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"github.com/labstack/echo/v4" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"sort" | 	"sort" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | @ -13,6 +12,7 @@ import ( | ||||||
| 	rice "github.com/GeertJohan/go.rice" | 	rice "github.com/GeertJohan/go.rice" | ||||||
| 	"github.com/gorilla/sessions" | 	"github.com/gorilla/sessions" | ||||||
| 	"github.com/labstack/echo-contrib/session" | 	"github.com/labstack/echo-contrib/session" | ||||||
|  | 	"github.com/labstack/echo/v4" | ||||||
| 	"github.com/labstack/gommon/log" | 	"github.com/labstack/gommon/log" | ||||||
| 	"github.com/rs/xid" | 	"github.com/rs/xid" | ||||||
| 	"golang.zx2c4.com/wireguard/wgctrl" | 	"golang.zx2c4.com/wireguard/wgctrl" | ||||||
|  | @ -685,77 +685,3 @@ func ApplyServerConfig(db store.IStore, tmplBox *rice.Box) echo.HandlerFunc { | ||||||
| 		return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Applied server config successfully"}) | 		return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Applied server config successfully"}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func GetWakeOnLanHosts(db store.IStore) echo.HandlerFunc { |  | ||||||
| 	return func(c echo.Context) error { |  | ||||||
| 		var err error |  | ||||||
| 
 |  | ||||||
| 		hosts, err := db.GetWakeOnLanHosts() |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Errorf("WOL ERROR") |  | ||||||
| 			return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Host not found"}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		err = c.Render(http.StatusOK, "wake_on_lan_hosts.html", map[string]interface{}{ |  | ||||||
| 			"baseData": model.BaseData{Active: "wake_on_lan_hosts", CurrentUser: currentUser(c)}, |  | ||||||
| 			"hosts":    hosts, |  | ||||||
| 			"error":    "", |  | ||||||
| 		}) |  | ||||||
| 		if err != nil { |  | ||||||
| 
 |  | ||||||
| 			print(err.Error() + "\n") |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func SaveWakeOnLanHost(db store.IStore) echo.HandlerFunc { |  | ||||||
| 	return func(c echo.Context) error { |  | ||||||
| 		type WakeOnLanHostPayload struct { |  | ||||||
| 			Name          string `json:"name"` |  | ||||||
| 			MacAddress    string `json:"mac_address"` |  | ||||||
| 			OldMacAddress string `json:"old_mac_address"` |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		var payload WakeOnLanHostPayload |  | ||||||
| 		err := c.Bind(&payload) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Error("Wake On Host Bind Error: ", err) |  | ||||||
| 			return c.JSON(http.StatusInternalServerError, payload) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		host := model.WakeOnLanHost{ |  | ||||||
| 			MacAddress: payload.MacAddress, |  | ||||||
| 			Name:       payload.Name, |  | ||||||
| 		} |  | ||||||
| 		if len(payload.OldMacAddress) != 0 { |  | ||||||
| 			oldHost, err := db.GetWakeOnLanHost(payload.OldMacAddress) |  | ||||||
| 			if err != nil { |  | ||||||
| 				log.Error("Wake On Host Update Err: ", err) |  | ||||||
| 				return c.JSON(http.StatusInternalServerError, payload) |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			err = db.DeleteWakeOnHostLanHost(payload.OldMacAddress) |  | ||||||
| 			if err != nil { |  | ||||||
| 				log.Error("Wake On Host Update Err: ", err) |  | ||||||
| 				return c.JSON(http.StatusInternalServerError, payload) |  | ||||||
| 			} |  | ||||||
| 			host.LatestUsed = oldHost.LatestUsed |  | ||||||
| 			err = db.SaveWakeOnLanHost(host) |  | ||||||
| 		} else { |  | ||||||
| 			now := time.Now() |  | ||||||
| 			host.LatestUsed = &now |  | ||||||
| 			err = db.SaveWakeOnLanHost(host) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Error("Wake On Host Save Error: ", err) |  | ||||||
| 			return c.JSON(http.StatusInternalServerError, payload) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return c.JSON(http.StatusOK, host) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -0,0 +1,171 @@ | ||||||
|  | package handler | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"github.com/labstack/echo/v4" | ||||||
|  | 	"github.com/labstack/gommon/log" | ||||||
|  | 	"github.com/ngoduykhanh/wireguard-ui/model" | ||||||
|  | 	"github.com/ngoduykhanh/wireguard-ui/store" | ||||||
|  | 	"github.com/sabhiram/go-wol/wol" | ||||||
|  | 	"net" | ||||||
|  | 	"net/http" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type WakeOnLanHostSavePayload struct { | ||||||
|  | 	Name          string `json:"name"` | ||||||
|  | 	MacAddress    string `json:"mac_address"` | ||||||
|  | 	OldMacAddress string `json:"old_mac_address"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func createError(c echo.Context, err error, msg string) error { | ||||||
|  | 	log.Error(msg, err) | ||||||
|  | 	return c.JSON( | ||||||
|  | 		http.StatusInternalServerError, | ||||||
|  | 		jsonHTTPResponse{ | ||||||
|  | 			false, | ||||||
|  | 			msg}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func GetWakeOnLanHosts(db store.IStore) echo.HandlerFunc { | ||||||
|  | 	return func(c echo.Context) error { | ||||||
|  | 		var err error | ||||||
|  | 
 | ||||||
|  | 		hosts, err := db.GetWakeOnLanHosts() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return createError(c, err, fmt.Sprintf("wake_on_lan_hosts database error: %s", err)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		err = c.Render(http.StatusOK, "wake_on_lan_hosts.html", map[string]interface{}{ | ||||||
|  | 			"baseData": model.BaseData{Active: "wake_on_lan_hosts", CurrentUser: currentUser(c)}, | ||||||
|  | 			"hosts":    hosts, | ||||||
|  | 			"error":    "", | ||||||
|  | 		}) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return createError(c, err, fmt.Sprintf("wake_on_lan_hosts.html render error: %s", err)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func SaveWakeOnLanHost(db store.IStore) echo.HandlerFunc { | ||||||
|  | 	return func(c echo.Context) error { | ||||||
|  | 		var payload WakeOnLanHostSavePayload | ||||||
|  | 		err := c.Bind(&payload) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Error("Wake On Host Save Payload Bind Error: ", err) | ||||||
|  | 			return c.JSON(http.StatusInternalServerError, payload) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		var host = model.WakeOnLanHost{ | ||||||
|  | 			MacAddress: payload.MacAddress, | ||||||
|  | 			Name:       payload.Name, | ||||||
|  | 		} | ||||||
|  | 		if len(payload.OldMacAddress) != 0 { // Edit
 | ||||||
|  | 			if payload.OldMacAddress != payload.MacAddress { // modified mac address
 | ||||||
|  | 				oldHost, err := db.GetWakeOnLanHost(payload.OldMacAddress) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return createError(c, err, fmt.Sprintf("Wake On Host Update Err: %s", err)) | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if payload.OldMacAddress != payload.MacAddress { | ||||||
|  | 					existHost, _ := db.GetWakeOnLanHost(payload.MacAddress) | ||||||
|  | 					if existHost != nil { | ||||||
|  | 						return createError(c, nil, "Mac Address already exists.") | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				err = db.DeleteWakeOnHostLanHost(payload.OldMacAddress) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return createError(c, err, fmt.Sprintf("Wake On Host Update Err: %s", err)) | ||||||
|  | 				} | ||||||
|  | 				host.LatestUsed = oldHost.LatestUsed | ||||||
|  | 			} | ||||||
|  | 			err = db.SaveWakeOnLanHost(host) | ||||||
|  | 		} else { // new
 | ||||||
|  | 			existHost, _ := db.GetWakeOnLanHost(payload.MacAddress) | ||||||
|  | 			if existHost != nil { | ||||||
|  | 				return createError(c, nil, "Mac Address already exists.") | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			err = db.SaveWakeOnLanHost(host) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if err != nil { | ||||||
|  | 			return createError(c, err, fmt.Sprintf("Wake On Host Save Error: %s", err)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return c.JSON(http.StatusOK, host) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func DeleteWakeOnHost(db store.IStore) echo.HandlerFunc { | ||||||
|  | 	return func(c echo.Context) error { | ||||||
|  | 		var macAddress = c.Param("mac_address") | ||||||
|  | 		var host, err = db.GetWakeOnLanHost(macAddress) | ||||||
|  | 
 | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Error("Wake On Host Delete Error: ", err) | ||||||
|  | 			return createError(c, err, fmt.Sprintf("Wake On Host Delete Error: %s", macAddress)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		err = db.DeleteWakeOnHost(*host) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return createError(c, err, fmt.Sprintf("Wake On Host Delete Error: %s", macAddress)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return c.JSON(http.StatusOK, nil) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func WakeOnHost(db store.IStore) echo.HandlerFunc { | ||||||
|  | 	return func(c echo.Context) error { | ||||||
|  | 		macAddress := c.Param("mac_address") | ||||||
|  | 		host, err := db.GetWakeOnLanHost(macAddress) | ||||||
|  | 
 | ||||||
|  | 		now := time.Now() | ||||||
|  | 		host.LatestUsed = &now | ||||||
|  | 		err = db.SaveWakeOnLanHost(*host) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return createError(c, err, fmt.Sprintf("Latest Used Update Error: %s", macAddress)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		magicPacket, err := wol.New(macAddress) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return createError(c, err, fmt.Sprintf("Magic Packet Create Error: %s", macAddress)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		bytes, err := magicPacket.Marshal() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return createError(c, err, fmt.Sprintf("Magic Packet Bytestream Error: %s", macAddress)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		udpAddr, err := net.ResolveUDPAddr("udp", "255.255.255.255:0") | ||||||
|  | 		if err != nil { | ||||||
|  | 			return createError(c, err, fmt.Sprintf("ResolveUDPAddr Error: %s", macAddress)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Grab a UDP connection to send our packet of bytes.
 | ||||||
|  | 		conn, err := net.DialUDP("udp", nil, udpAddr) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		defer func(conn *net.UDPConn) { | ||||||
|  | 			err := conn.Close() | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Error(err) | ||||||
|  | 			} | ||||||
|  | 		}(conn) | ||||||
|  | 
 | ||||||
|  | 		n, err := conn.Write(bytes) | ||||||
|  | 		if err == nil && n != 102 { | ||||||
|  | 			return createError(c, nil, fmt.Sprintf("magic packet sent was %d bytes (expected 102 bytes sent)", n)) | ||||||
|  | 		} | ||||||
|  | 		if err != nil { | ||||||
|  | 			return createError(c, err, fmt.Sprintf("Network Send Error: %s", macAddress)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return c.JSON(http.StatusOK, nil) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								main.go
								
								
								
								
							
							
						
						
									
										2
									
								
								main.go
								
								
								
								
							|  | @ -148,6 +148,8 @@ func main() { | ||||||
| 	app.GET("/api/apply-wg-config", handler.ApplyServerConfig(db, tmplBox), handler.ValidSession) | 	app.GET("/api/apply-wg-config", handler.ApplyServerConfig(db, tmplBox), handler.ValidSession) | ||||||
| 	app.GET("/wake_on_lan_hosts", handler.GetWakeOnLanHosts(db), handler.ValidSession) | 	app.GET("/wake_on_lan_hosts", handler.GetWakeOnLanHosts(db), handler.ValidSession) | ||||||
| 	app.POST("/wake_on_lan_host", handler.SaveWakeOnLanHost(db), handler.ValidSession) | 	app.POST("/wake_on_lan_host", handler.SaveWakeOnLanHost(db), handler.ValidSession) | ||||||
|  | 	app.DELETE("/wake_on_lan_host/:mac_address", handler.DeleteWakeOnHost(db), handler.ValidSession) | ||||||
|  | 	app.PUT("/wake_on_lan_host/:mac_address", handler.WakeOnHost(db), handler.ValidSession) | ||||||
| 
 | 
 | ||||||
| 	// servers other static files
 | 	// servers other static files
 | ||||||
| 	app.GET("/static/*", echo.WrapHandler(http.StripPrefix("/static/", assetHandler))) | 	app.GET("/static/*", echo.WrapHandler(http.StripPrefix("/static/", assetHandler))) | ||||||
|  |  | ||||||
|  | @ -38,12 +38,10 @@ func New(dbPath string) (*JsonDB, error) { | ||||||
| func (o *JsonDB) Init() error { | func (o *JsonDB) Init() error { | ||||||
| 	var clientPath string = path.Join(o.dbPath, "clients") | 	var clientPath string = path.Join(o.dbPath, "clients") | ||||||
| 	var serverPath string = path.Join(o.dbPath, "server") | 	var serverPath string = path.Join(o.dbPath, "server") | ||||||
| 	var wakeOnLanListPath string = path.Join(o.dbPath, model.WakeOnLanHostCollectionName) |  | ||||||
| 	var serverInterfacePath string = path.Join(serverPath, "interfaces.json") | 	var serverInterfacePath string = path.Join(serverPath, "interfaces.json") | ||||||
| 	var serverKeyPairPath string = path.Join(serverPath, "keypair.json") | 	var serverKeyPairPath string = path.Join(serverPath, "keypair.json") | ||||||
| 	var globalSettingPath string = path.Join(serverPath, "global_settings.json") | 	var globalSettingPath string = path.Join(serverPath, "global_settings.json") | ||||||
| 	var userPath string = path.Join(serverPath, "users.json") | 	var userPath string = path.Join(serverPath, "users.json") | ||||||
| 
 |  | ||||||
| 	// create directories if they do not exist
 | 	// create directories if they do not exist
 | ||||||
| 	if _, err := os.Stat(clientPath); os.IsNotExist(err) { | 	if _, err := os.Stat(clientPath); os.IsNotExist(err) { | ||||||
| 		os.MkdirAll(clientPath, os.ModePerm) | 		os.MkdirAll(clientPath, os.ModePerm) | ||||||
|  | @ -101,10 +99,6 @@ func (o *JsonDB) Init() error { | ||||||
| 		o.conn.Write("server", "users", user) | 		o.conn.Write("server", "users", user) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if _, err := os.Stat(wakeOnLanListPath); os.IsNotExist(err) { |  | ||||||
| 		os.MkdirAll(wakeOnLanListPath, os.ModePerm) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -227,54 +221,3 @@ func (o *JsonDB) SaveServerKeyPair(serverKeyPair model.ServerKeypair) error { | ||||||
| func (o *JsonDB) SaveGlobalSettings(globalSettings model.GlobalSetting) error { | func (o *JsonDB) SaveGlobalSettings(globalSettings model.GlobalSetting) error { | ||||||
| 	return o.conn.Write("server", "global_settings", globalSettings) | 	return o.conn.Write("server", "global_settings", globalSettings) | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func (o *JsonDB) GetWakeOnLanHosts() ([]model.WakeOnLanHost, error) { |  | ||||||
| 	var hosts []model.WakeOnLanHost |  | ||||||
| 
 |  | ||||||
| 	// read all client json file in "hosts" directory
 |  | ||||||
| 	records, err := o.conn.ReadAll(model.WakeOnLanHostCollectionName) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return hosts, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// build the ClientData list
 |  | ||||||
| 	for _, f := range records { |  | ||||||
| 		host := model.WakeOnLanHost{} |  | ||||||
| 
 |  | ||||||
| 		// get client info
 |  | ||||||
| 		if err := json.Unmarshal([]byte(f), &host); err != nil { |  | ||||||
| 			return hosts, fmt.Errorf("cannot decode client json structure: %v", err) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// create the list of hosts and their qrcode data
 |  | ||||||
| 		hosts = append(hosts, host) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return hosts, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (o *JsonDB) GetWakeOnLanHost(macAddress string) (*model.WakeOnLanHost, error) { |  | ||||||
| 	host := &model.WakeOnLanHost{ |  | ||||||
| 		MacAddress: macAddress, |  | ||||||
| 	} |  | ||||||
| 	resourceName, err := host.ResolveResourceName() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err = o.conn.Read(model.WakeOnLanHostCollectionName, resourceName, host) |  | ||||||
| 	return host, err |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (o *JsonDB) DeleteWakeOnHostLanHost(macAddress string) error { |  | ||||||
| 	return o.conn.Delete(model.WakeOnLanHostCollectionName, macAddress) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (o *JsonDB) SaveWakeOnLanHost(host model.WakeOnLanHost) error { |  | ||||||
| 	resourceName, err := host.ResolveResourceName() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return o.conn.Write(model.WakeOnLanHostCollectionName, resourceName, host) |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -0,0 +1,78 @@ | ||||||
|  | package jsondb | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
|  | 	"github.com/ngoduykhanh/wireguard-ui/model" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func (o *JsonDB) GetWakeOnLanHosts() ([]model.WakeOnLanHost, error) { | ||||||
|  | 	var hosts []model.WakeOnLanHost | ||||||
|  | 
 | ||||||
|  | 	// read all client json file in "hosts" directory
 | ||||||
|  | 	records, err := o.conn.ReadAll(model.WakeOnLanHostCollectionName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return hosts, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// build the ClientData list
 | ||||||
|  | 	for _, f := range records { | ||||||
|  | 		host := model.WakeOnLanHost{} | ||||||
|  | 
 | ||||||
|  | 		// get client info
 | ||||||
|  | 		if err := json.Unmarshal([]byte(f), &host); err != nil { | ||||||
|  | 			return hosts, fmt.Errorf("cannot decode client json structure: %v", err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// create the list of hosts and their qrcode data
 | ||||||
|  | 		hosts = append(hosts, host) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return hosts, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (o *JsonDB) GetWakeOnLanHost(macAddress string) (*model.WakeOnLanHost, error) { | ||||||
|  | 	host := &model.WakeOnLanHost{ | ||||||
|  | 		MacAddress: macAddress, | ||||||
|  | 	} | ||||||
|  | 	resourceName, err := host.ResolveResourceName() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = o.conn.Read(model.WakeOnLanHostCollectionName, resourceName, host) | ||||||
|  | 	if err != nil { | ||||||
|  | 		host = nil | ||||||
|  | 	} | ||||||
|  | 	return host, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (o *JsonDB) DeleteWakeOnHostLanHost(macAddress string) error { | ||||||
|  | 	host := &model.WakeOnLanHost{ | ||||||
|  | 		MacAddress: macAddress, | ||||||
|  | 	} | ||||||
|  | 	resourceName, err := host.ResolveResourceName() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return o.conn.Delete(model.WakeOnLanHostCollectionName, resourceName) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (o *JsonDB) SaveWakeOnLanHost(host model.WakeOnLanHost) error { | ||||||
|  | 	resourceName, err := host.ResolveResourceName() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return o.conn.Write(model.WakeOnLanHostCollectionName, resourceName, host) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (o *JsonDB) DeleteWakeOnHost(host model.WakeOnLanHost) error { | ||||||
|  | 	resourceName, err := host.ResolveResourceName() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return o.conn.Delete(model.WakeOnLanHostCollectionName, resourceName) | ||||||
|  | } | ||||||
|  | @ -20,4 +20,5 @@ type IStore interface { | ||||||
| 	GetWakeOnLanHost(macAddress string) (*model.WakeOnLanHost, error) | 	GetWakeOnLanHost(macAddress string) (*model.WakeOnLanHost, error) | ||||||
| 	DeleteWakeOnHostLanHost(macAddress string) error | 	DeleteWakeOnHostLanHost(macAddress string) error | ||||||
| 	SaveWakeOnLanHost(host model.WakeOnLanHost) error | 	SaveWakeOnLanHost(host model.WakeOnLanHost) error | ||||||
|  | 	DeleteWakeOnHost(host model.WakeOnLanHost) error | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,24 +1,24 @@ | ||||||
| {{define "title"}} | {{define "title"}} | ||||||
| Wake On Lan Hosts |     Wake On Lan Hosts | ||||||
| {{end}} | {{end}} | ||||||
| 
 | 
 | ||||||
| {{define "top_css"}} | {{define "top_css"}} | ||||||
| {{end}} | {{end}} | ||||||
| 
 | 
 | ||||||
| {{define "username"}} | {{define "username"}} | ||||||
| {{ .username }} |     {{ .username }} | ||||||
| {{end}} | {{end}} | ||||||
| 
 | 
 | ||||||
| {{define "page_title"}} | {{define "page_title"}} | ||||||
| Wake On Lan Hosts |     Wake On Lan Hosts | ||||||
| {{end}} | {{end}} | ||||||
| 
 | 
 | ||||||
| {{define "page_content"}} | {{define "page_content"}} | ||||||
| 
 | 
 | ||||||
| <div class="modal fade" id="modal_wake_on_lan_host"> |     <div class="modal fade" id="modal_wake_on_lan_host"> | ||||||
| <!--    MacAddress      string `json:"MacAddress"`--> |         <!--    MacAddress      string `json:"MacAddress"`--> | ||||||
| <!--    Name            string `json:"Name"`--> |         <!--    Name            string `json:"Name"`--> | ||||||
| <!--    LatestIPAddress string `json:"LatestIPAddress"`--> |         <!--    LatestIPAddress string `json:"LatestIPAddress"`--> | ||||||
|         <div class="modal-dialog"> |         <div class="modal-dialog"> | ||||||
|             <div class="modal-content"> |             <div class="modal-content"> | ||||||
|                 <div class="modal-header"> |                 <div class="modal-header"> | ||||||
|  | @ -36,7 +36,8 @@ Wake On Lan Hosts | ||||||
|                         </div> |                         </div> | ||||||
|                         <div class="form-group"> |                         <div class="form-group"> | ||||||
|                             <label for="frm_wake_on_lan_host_mac_address" class="control-label">Mac Address</label> |                             <label for="frm_wake_on_lan_host_mac_address" class="control-label">Mac Address</label> | ||||||
|                         <input type="text" class="form-control" id="frm_wake_on_lan_host_mac_address" name="mac_address"> |                             <input type="text" class="form-control" id="frm_wake_on_lan_host_mac_address" | ||||||
|  |                                    name="mac_address"> | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div class="modal-footer justify-content-between"> |                     <div class="modal-footer justify-content-between"> | ||||||
|  | @ -47,9 +48,30 @@ Wake On Lan Hosts | ||||||
|             </div> |             </div> | ||||||
|             <!-- /.modal-content --> |             <!-- /.modal-content --> | ||||||
|         </div> |         </div> | ||||||
| </div> |     </div> | ||||||
| 
 | 
 | ||||||
| <section class="content"> |     <div class="modal fade" id="modal_remove_wake_on_lan_host"> | ||||||
|  |         <div class="modal-dialog"> | ||||||
|  |             <div class="modal-content bg-danger"> | ||||||
|  |                 <div class="modal-header"> | ||||||
|  |                     <h4 class="modal-title">Remove</h4> | ||||||
|  |                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||||||
|  |                         <span aria-hidden="true">×</span> | ||||||
|  |                     </button> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-body"> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-footer justify-content-between"> | ||||||
|  |                     <button type="button" class="btn btn-outline-dark" data-dismiss="modal">Cancel</button> | ||||||
|  |                     <button type="button" class="btn btn-outline-dark" id="remove_wake_on_host_confirm">Apply</button> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |             <!-- /.modal-content --> | ||||||
|  |         </div> | ||||||
|  |         <!-- /.modal-dialog --> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <section class="content"> | ||||||
|         <div class="container-fluid"> |         <div class="container-fluid"> | ||||||
|             {{ if .error }} |             {{ if .error }} | ||||||
|                 <div class="alert alert-warning" role="alert">{{.error}}</div> |                 <div class="alert alert-warning" role="alert">{{.error}}</div> | ||||||
|  | @ -58,114 +80,44 @@ Wake On Lan Hosts | ||||||
|             <div class="row"> |             <div class="row"> | ||||||
|                 {{ range $idx, $host := .hosts }} |                 {{ range $idx, $host := .hosts }} | ||||||
|                     {{- /*gotype: github.com/ngoduykhanh/wireguard-ui/model.WakeOnLanHost*/ -}} |                     {{- /*gotype: github.com/ngoduykhanh/wireguard-ui/model.WakeOnLanHost*/ -}} | ||||||
|             <div class="col-sm-4" id="{{.MacAddress}}"> |                     <div class="col-sm-4" id="{{ $host.ResolveResourceName }}"> | ||||||
|                         <div class="info-box"> |                         <div class="info-box"> | ||||||
|                             <div class="info-box-content"> |                             <div class="info-box-content"> | ||||||
|                                 <div class="btn-group"> |                                 <div class="btn-group"> | ||||||
|                             <button type="button" class="btn btn-outline-success btn-sm" data-mac-address="{{ .MacAddress }}">Wake On</button> |                                     <button type="button" class="btn btn-outline-success btn-sm" | ||||||
|                             <button type="button" class="btn btn-outline-primary btn-sm btn_modify_wake_on_lan_host" data-toggle="modal" data-target="#modal_wake_on_lan_host" data-name="{{ .Name }}" data-mac-address="{{ .MacAddress }}">Edit</button> |                                             data-mac-address="{{ .MacAddress }}">Wake On | ||||||
|                             <button type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal" data-target="#modal_remove_wake_on_lan_host" data-mac-address="{{ .MacAddress }}">Remove</button> |                                     </button> | ||||||
|  |                                     <button type="button" | ||||||
|  |                                             class="btn btn-outline-primary btn-sm btn_modify_wake_on_lan_host" | ||||||
|  |                                             data-toggle="modal" data-target="#modal_wake_on_lan_host" | ||||||
|  |                                             data-name="{{ .Name }}" data-mac-address="{{ .MacAddress }}">Edit | ||||||
|  |                                     </button> | ||||||
|  |                                     <button type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal" | ||||||
|  |                                             data-target="#modal_remove_wake_on_lan_host" | ||||||
|  |                                             data-mac-address="{{ .MacAddress }}">Remove | ||||||
|  |                                     </button> | ||||||
|                                 </div> |                                 </div> | ||||||
|                                 <hr> |                                 <hr> | ||||||
|                         <span class="info-box-text"><i class="fas fa-address-card"></i> {{ .Name }}</span> |                                 <span class="info-box-text"><i class="fas fa-address-card"></i> <span class="name">{{ .Name }}</span></span> | ||||||
|                         <span class="info-box-text"><i class="fas fa-ethernet"></i> {{ .MacAddress }}</span> |                                 <span class="info-box-text"><i class="fas fa-ethernet"></i> <span class="mac-address">{{ .MacAddress }}</span></span> | ||||||
|                         <span class="info-box-text"><i class="fas fa-ethernet"></i> |                                 <span class="info-box-text"><i class="fas fa-clock"></i> | ||||||
|  |                                     <span class="latest-used"> | ||||||
|                                         {{ if .LatestUsed }} |                                         {{ if .LatestUsed }} | ||||||
|                                             {{ .LatestUsed }} |                                             {{ .LatestUsed }} | ||||||
|                                         {{ else }} |                                         {{ else }} | ||||||
|                                             Unused |                                             Unused | ||||||
|                                         {{ end }} |                                         {{ end }} | ||||||
|                                     </span> |                                     </span> | ||||||
|  |                                 </span> | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                 {{ end }} |                 {{ end }} | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
| </section> |     </section> | ||||||
| 
 | 
 | ||||||
| {{end}} | {{end}} | ||||||
| {{define "bottom_js"}} | {{define "bottom_js"}} | ||||||
|     <script> |     <script src="/static/custom/js/wake_on_lan_hosts.js"></script> | ||||||
|         jQuery(function ($) { |  | ||||||
|             let newHostHtml = '<div class="col-sm-2 offset-md-4" style=" text-align: right;"><button style="" id="btn_new_wake_on_lan_host" type="button" class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#modal_wake_on_lan_host"><i class="nav-icon fas fa-plus"></i> New Host</button></div>'; |  | ||||||
|             $('h1').parents(".row").append(newHostHtml); |  | ||||||
| 
 |  | ||||||
|             // https://jqueryvalidation.org/ |  | ||||||
|             let $modal = $("#modal_wake_on_lan_host"); |  | ||||||
|             let $name = $('#frm_wake_on_lan_host_name'); |  | ||||||
|             let $macAddress = $('#frm_wake_on_lan_host_mac_address'); |  | ||||||
|             let $oldMacAddress = $('#frm_wake_on_lan_host_old_mac_address'); |  | ||||||
| 
 |  | ||||||
|             $('#btn_new_wake_on_lan_host').click(function() { |  | ||||||
|                 alert(1); |  | ||||||
|                 // FIXME modal 초기화 |  | ||||||
|             }); |  | ||||||
|             $('.btn_modify_wake_on_lan_host').each(function () { |  | ||||||
|                 let $btn = $(this); |  | ||||||
|                 $btn.click(function () { |  | ||||||
|                    console.log($btn.data('mac-address'), $btn.data('name')); |  | ||||||
|                     // FIXME MODAL Data데이터삽입 |  | ||||||
|                 }); |  | ||||||
|             }); |  | ||||||
|             $modal.on('shown.bs.modal', function (e) {}); |  | ||||||
| 
 |  | ||||||
|             $("#frm_wake_on_lan_host").validate({ |  | ||||||
|                 submitHandler: function() { |  | ||||||
|                     let data = { |  | ||||||
|                         name: $name.val(), |  | ||||||
|                         mac_address: $macAddress.val(), |  | ||||||
|                         old_mac_address: $oldMacAddress.val() |  | ||||||
|                     }; |  | ||||||
|                     $.ajax({ |  | ||||||
|                         cache: false, |  | ||||||
|                         method: 'POST', |  | ||||||
|                         url: '/wake_on_lan_host', |  | ||||||
|                         dataType: 'json', |  | ||||||
|                         contentType: "application/json", |  | ||||||
|                         data: JSON.stringify(data), |  | ||||||
|                         success: function(response) { |  | ||||||
|                             // FIXME 화면에 동적으로 추가 하는 코드 추가 |  | ||||||
|                             $modal.modal('hide'); |  | ||||||
|                             toastr.success('Wake on Lan Host Save successfully'); |  | ||||||
|                         }, |  | ||||||
|                         error: function(jqXHR, exception) { |  | ||||||
|                             const responseJson = jQuery.parseJSON(jqXHR.responseText); |  | ||||||
|                             toastr.error(responseJson['message']); |  | ||||||
|                         } |  | ||||||
|                     }); |  | ||||||
| 
 |  | ||||||
|                     return false; |  | ||||||
|                 }, |  | ||||||
|                 rules: { |  | ||||||
|                     name: { |  | ||||||
|                         required: true, |  | ||||||
|                     }, |  | ||||||
|                     mac_address: { |  | ||||||
|                         required: true, |  | ||||||
|                     } |  | ||||||
|                 }, |  | ||||||
|                 messages: { |  | ||||||
|                     name: { |  | ||||||
|                         required: "Please enter a name" |  | ||||||
|                     }, |  | ||||||
|                     mac_address: { |  | ||||||
|                         required: "Please enter a Mac Address" |  | ||||||
|                     } |  | ||||||
|                 }, |  | ||||||
|                 errorElement: 'span', |  | ||||||
|                 errorPlacement: function (error, element) { |  | ||||||
|                     error.addClass('invalid-feedback'); |  | ||||||
|                     element.closest('.form-group').append(error); |  | ||||||
|                 }, |  | ||||||
|                 highlight: function (element, errorClass, validClass) { |  | ||||||
|                     $(element).addClass('is-invalid'); |  | ||||||
|                 }, |  | ||||||
|                 unhighlight: function (element, errorClass, validClass) { |  | ||||||
|                     $(element).removeClass('is-invalid'); |  | ||||||
|                 } |  | ||||||
|             }); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     </script> |  | ||||||
| {{end}} | {{end}} | ||||||
		Loading…
	
		Reference in New Issue