diff --git a/go.mod b/go.mod index 3d89376..0c7573f 100644 --- a/go.mod +++ b/go.mod @@ -22,14 +22,16 @@ require ( golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 golang.org/x/mod v0.5.1 // indirect golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 - golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac + golang.org/x/tools v0.1.8 // indirect gopkg.in/ini.v1 v1.64.0 // indirect gopkg.in/irc.v3 v3.1.4 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.4.0 - modernc.org/ccgo/v3 v3.12.73 // indirect - modernc.org/sqlite v1.14.1 + modernc.org/ccgo/v3 v3.14.0 // indirect + modernc.org/libc v1.13.2 // indirect + modernc.org/sqlite v1.14.3 ) diff --git a/go.sum b/go.sum index 2c87862..a4ae3ea 100644 --- a/go.sum +++ b/go.sum @@ -876,6 +876,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -1033,6 +1034,7 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 h1:0qxwC5n+ttVOINCBeRHO0nq9X7uy8SDsPoi5OaCdIEI= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1158,9 +1160,12 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211023085530-d6a326fbbf70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/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-20211216021012-1d35b9e2eb4e/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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -1251,6 +1256,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= 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= @@ -1463,6 +1470,9 @@ modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= modernc.org/cc/v3 v3.35.18 h1:rMZhRcWrba0y3nVmdiQ7kxAgOOSq2m2f2VzjHLgEs6U= modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.20/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.22 h1:BzShpwCAP7TWzFppM4k2t03RhXhgYqaibROWkrWq7lE= +modernc.org/cc/v3 v3.35.22/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60= modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw= modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI= @@ -1497,6 +1507,17 @@ modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/E modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84= modernc.org/ccgo/v3 v3.12.73 h1:AMk4wEpzWjpODXohKvvnlwLob4Xk8tq3we6CwYh88mA= modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ= +modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY= +modernc.org/ccgo/v3 v3.12.84/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w= +modernc.org/ccgo/v3 v3.12.86/go.mod h1:dN7S26DLTgVSni1PVA3KxxHTcykyDurf3OgUzNqTSrU= +modernc.org/ccgo/v3 v3.12.88/go.mod h1:0MFzUHIuSIthpVZyMWiFYMwjiFnhrN5MkvBrUwON+ZM= +modernc.org/ccgo/v3 v3.12.90/go.mod h1:obhSc3CdivCRpYZmrvO88TXlW0NvoSVvdh/ccRjJYko= +modernc.org/ccgo/v3 v3.12.92/go.mod h1:5yDdN7ti9KWPi5bRVWPl8UNhpEAtCjuEE7ayQnzzqHA= +modernc.org/ccgo/v3 v3.12.95/go.mod h1:ZcLyvtocXYi8uF+9Ebm3G8EF8HNY5hGomBqthDp4eC8= +modernc.org/ccgo/v3 v3.13.1/go.mod h1:aBYVOUfIlcSnrsRVU8VRS35y2DIfpgkmVkYZ0tpIXi4= +modernc.org/ccgo/v3 v3.14.0 h1:Zr1Ny9+7r5yAiXpBdgp8XiXqkNA4ARrRphHGHVXeAp0= +modernc.org/ccgo/v3 v3.14.0/go.mod h1:hBrkiBlUwvr5vV/ZH9YzXIp982jKE8Ek8tR1ytoAL6Q= +modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= @@ -1533,6 +1554,18 @@ modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw= modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0= modernc.org/libc v1.11.82 h1:CSl/6n4odvPYWKKqBtFb8e0ZWVTjxDqwxTjaoee9V7E= modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI= +modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE= +modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY= +modernc.org/libc v1.11.88/go.mod h1:h3oIVe8dxmTcchcFuCcJ4nAWaoiwzKCdv82MM0oiIdQ= +modernc.org/libc v1.11.90/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c= +modernc.org/libc v1.11.98/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c= +modernc.org/libc v1.11.99/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI= +modernc.org/libc v1.11.101/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI= +modernc.org/libc v1.11.104/go.mod h1:2MH3DaF/gCU8i/UBiVE1VFRos4o523M7zipmwH8SIgQ= +modernc.org/libc v1.12.0/go.mod h1:2MH3DaF/gCU8i/UBiVE1VFRos4o523M7zipmwH8SIgQ= +modernc.org/libc v1.13.1/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk= +modernc.org/libc v1.13.2 h1:GCFjY9bmwDZ/TJC4OZOUWaNgxIxwb104C/QZrqpcVEA= +modernc.org/libc v1.13.2/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk= modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= @@ -1545,14 +1578,20 @@ modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.14.1 h1:jthfQCbWKfbK/lvZSjFEpBk0QzIBN6pQbFdDqBMR490= modernc.org/sqlite v1.14.1/go.mod h1:04Lqa+3PuAEUhAPAPWeDMljT4UYA31nb2DHTFG47L1g= +modernc.org/sqlite v1.14.3 h1:psrTwgpEujgWEP3FNdsC9yNh5tSeA77U0GeWhHH4XmQ= +modernc.org/sqlite v1.14.3/go.mod h1:xMpicS1i2MJ4C8+Ap0vYBqTwYfpFvdnPE6brbFOtV2Y= modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/tcl v1.8.13 h1:V0sTNBw0Re86PvXZxuCub3oO9WrSTqALgrwNZNvLFGw= modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY= +modernc.org/tcl v1.9.2 h1:YA87dFLOsR2KqMka371a2Xgr+YsyUwo7OmHVSv/kztw= +modernc.org/tcl v1.9.2/go.mod h1:aw7OnlIoiuJgu1gwbTZtrKnGpDqH9wyH++jZcxdqNsg= modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.2.19 h1:BGyRFWhDVn5LFS5OcX4Yd/MlpRTOc7hOPTdcIpCiUao= modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY= +modernc.org/z v1.2.20 h1:DyboxM1sJR2NB803j2StnbnL6jcQXz273OhHDGu8dGk= +modernc.org/z v1.2.20/go.mod h1:zU9FiF4PbHdOTUxw+IF8j7ArBMRPsHgq10uVPt6xTzo= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/action/run.go b/internal/action/run.go index 77524eb..7686a52 100644 --- a/internal/action/run.go +++ b/internal/action/run.go @@ -4,6 +4,7 @@ import ( "io" "os" "path" + "time" "github.com/rs/zerolog/log" @@ -24,10 +25,20 @@ func (s *service) RunActions(actions []domain.Action, release domain.Release) er log.Debug().Msgf("process action: %v for '%v'", action.Name, release.TorrentName) + actionStatus := domain.ReleaseActionStatus{ + ReleaseID: release.ID, + Status: domain.ReleasePushStatusPending, + Action: action.Name, + Type: action.Type, + Rejections: []string{}, + Timestamp: time.Now(), + } + + s.bus.Publish("release:store-action-status", &actionStatus) + switch action.Type { case domain.ActionTypeTest: s.test(action.Name) - s.bus.Publish("release:update-push-status", release.ID, domain.ReleasePushStatusApproved) case domain.ActionTypeExec: if release.TorrentTmpFile == "" { @@ -42,7 +53,6 @@ func (s *service) RunActions(actions []domain.Action, release domain.Release) er go func(release domain.Release, action domain.Action, tmpFile string) { s.execCmd(release, action, tmpFile) - s.bus.Publish("release:update-push-status", release.ID, domain.ReleasePushStatusApproved) }(release, action, tmpFile) case domain.ActionTypeWatchFolder: @@ -56,7 +66,6 @@ func (s *service) RunActions(actions []domain.Action, release domain.Release) er tmpFile = t.TmpFileName } s.watchFolder(action.WatchFolder, tmpFile) - s.bus.Publish("release:update-push-status", release.ID, domain.ReleasePushStatusApproved) case domain.ActionTypeDelugeV1, domain.ActionTypeDelugeV2: canDownload, err := s.delugeCheckRulesCanDownload(action) @@ -65,7 +74,14 @@ func (s *service) RunActions(actions []domain.Action, release domain.Release) er continue } if !canDownload { - s.bus.Publish("release:update-push-status-rejected", release.ID, "deluge busy") + s.bus.Publish("release:store-action-status", &domain.ReleaseActionStatus{ + ID: actionStatus.ID, + ReleaseID: release.ID, + Status: domain.ReleasePushStatusRejected, + Action: action.Name, + Type: action.Type, + Rejections: []string{"deluge busy"}, + }) continue } if release.TorrentTmpFile == "" { @@ -83,7 +99,6 @@ func (s *service) RunActions(actions []domain.Action, release domain.Release) er if err != nil { log.Error().Stack().Err(err).Msg("error sending torrent to Deluge") } - s.bus.Publish("release:update-push-status", release.ID, domain.ReleasePushStatusApproved) }(action, tmpFile) case domain.ActionTypeQbittorrent: @@ -93,7 +108,14 @@ func (s *service) RunActions(actions []domain.Action, release domain.Release) er continue } if !canDownload { - s.bus.Publish("release:update-push-status-rejected", release.ID, "qbittorrent busy") + s.bus.Publish("release:store-action-status", &domain.ReleaseActionStatus{ + ID: actionStatus.ID, + ReleaseID: release.ID, + Status: domain.ReleasePushStatusRejected, + Action: action.Name, + Type: action.Type, + Rejections: []string{"qbittorrent busy"}, + }) continue } @@ -113,7 +135,6 @@ func (s *service) RunActions(actions []domain.Action, release domain.Release) er if err != nil { log.Error().Stack().Err(err).Msg("error sending torrent to qBittorrent") } - s.bus.Publish("release:update-push-status", release.ID, domain.ReleasePushStatusApproved) }(action, hash, tmpFile) case domain.ActionTypeRadarr: @@ -146,6 +167,15 @@ func (s *service) RunActions(actions []domain.Action, release domain.Release) er default: log.Warn().Msgf("unsupported action: %v type: %v", action.Name, action.Type) } + + s.bus.Publish("release:store-action-status", &domain.ReleaseActionStatus{ + ID: actionStatus.ID, + ReleaseID: release.ID, + Status: domain.ReleasePushStatusApproved, + Action: action.Name, + Type: action.Type, + Rejections: []string{}, + }) } // safe to delete tmp file diff --git a/internal/database/filter.go b/internal/database/filter.go index 6545577..ba922f3 100644 --- a/internal/database/filter.go +++ b/internal/database/filter.go @@ -183,7 +183,8 @@ func (r *FilterRepo) FindByIndexerIdentifier(indexer string) ([]domain.Filter, e WHERE i.identifier = ? AND f.enabled = true`, indexer) if err != nil { - log.Fatal().Err(err) + log.Error().Stack().Err(err).Msg("error querying filter row") + return nil, err } defer rows.Close() @@ -199,8 +200,6 @@ func (r *FilterRepo) FindByIndexerIdentifier(indexer string) ([]domain.Filter, e if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &minSize, &maxSize, &delay, &matchReleases, &exceptReleases, &useRegex, &matchReleaseGroups, &exceptReleaseGroups, &scene, &freeleech, &freeleechPercent, &shows, &seasons, &episodes, pq.Array(&f.Resolutions), pq.Array(&f.Codecs), pq.Array(&f.Sources), pq.Array(&f.Containers), &years, &matchCategories, &exceptCategories, &matchUploaders, &exceptUploaders, &tags, &exceptTags, &createdAt, &updatedAt); err != nil { log.Error().Stack().Err(err).Msg("error scanning data to struct") - } - if err != nil { return nil, err } diff --git a/internal/database/migrate.go b/internal/database/migrate.go index 381fabf..92e1a7a 100644 --- a/internal/database/migrate.go +++ b/internal/database/migrate.go @@ -143,7 +143,6 @@ CREATE TABLE "release" ( id INTEGER PRIMARY KEY, filter_status TEXT, - push_status TEXT, rejections TEXT [] DEFAULT '{}' NOT NULL, indexer TEXT, filter TEXT, @@ -190,6 +189,20 @@ CREATE TABLE "release" uploader TEXT, pre_time TEXT ); + +CREATE TABLE release_action_status +( + id INTEGER PRIMARY KEY, + status TEXT, + action TEXT NOT NULL, + type TEXT NOT NULL, + rejections TEXT [] DEFAULT '{}' NOT NULL, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + raw TEXT, + log TEXT, + release_id INTEGER NOT NULL, + FOREIGN KEY (release_id) REFERENCES "release"(id) +); ` var migrations = []string{ @@ -247,6 +260,27 @@ var migrations = []string{ pre_time TEXT ); `, + ` + CREATE TABLE release_action_status + ( + id INTEGER PRIMARY KEY, + status TEXT, + action TEXT NOT NULL, + type TEXT NOT NULL, + rejections TEXT [] DEFAULT '{}' NOT NULL, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + raw TEXT, + log TEXT, + release_id INTEGER NOT NULL, + FOREIGN KEY (release_id) REFERENCES "release"(id) + ); + + INSERT INTO "release_action_status" (status, action, type, timestamp, release_id) + SELECT push_status, 'DEFAULT', 'QBITTORRENT', timestamp, id FROM "release"; + + ALTER TABLE "release" + DROP COLUMN push_status; + `, } func Migrate(db *sql.DB) error { diff --git a/internal/database/release.go b/internal/database/release.go index fd77d39..9f01e97 100644 --- a/internal/database/release.go +++ b/internal/database/release.go @@ -23,8 +23,8 @@ func NewReleaseRepo(db *sql.DB) domain.ReleaseRepo { func (repo *ReleaseRepo) Store(ctx context.Context, r *domain.Release) (*domain.Release, error) { query, args, err := sq. Insert("release"). - Columns("filter_status", "push_status", "rejections", "indexer", "filter", "protocol", "implementation", "timestamp", "group_id", "torrent_id", "torrent_name", "size", "raw", "title", "category", "season", "episode", "year", "resolution", "source", "codec", "container", "hdr", "audio", "release_group", "region", "language", "edition", "unrated", "hybrid", "proper", "repack", "website", "artists", "type", "format", "bitrate", "log_score", "has_log", "has_cue", "is_scene", "origin", "tags", "freeleech", "freeleech_percent", "uploader", "pre_time"). - Values(r.FilterStatus, r.PushStatus, pq.Array(r.Rejections), r.Indexer, r.FilterName, r.Protocol, r.Implementation, r.Timestamp, r.GroupID, r.TorrentID, r.TorrentName, r.Size, r.Raw, r.Title, r.Category, r.Season, r.Episode, r.Year, r.Resolution, r.Source, r.Codec, r.Container, r.HDR, r.Audio, r.Group, r.Region, r.Language, r.Edition, r.Unrated, r.Hybrid, r.Proper, r.Repack, r.Website, pq.Array(r.Artists), r.Type, r.Format, r.Bitrate, r.LogScore, r.HasLog, r.HasCue, r.IsScene, r.Origin, pq.Array(r.Tags), r.Freeleech, r.FreeleechPercent, r.Uploader, r.PreTime). + Columns("filter_status", "rejections", "indexer", "filter", "protocol", "implementation", "timestamp", "group_id", "torrent_id", "torrent_name", "size", "raw", "title", "category", "season", "episode", "year", "resolution", "source", "codec", "container", "hdr", "audio", "release_group", "region", "language", "edition", "unrated", "hybrid", "proper", "repack", "website", "artists", "type", "format", "bitrate", "log_score", "has_log", "has_cue", "is_scene", "origin", "tags", "freeleech", "freeleech_percent", "uploader", "pre_time"). + Values(r.FilterStatus, pq.Array(r.Rejections), r.Indexer, r.FilterName, r.Protocol, r.Implementation, r.Timestamp, r.GroupID, r.TorrentID, r.TorrentName, r.Size, r.Raw, r.Title, r.Category, r.Season, r.Episode, r.Year, r.Resolution, r.Source, r.Codec, r.Container, r.HDR, r.Audio, r.Group, r.Region, r.Language, r.Edition, r.Unrated, r.Hybrid, r.Proper, r.Repack, r.Website, pq.Array(r.Artists), r.Type, r.Format, r.Bitrate, r.LogScore, r.HasLog, r.HasCue, r.IsScene, r.Origin, pq.Array(r.Tags), r.Freeleech, r.FreeleechPercent, r.Uploader, r.PreTime). ToSql() res, err := repo.db.ExecContext(ctx, query, args...) @@ -41,37 +41,42 @@ func (repo *ReleaseRepo) Store(ctx context.Context, r *domain.Release) (*domain. return r, nil } -func (repo *ReleaseRepo) UpdatePushStatus(ctx context.Context, id int64, status domain.ReleasePushStatus) error { - query, args, err := sq.Update("release").Set("push_status", status).Where("id = ?", id).ToSql() +func (repo *ReleaseRepo) StoreReleaseActionStatus(ctx context.Context, a *domain.ReleaseActionStatus) error { - _, err = repo.db.ExecContext(ctx, query, args...) - if err != nil { - log.Error().Stack().Err(err).Msg("error updating status of release") - return err + if a.ID != 0 { + query, args, err := sq. + Update("release_action_status"). + Set("status", a.Status). + Set("rejections", pq.Array(a.Rejections)). + Set("timestamp", time.Now().Format(time.RFC3339)). + Where("id = ?", a.ID). + Where("release_id = ?", a.ReleaseID). + ToSql() + + _, err = repo.db.ExecContext(ctx, query, args...) + if err != nil { + log.Error().Stack().Err(err).Msg("error updating status of release") + return err + } + + } else { + query, args, err := sq. + Insert("release_action_status"). + Columns("status", "action", "type", "rejections", "timestamp", "release_id"). + Values(a.Status, a.Action, a.Type, pq.Array(a.Rejections), a.Timestamp, a.ReleaseID). + ToSql() + + res, err := repo.db.ExecContext(ctx, query, args...) + if err != nil { + log.Error().Stack().Err(err).Msg("error inserting status of release") + return err + } + + resId, _ := res.LastInsertId() + a.ID = resId } - log.Trace().Msgf("release.update_push_status: id %+v", id) - - return nil -} - -func (repo *ReleaseRepo) UpdatePushStatusRejected(ctx context.Context, id int64, rejections string) error { - r := []string{rejections} - - query, args, err := sq. - Update("release"). - Set("push_status", domain.ReleasePushStatusRejected). - Set("rejections", pq.Array(r)). - Where("id = ?", id). - ToSql() - - _, err = repo.db.ExecContext(ctx, query, args...) - if err != nil { - log.Error().Stack().Err(err).Msg("error updating status of release") - return err - } - - log.Trace().Msgf("release.update_push_status_rejected: id %+v", id) + log.Trace().Msgf("release.store_release_action_status: %+v", a) return nil } @@ -79,7 +84,7 @@ func (repo *ReleaseRepo) UpdatePushStatusRejected(ctx context.Context, id int64, func (repo *ReleaseRepo) Find(ctx context.Context, params domain.QueryParams) ([]domain.Release, int64, int64, error) { queryBuilder := sq. - Select("id", "filter_status", "push_status", "rejections", "indexer", "filter", "protocol", "title", "torrent_name", "size", "timestamp", "COUNT() OVER() AS total_count"). + Select("id", "filter_status", "rejections", "indexer", "filter", "protocol", "title", "torrent_name", "size", "timestamp", "COUNT() OVER() AS total_count"). From("release"). OrderBy("timestamp DESC") @@ -132,7 +137,7 @@ func (repo *ReleaseRepo) Find(ctx context.Context, params domain.QueryParams) ([ var indexer, filter sql.NullString var timestamp string - if err := rows.Scan(&rls.ID, &rls.FilterStatus, &rls.PushStatus, pq.Array(&rls.Rejections), &indexer, &filter, &rls.Protocol, &rls.Title, &rls.TorrentName, &rls.Size, ×tamp, &countItems); err != nil { + if err := rows.Scan(&rls.ID, &rls.FilterStatus, pq.Array(&rls.Rejections), &indexer, &filter, &rls.Protocol, &rls.Title, &rls.TorrentName, &rls.Size, ×tamp, &countItems); err != nil { log.Error().Stack().Err(err).Msg("release.find: error scanning data to struct") return res, 0, 0, err } @@ -143,6 +148,15 @@ func (repo *ReleaseRepo) Find(ctx context.Context, params domain.QueryParams) ([ ca, _ := time.Parse(time.RFC3339, timestamp) rls.Timestamp = ca + // get action status + actionStatus, err := repo.GetActionStatusByReleaseID(ctx, rls.ID) + if err != nil { + log.Error().Stack().Err(err).Msg("release.find: error getting action status") + return res, 0, 0, err + } + + rls.ActionStatus = actionStatus + res = append(res, rls) } @@ -156,13 +170,57 @@ func (repo *ReleaseRepo) Find(ctx context.Context, params domain.QueryParams) ([ return res, nextCursor, countItems, nil } +func (repo *ReleaseRepo) GetActionStatusByReleaseID(ctx context.Context, releaseID int64) ([]domain.ReleaseActionStatus, error) { + + queryBuilder := sq. + Select("id", "status", "action", "type", "rejections", "timestamp"). + From("release_action_status"). + Where("release_id = ?", releaseID) + + query, args, err := queryBuilder.ToSql() + + res := make([]domain.ReleaseActionStatus, 0) + + rows, err := repo.db.QueryContext(ctx, query, args...) + if err != nil { + log.Error().Stack().Err(err).Msg("error fetching releases") + return res, nil + } + + defer rows.Close() + + if err := rows.Err(); err != nil { + log.Error().Stack().Err(err) + return res, err + } + + for rows.Next() { + var rls domain.ReleaseActionStatus + + var timestamp string + + if err := rows.Scan(&rls.ID, &rls.Status, &rls.Action, &rls.Type, pq.Array(&rls.Rejections), ×tamp); err != nil { + log.Error().Stack().Err(err).Msg("release.find: error scanning data to struct") + return res, err + } + + ca, _ := time.Parse(time.RFC3339, timestamp) + rls.Timestamp = ca + + res = append(res, rls) + } + + return res, nil +} + func (repo *ReleaseRepo) Stats(ctx context.Context) (*domain.ReleaseStats, error) { - query := `SELECT - COUNT(*) total, - IFNULL(SUM(CASE WHEN push_status = 'PUSH_APPROVED' THEN 1 ELSE 0 END), 0) push_approved_count, - IFNULL(SUM(CASE WHEN push_status = 'PUSH_REJECTED' THEN 1 ELSE 0 END), 0) push_rejected_count, - IFNULL(SUM(CASE WHEN filter_status = 'FILTER_APPROVED' THEN 1 ELSE 0 END), 0) filtered_count, - IFNULL(SUM(CASE WHEN filter_status = 'FILTER_REJECTED' THEN 1 ELSE 0 END), 0) filter_rejected_count + query := `SELECT COUNT(*) total, + IFNULL(SUM(CASE WHEN filter_status = 'FILTER_APPROVED' THEN 1 ELSE 0 END), 0) filtered_count, + IFNULL(SUM(CASE WHEN filter_status = 'FILTER_REJECTED' THEN 1 ELSE 0 END), 0) filter_rejected_count, + (SELECT IFNULL(SUM(CASE WHEN status = 'PUSH_APPROVED' THEN 1 ELSE 0 END), 0) + FROM "release_action_status") AS push_approved_count, + (SELECT IFNULL(SUM(CASE WHEN status = 'PUSH_REJECTED' THEN 1 ELSE 0 END), 0) + FROM "release_action_status") AS push_rejected_count FROM "release";` row := repo.db.QueryRowContext(ctx, query) diff --git a/internal/domain/release.go b/internal/domain/release.go index a5de577..3a637e1 100644 --- a/internal/domain/release.go +++ b/internal/domain/release.go @@ -27,15 +27,14 @@ import ( type ReleaseRepo interface { Store(ctx context.Context, release *Release) (*Release, error) Find(ctx context.Context, params QueryParams) (res []Release, nextCursor int64, count int64, err error) + GetActionStatusByReleaseID(ctx context.Context, releaseID int64) ([]ReleaseActionStatus, error) Stats(ctx context.Context) (*ReleaseStats, error) - UpdatePushStatus(ctx context.Context, id int64, status ReleasePushStatus) error - UpdatePushStatusRejected(ctx context.Context, id int64, rejections string) error + StoreReleaseActionStatus(ctx context.Context, actionStatus *ReleaseActionStatus) error } type Release struct { ID int64 `json:"id"` FilterStatus ReleaseFilterStatus `json:"filter_status"` - PushStatus ReleasePushStatus `json:"push_status"` Rejections []string `json:"rejections"` Indexer string `json:"indexer"` FilterName string `json:"filter"` @@ -89,6 +88,17 @@ type Release struct { AdditionalSizeCheckRequired bool `json:"-"` FilterID int `json:"-"` Filter *Filter `json:"-"` + ActionStatus []ReleaseActionStatus `json:"action_status"` +} + +type ReleaseActionStatus struct { + ID int64 `json:"id"` + Status ReleasePushStatus `json:"status"` + Action string `json:"action"` + Type ActionType `json:"type"` + Rejections []string `json:"rejections"` + Timestamp time.Time `json:"timestamp"` + ReleaseID int64 `json:"-"` } func NewRelease(indexer string, line string) (*Release, error) { @@ -96,7 +106,6 @@ func NewRelease(indexer string, line string) (*Release, error) { Indexer: indexer, Raw: line, FilterStatus: ReleaseStatusFilterPending, - PushStatus: ReleasePushStatusPending, Rejections: []string{}, Protocol: ReleaseProtocolTorrent, Implementation: ReleaseImplementationIRC, diff --git a/internal/events/subscribers.go b/internal/events/subscribers.go index 8685bea..8843dad 100644 --- a/internal/events/subscribers.go +++ b/internal/events/subscribers.go @@ -24,23 +24,14 @@ func NewSubscribers(eventbus EventBus.Bus, releaseSvc release.Service) Subscribe } func (s Subscriber) Register() { - s.eventbus.Subscribe("release:update-push-status", s.releaseUpdatePushStatus) - s.eventbus.Subscribe("release:update-push-status-rejected", s.releaseUpdatePushStatusRejected) + s.eventbus.Subscribe("release:store-action-status", s.releaseActionStatus) } -func (s Subscriber) releaseUpdatePushStatus(id int64, status domain.ReleasePushStatus) { - log.Trace().Msgf("event: 'release:update-push-status' release ID '%v' update push status: '%v'", id, status) +func (s Subscriber) releaseActionStatus(actionStatus *domain.ReleaseActionStatus) { + log.Trace().Msgf("events: 'release:store-action-status' '%+v'", actionStatus) - err := s.releaseSvc.UpdatePushStatus(context.Background(), id, status) + err := s.releaseSvc.StoreReleaseActionStatus(context.Background(), actionStatus) if err != nil { - log.Error().Err(err).Msgf("events: error") - } -} -func (s Subscriber) releaseUpdatePushStatusRejected(id int64, rejections string) { - log.Trace().Msgf("event: 'release:update-push-status-rejected' release ID '%v' update push status rejected rejections: '%v'", id, rejections) - - err := s.releaseSvc.UpdatePushStatusRejected(context.Background(), id, rejections) - if err != nil { - log.Error().Err(err).Msgf("events: error") + log.Error().Err(err).Msgf("events: 'release:store-action-status' error") } } diff --git a/internal/release/service.go b/internal/release/service.go index eb7f2e4..78a5b31 100644 --- a/internal/release/service.go +++ b/internal/release/service.go @@ -14,8 +14,7 @@ type Service interface { Find(ctx context.Context, query domain.QueryParams) (res []domain.Release, nextCursor int64, count int64, err error) Stats(ctx context.Context) (*domain.ReleaseStats, error) Store(ctx context.Context, release *domain.Release) error - UpdatePushStatus(ctx context.Context, id int64, status domain.ReleasePushStatus) error - UpdatePushStatusRejected(ctx context.Context, id int64, rejections string) error + StoreReleaseActionStatus(ctx context.Context, actionStatus *domain.ReleaseActionStatus) error Process(release domain.Release) error } @@ -36,6 +35,7 @@ func (s *service) Find(ctx context.Context, query domain.QueryParams) (res []dom if err != nil { return } + return } @@ -57,17 +57,8 @@ func (s *service) Store(ctx context.Context, release *domain.Release) error { return nil } -func (s *service) UpdatePushStatus(ctx context.Context, id int64, status domain.ReleasePushStatus) error { - err := s.repo.UpdatePushStatus(ctx, id, status) - if err != nil { - return err - } - - return nil -} - -func (s *service) UpdatePushStatusRejected(ctx context.Context, id int64, rejections string) error { - err := s.repo.UpdatePushStatusRejected(ctx, id, rejections) +func (s *service) StoreReleaseActionStatus(ctx context.Context, actionStatus *domain.ReleaseActionStatus) error { + err := s.repo.StoreReleaseActionStatus(ctx, actionStatus) if err != nil { return err } diff --git a/web/src/domain/interfaces.ts b/web/src/domain/interfaces.ts index 2fc1461..10debd6 100644 --- a/web/src/domain/interfaces.ts +++ b/web/src/domain/interfaces.ts @@ -177,7 +177,6 @@ export interface Config { export interface Release { id: number; filter_status: string; - push_status: string; rejections: string[]; indexer: string; filter: string; @@ -186,6 +185,17 @@ export interface Release { size: number; raw: string; timestamp: Date + action_status: ReleaseActionStatus[] +} + +export interface ReleaseActionStatus { + id: number; + status: string; + action: string; + type: string; + rejections: string[]; + timestamp: Date + // raw: string; } export interface ReleaseFindResponse { diff --git a/web/src/screens/Dashboard.tsx b/web/src/screens/Dashboard.tsx index d6bb5f2..1cd1319 100644 --- a/web/src/screens/Dashboard.tsx +++ b/web/src/screens/Dashboard.tsx @@ -6,6 +6,7 @@ import APIClient from '../api/APIClient' import { useQuery } from 'react-query' import { ReleaseFindResponse, ReleaseStats } from '../domain/interfaces' import { EmptyListState } from '../components/emptystates' +import { ReleaseStatusCell } from './Releases' export function Dashboard() { return ( @@ -660,9 +661,9 @@ function DataTablee() { // Cell: StatusPill, // }, { - Header: "Push Status", - accessor: 'push_status', - Cell: StatusPill, + Header: "Actions", + accessor: 'action_status', + Cell: ReleaseStatusCell, }, { Header: "Indexer", diff --git a/web/src/screens/Releases.tsx b/web/src/screens/Releases.tsx index 433299a..a46de84 100644 --- a/web/src/screens/Releases.tsx +++ b/web/src/screens/Releases.tsx @@ -1,10 +1,13 @@ -import { ChevronDoubleLeftIcon, ChevronLeftIcon, ChevronRightIcon, ChevronDoubleRightIcon } from "@heroicons/react/solid" +import { ExclamationCircleIcon } from "@heroicons/react/outline" +import ClockIcon from "@heroicons/react/outline/ClockIcon" +import { ChevronDoubleLeftIcon, ChevronLeftIcon, ChevronRightIcon, ChevronDoubleRightIcon, CheckIcon } from "@heroicons/react/solid" import { formatDistanceToNowStrict } from "date-fns" import React from "react" import { useQuery } from "react-query" import { useTable, useSortBy, usePagination } from "react-table" import APIClient from "../api/APIClient" import { EmptyListState } from "../components/emptystates" +import { ReleaseActionStatus } from "../domain/interfaces" import { classNames } from "../utils" export function Releases() { @@ -98,6 +101,7 @@ export function StatusPill({ value }: any) { ); }; + export function AgeCell({ value, column, row }: any) { const formatDate = formatDistanceToNowStrict( @@ -116,6 +120,31 @@ export function ReleaseCell({ value, column, row }: any) { ) } +interface ReleaseStatusCellProps { + value: ReleaseActionStatus[]; + column: any; + row: any; +} + +export function ReleaseStatusCell({ value, column, row }: ReleaseStatusCellProps) { + const statusMap: any = { + "PUSH_REJECTED": + , + "PUSH_APPROVED": + + , + "PENDING": + + , + } + return ( + +