pgsql: Move notification to its module
This commit is contained in:
parent
921acb26fe
commit
dfa07f6d86
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package pgsql
|
package notification
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@ -22,6 +22,8 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/coreos/clair/database"
|
"github.com/coreos/clair/database"
|
||||||
|
"github.com/coreos/clair/database/pgsql/page"
|
||||||
|
"github.com/coreos/clair/database/pgsql/testutil"
|
||||||
"github.com/coreos/clair/pkg/pagination"
|
"github.com/coreos/clair/pkg/pagination"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,6 +40,8 @@ type findVulnerabilityNotificationOut struct {
|
|||||||
err string
|
err string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var testPaginationKey = pagination.Must(pagination.NewKey())
|
||||||
|
|
||||||
var findVulnerabilityNotificationTests = []struct {
|
var findVulnerabilityNotificationTests = []struct {
|
||||||
title string
|
title string
|
||||||
in findVulnerabilityNotificationIn
|
in findVulnerabilityNotificationIn
|
||||||
@ -77,21 +81,21 @@ var findVulnerabilityNotificationTests = []struct {
|
|||||||
},
|
},
|
||||||
out: findVulnerabilityNotificationOut{
|
out: findVulnerabilityNotificationOut{
|
||||||
&database.VulnerabilityNotificationWithVulnerable{
|
&database.VulnerabilityNotificationWithVulnerable{
|
||||||
NotificationHook: realNotification[1].NotificationHook,
|
NotificationHook: testutil.RealNotification[1].NotificationHook,
|
||||||
Old: &database.PagedVulnerableAncestries{
|
Old: &database.PagedVulnerableAncestries{
|
||||||
Vulnerability: realVulnerability[2],
|
Vulnerability: testutil.RealVulnerability[2],
|
||||||
Limit: 1,
|
Limit: 1,
|
||||||
Affected: make(map[int]string),
|
Affected: make(map[int]string),
|
||||||
Current: mustMarshalToken(testPaginationKey, Page{0}),
|
Current: testutil.MustMarshalToken(testutil.TestPaginationKey, page.Page{0}),
|
||||||
Next: mustMarshalToken(testPaginationKey, Page{0}),
|
Next: testutil.MustMarshalToken(testutil.TestPaginationKey, page.Page{0}),
|
||||||
End: true,
|
End: true,
|
||||||
},
|
},
|
||||||
New: &database.PagedVulnerableAncestries{
|
New: &database.PagedVulnerableAncestries{
|
||||||
Vulnerability: realVulnerability[1],
|
Vulnerability: testutil.RealVulnerability[1],
|
||||||
Limit: 1,
|
Limit: 1,
|
||||||
Affected: map[int]string{3: "ancestry-3"},
|
Affected: map[int]string{3: "ancestry-3"},
|
||||||
Current: mustMarshalToken(testPaginationKey, Page{0}),
|
Current: testutil.MustMarshalToken(testutil.TestPaginationKey, page.Page{0}),
|
||||||
Next: mustMarshalToken(testPaginationKey, Page{4}),
|
Next: testutil.MustMarshalToken(testutil.TestPaginationKey, page.Page{4}),
|
||||||
End: false,
|
End: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -100,32 +104,31 @@ var findVulnerabilityNotificationTests = []struct {
|
|||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: "find existing notification of second page of new affected ancestry",
|
title: "find existing notification of second page of new affected ancestry",
|
||||||
in: findVulnerabilityNotificationIn{
|
in: findVulnerabilityNotificationIn{
|
||||||
notificationName: "test",
|
notificationName: "test",
|
||||||
pageSize: 1,
|
pageSize: 1,
|
||||||
oldAffectedAncestryPage: pagination.FirstPageToken,
|
oldAffectedAncestryPage: pagination.FirstPageToken,
|
||||||
newAffectedAncestryPage: mustMarshalToken(testPaginationKey, Page{4}),
|
newAffectedAncestryPage: testutil.MustMarshalToken(testutil.TestPaginationKey, page.Page{4}),
|
||||||
},
|
},
|
||||||
out: findVulnerabilityNotificationOut{
|
out: findVulnerabilityNotificationOut{
|
||||||
&database.VulnerabilityNotificationWithVulnerable{
|
&database.VulnerabilityNotificationWithVulnerable{
|
||||||
NotificationHook: realNotification[1].NotificationHook,
|
NotificationHook: testutil.RealNotification[1].NotificationHook,
|
||||||
Old: &database.PagedVulnerableAncestries{
|
Old: &database.PagedVulnerableAncestries{
|
||||||
Vulnerability: realVulnerability[2],
|
Vulnerability: testutil.RealVulnerability[2],
|
||||||
Limit: 1,
|
Limit: 1,
|
||||||
Affected: make(map[int]string),
|
Affected: make(map[int]string),
|
||||||
Current: mustMarshalToken(testPaginationKey, Page{0}),
|
Current: testutil.MustMarshalToken(testutil.TestPaginationKey, page.Page{0}),
|
||||||
Next: mustMarshalToken(testPaginationKey, Page{0}),
|
Next: testutil.MustMarshalToken(testutil.TestPaginationKey, page.Page{0}),
|
||||||
End: true,
|
End: true,
|
||||||
},
|
},
|
||||||
New: &database.PagedVulnerableAncestries{
|
New: &database.PagedVulnerableAncestries{
|
||||||
Vulnerability: realVulnerability[1],
|
Vulnerability: testutil.RealVulnerability[1],
|
||||||
Limit: 1,
|
Limit: 1,
|
||||||
Affected: map[int]string{4: "ancestry-4"},
|
Affected: map[int]string{4: "ancestry-4"},
|
||||||
Current: mustMarshalToken(testPaginationKey, Page{4}),
|
Current: testutil.MustMarshalToken(testutil.TestPaginationKey, page.Page{4}),
|
||||||
Next: mustMarshalToken(testPaginationKey, Page{0}),
|
Next: testutil.MustMarshalToken(testutil.TestPaginationKey, page.Page{0}),
|
||||||
End: true,
|
End: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -137,12 +140,12 @@ var findVulnerabilityNotificationTests = []struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFindVulnerabilityNotification(t *testing.T) {
|
func TestFindVulnerabilityNotification(t *testing.T) {
|
||||||
datastore, tx := openSessionForTest(t, "pagination", true)
|
tx, cleanup := testutil.CreateTestTxWithFixtures(t, "pagination")
|
||||||
defer closeTest(t, datastore, tx)
|
defer cleanup()
|
||||||
|
|
||||||
for _, test := range findVulnerabilityNotificationTests {
|
for _, test := range findVulnerabilityNotificationTests {
|
||||||
t.Run(test.title, func(t *testing.T) {
|
t.Run(test.title, func(t *testing.T) {
|
||||||
notification, ok, err := tx.FindVulnerabilityNotification(test.in.notificationName, test.in.pageSize, test.in.oldAffectedAncestryPage, test.in.newAffectedAncestryPage)
|
notification, ok, err := FindVulnerabilityNotification(tx, test.in.notificationName, test.in.pageSize, test.in.oldAffectedAncestryPage, test.in.newAffectedAncestryPage, testutil.TestPaginationKey)
|
||||||
if test.out.err != "" {
|
if test.out.err != "" {
|
||||||
require.EqualError(t, err, test.out.err)
|
require.EqualError(t, err, test.out.err)
|
||||||
return
|
return
|
||||||
@ -155,13 +158,14 @@ func TestFindVulnerabilityNotification(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assertVulnerabilityNotificationWithVulnerableEqual(t, testPaginationKey, test.out.notification, ¬ification)
|
testutil.AssertVulnerabilityNotificationWithVulnerableEqual(t, testutil.TestPaginationKey, test.out.notification, ¬ification)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertVulnerabilityNotifications(t *testing.T) {
|
func TestInsertVulnerabilityNotifications(t *testing.T) {
|
||||||
datastore, tx := openSessionForTest(t, "InsertVulnerabilityNotifications", true)
|
datastore, cleanup := testutil.CreateTestDBWithFixture(t, "InsertVulnerabilityNotifications")
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
n1 := database.VulnerabilityNotification{}
|
n1 := database.VulnerabilityNotification{}
|
||||||
n3 := database.VulnerabilityNotification{
|
n3 := database.VulnerabilityNotification{
|
||||||
@ -187,34 +191,37 @@ func TestInsertVulnerabilityNotifications(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tx, err := datastore.Begin()
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
// invalid case
|
// invalid case
|
||||||
err := tx.InsertVulnerabilityNotifications([]database.VulnerabilityNotification{n1})
|
err = InsertVulnerabilityNotifications(tx, []database.VulnerabilityNotification{n1})
|
||||||
assert.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
|
|
||||||
// invalid case: unknown vulnerability
|
// invalid case: unknown vulnerability
|
||||||
err = tx.InsertVulnerabilityNotifications([]database.VulnerabilityNotification{n3})
|
err = InsertVulnerabilityNotifications(tx, []database.VulnerabilityNotification{n3})
|
||||||
assert.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
|
|
||||||
// invalid case: duplicated input notification
|
// invalid case: duplicated input notification
|
||||||
err = tx.InsertVulnerabilityNotifications([]database.VulnerabilityNotification{n4, n4})
|
err = InsertVulnerabilityNotifications(tx, []database.VulnerabilityNotification{n4, n4})
|
||||||
assert.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
tx = restartSession(t, datastore, tx, false)
|
tx = testutil.RestartTransaction(datastore, tx, false)
|
||||||
|
|
||||||
// valid case
|
// valid case
|
||||||
err = tx.InsertVulnerabilityNotifications([]database.VulnerabilityNotification{n4})
|
err = InsertVulnerabilityNotifications(tx, []database.VulnerabilityNotification{n4})
|
||||||
assert.Nil(t, err)
|
require.Nil(t, err)
|
||||||
// invalid case: notification is already in database
|
// invalid case: notification is already in database
|
||||||
err = tx.InsertVulnerabilityNotifications([]database.VulnerabilityNotification{n4})
|
err = InsertVulnerabilityNotifications(tx, []database.VulnerabilityNotification{n4})
|
||||||
assert.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
|
|
||||||
closeTest(t, datastore, tx)
|
require.Nil(t, tx.Rollback())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindNewNotification(t *testing.T) {
|
func TestFindNewNotification(t *testing.T) {
|
||||||
tx, cleanup := createTestPgSessionWithFixtures(t, "TestFindNewNotification")
|
tx, cleanup := testutil.CreateTestTxWithFixtures(t, "TestFindNewNotification")
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
noti, ok, err := tx.FindNewNotification(time.Now())
|
noti, ok, err := FindNewNotification(tx, time.Now())
|
||||||
if assert.Nil(t, err) && assert.True(t, ok) {
|
if assert.Nil(t, err) && assert.True(t, ok) {
|
||||||
assert.Equal(t, "test", noti.Name)
|
assert.Equal(t, "test", noti.Name)
|
||||||
assert.Equal(t, time.Time{}, noti.Notified)
|
assert.Equal(t, time.Time{}, noti.Notified)
|
||||||
@ -223,13 +230,13 @@ func TestFindNewNotification(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// can't find the notified
|
// can't find the notified
|
||||||
assert.Nil(t, tx.MarkNotificationAsRead("test"))
|
assert.Nil(t, MarkNotificationAsRead(tx, "test"))
|
||||||
// if the notified time is before
|
// if the notified time is before
|
||||||
noti, ok, err = tx.FindNewNotification(time.Now().Add(-time.Duration(10 * time.Second)))
|
noti, ok, err = FindNewNotification(tx, time.Now().Add(-time.Duration(10*time.Second)))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.False(t, ok)
|
assert.False(t, ok)
|
||||||
// can find the notified after a period of time
|
// can find the notified after a period of time
|
||||||
noti, ok, err = tx.FindNewNotification(time.Now().Add(time.Duration(10 * time.Second)))
|
noti, ok, err = FindNewNotification(tx, time.Now().Add(time.Duration(10*time.Second)))
|
||||||
if assert.Nil(t, err) && assert.True(t, ok) {
|
if assert.Nil(t, err) && assert.True(t, ok) {
|
||||||
assert.Equal(t, "test", noti.Name)
|
assert.Equal(t, "test", noti.Name)
|
||||||
assert.NotEqual(t, time.Time{}, noti.Notified)
|
assert.NotEqual(t, time.Time{}, noti.Notified)
|
||||||
@ -237,37 +244,37 @@ func TestFindNewNotification(t *testing.T) {
|
|||||||
assert.Equal(t, time.Time{}, noti.Deleted)
|
assert.Equal(t, time.Time{}, noti.Deleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Nil(t, tx.DeleteNotification("test"))
|
assert.Nil(t, DeleteNotification(tx, "test"))
|
||||||
// can't find in any time
|
// can't find in any time
|
||||||
noti, ok, err = tx.FindNewNotification(time.Now().Add(-time.Duration(1000)))
|
noti, ok, err = FindNewNotification(tx, time.Now().Add(-time.Duration(1000)))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.False(t, ok)
|
assert.False(t, ok)
|
||||||
|
|
||||||
noti, ok, err = tx.FindNewNotification(time.Now().Add(time.Duration(1000)))
|
noti, ok, err = FindNewNotification(tx, time.Now().Add(time.Duration(1000)))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.False(t, ok)
|
assert.False(t, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarkNotificationAsRead(t *testing.T) {
|
func TestMarkNotificationAsRead(t *testing.T) {
|
||||||
datastore, tx := openSessionForTest(t, "MarkNotificationAsRead", true)
|
tx, cleanup := testutil.CreateTestTxWithFixtures(t, "MarkNotificationAsRead")
|
||||||
defer closeTest(t, datastore, tx)
|
defer cleanup()
|
||||||
|
|
||||||
// invalid case: notification doesn't exist
|
// invalid case: notification doesn't exist
|
||||||
assert.NotNil(t, tx.MarkNotificationAsRead("non-existing"))
|
assert.NotNil(t, MarkNotificationAsRead(tx, "non-existing"))
|
||||||
// valid case
|
// valid case
|
||||||
assert.Nil(t, tx.MarkNotificationAsRead("test"))
|
assert.Nil(t, MarkNotificationAsRead(tx, "test"))
|
||||||
// valid case
|
// valid case
|
||||||
assert.Nil(t, tx.MarkNotificationAsRead("test"))
|
assert.Nil(t, MarkNotificationAsRead(tx, "test"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteNotification(t *testing.T) {
|
func TestDeleteNotification(t *testing.T) {
|
||||||
datastore, tx := openSessionForTest(t, "DeleteNotification", true)
|
tx, cleanup := testutil.CreateTestTxWithFixtures(t, "DeleteNotification")
|
||||||
defer closeTest(t, datastore, tx)
|
defer cleanup()
|
||||||
|
|
||||||
// invalid case: notification doesn't exist
|
// invalid case: notification doesn't exist
|
||||||
assert.NotNil(t, tx.DeleteNotification("non-existing"))
|
assert.NotNil(t, DeleteNotification(tx, "non-existing"))
|
||||||
// valid case
|
// valid case
|
||||||
assert.Nil(t, tx.DeleteNotification("test"))
|
assert.Nil(t, DeleteNotification(tx, "test"))
|
||||||
// invalid case: notification is already deleted
|
// invalid case: notification is already deleted
|
||||||
assert.NotNil(t, tx.DeleteNotification("test"))
|
assert.NotNil(t, DeleteNotification(tx, "test"))
|
||||||
}
|
}
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package pgsql
|
package notification
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
@ -22,6 +22,8 @@ import (
|
|||||||
"github.com/guregu/null/zero"
|
"github.com/guregu/null/zero"
|
||||||
|
|
||||||
"github.com/coreos/clair/database"
|
"github.com/coreos/clair/database"
|
||||||
|
"github.com/coreos/clair/database/pgsql/util"
|
||||||
|
"github.com/coreos/clair/database/pgsql/vulnerability"
|
||||||
"github.com/coreos/clair/pkg/commonerr"
|
"github.com/coreos/clair/pkg/commonerr"
|
||||||
"github.com/coreos/clair/pkg/pagination"
|
"github.com/coreos/clair/pkg/pagination"
|
||||||
)
|
)
|
||||||
@ -54,26 +56,24 @@ const (
|
|||||||
SELECT created_at, notified_at, deleted_at, old_vulnerability_id, new_vulnerability_id
|
SELECT created_at, notified_at, deleted_at, old_vulnerability_id, new_vulnerability_id
|
||||||
FROM Vulnerability_Notification
|
FROM Vulnerability_Notification
|
||||||
WHERE name = $1`
|
WHERE name = $1`
|
||||||
|
|
||||||
searchNotificationVulnerableAncestry = `
|
|
||||||
SELECT DISTINCT ON (a.id)
|
|
||||||
a.id, a.name
|
|
||||||
FROM vulnerability_affected_namespaced_feature AS vanf,
|
|
||||||
ancestry_layer AS al, ancestry_feature AS af, ancestry AS a
|
|
||||||
WHERE vanf.vulnerability_id = $1
|
|
||||||
AND a.id >= $2
|
|
||||||
AND al.ancestry_id = a.id
|
|
||||||
AND al.id = af.ancestry_layer_id
|
|
||||||
AND af.namespaced_feature_id = vanf.namespaced_feature_id
|
|
||||||
ORDER BY a.id ASC
|
|
||||||
LIMIT $3;`
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func queryInsertNotifications(count int) string {
|
||||||
|
return util.QueryInsert(count,
|
||||||
|
"vulnerability_notification",
|
||||||
|
"name",
|
||||||
|
"created_at",
|
||||||
|
"old_vulnerability_id",
|
||||||
|
"new_vulnerability_id",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNotificationNotFound = errors.New("requested notification is not found")
|
errNotificationNotFound = errors.New("requested notification is not found")
|
||||||
|
errVulnerabilityNotFound = errors.New("vulnerability is not in database")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (tx *pgSession) InsertVulnerabilityNotifications(notifications []database.VulnerabilityNotification) error {
|
func InsertVulnerabilityNotifications(tx *sql.Tx, notifications []database.VulnerabilityNotification) error {
|
||||||
if len(notifications) == 0 {
|
if len(notifications) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -122,26 +122,26 @@ func (tx *pgSession) InsertVulnerabilityNotifications(notifications []database.V
|
|||||||
oldVulnIDs = append(oldVulnIDs, vulnID)
|
oldVulnIDs = append(oldVulnIDs, vulnID)
|
||||||
}
|
}
|
||||||
|
|
||||||
ids, err := tx.findNotDeletedVulnerabilityIDs(newVulnIDs)
|
ids, err := vulnerability.FindNotDeletedVulnerabilityIDs(tx, newVulnIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, id := range ids {
|
for i, id := range ids {
|
||||||
if !id.Valid {
|
if !id.Valid {
|
||||||
return handleError("findNotDeletedVulnerabilityIDs", errVulnerabilityNotFound)
|
return util.HandleError("findNotDeletedVulnerabilityIDs", errVulnerabilityNotFound)
|
||||||
}
|
}
|
||||||
newVulnIDMap[newVulnIDs[i]] = id
|
newVulnIDMap[newVulnIDs[i]] = id
|
||||||
}
|
}
|
||||||
|
|
||||||
ids, err = tx.findLatestDeletedVulnerabilityIDs(oldVulnIDs)
|
ids, err = vulnerability.FindLatestDeletedVulnerabilityIDs(tx, oldVulnIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, id := range ids {
|
for i, id := range ids {
|
||||||
if !id.Valid {
|
if !id.Valid {
|
||||||
return handleError("findLatestDeletedVulnerabilityIDs", errVulnerabilityNotFound)
|
return util.HandleError("findLatestDeletedVulnerabilityIDs", errVulnerabilityNotFound)
|
||||||
}
|
}
|
||||||
oldVulnIDMap[oldVulnIDs[i]] = id
|
oldVulnIDMap[oldVulnIDs[i]] = id
|
||||||
}
|
}
|
||||||
@ -178,13 +178,13 @@ func (tx *pgSession) InsertVulnerabilityNotifications(notifications []database.V
|
|||||||
// multiple updaters, deadlock may happen.
|
// multiple updaters, deadlock may happen.
|
||||||
_, err = tx.Exec(queryInsertNotifications(len(notifications)), keys...)
|
_, err = tx.Exec(queryInsertNotifications(len(notifications)), keys...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleError("queryInsertNotifications", err)
|
return util.HandleError("queryInsertNotifications", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *pgSession) FindNewNotification(notifiedBefore time.Time) (database.NotificationHook, bool, error) {
|
func FindNewNotification(tx *sql.Tx, notifiedBefore time.Time) (database.NotificationHook, bool, error) {
|
||||||
var (
|
var (
|
||||||
notification database.NotificationHook
|
notification database.NotificationHook
|
||||||
created zero.Time
|
created zero.Time
|
||||||
@ -197,7 +197,7 @@ func (tx *pgSession) FindNewNotification(notifiedBefore time.Time) (database.Not
|
|||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return notification, false, nil
|
return notification, false, nil
|
||||||
}
|
}
|
||||||
return notification, false, handleError("searchNotificationAvailable", err)
|
return notification, false, util.HandleError("searchNotificationAvailable", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
notification.Created = created.Time
|
notification.Created = created.Time
|
||||||
@ -207,71 +207,7 @@ func (tx *pgSession) FindNewNotification(notifiedBefore time.Time) (database.Not
|
|||||||
return notification, true, nil
|
return notification, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *pgSession) findPagedVulnerableAncestries(vulnID int64, limit int, currentToken pagination.Token) (database.PagedVulnerableAncestries, error) {
|
func FindVulnerabilityNotification(tx *sql.Tx, name string, limit int, oldPageToken pagination.Token, newPageToken pagination.Token, key pagination.Key) (
|
||||||
vulnPage := database.PagedVulnerableAncestries{Limit: limit}
|
|
||||||
currentPage := Page{0}
|
|
||||||
if currentToken != pagination.FirstPageToken {
|
|
||||||
if err := tx.key.UnmarshalToken(currentToken, ¤tPage); err != nil {
|
|
||||||
return vulnPage, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tx.QueryRow(searchVulnerabilityByID, vulnID).Scan(
|
|
||||||
&vulnPage.Name,
|
|
||||||
&vulnPage.Description,
|
|
||||||
&vulnPage.Link,
|
|
||||||
&vulnPage.Severity,
|
|
||||||
&vulnPage.Metadata,
|
|
||||||
&vulnPage.Namespace.Name,
|
|
||||||
&vulnPage.Namespace.VersionFormat,
|
|
||||||
); err != nil {
|
|
||||||
return vulnPage, handleError("searchVulnerabilityByID", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// the last result is used for the next page's startID
|
|
||||||
rows, err := tx.Query(searchNotificationVulnerableAncestry, vulnID, currentPage.StartID, limit+1)
|
|
||||||
if err != nil {
|
|
||||||
return vulnPage, handleError("searchNotificationVulnerableAncestry", err)
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
ancestries := []affectedAncestry{}
|
|
||||||
for rows.Next() {
|
|
||||||
var ancestry affectedAncestry
|
|
||||||
err := rows.Scan(&ancestry.id, &ancestry.name)
|
|
||||||
if err != nil {
|
|
||||||
return vulnPage, handleError("searchNotificationVulnerableAncestry", err)
|
|
||||||
}
|
|
||||||
ancestries = append(ancestries, ancestry)
|
|
||||||
}
|
|
||||||
|
|
||||||
lastIndex := 0
|
|
||||||
if len(ancestries)-1 < limit {
|
|
||||||
lastIndex = len(ancestries)
|
|
||||||
vulnPage.End = true
|
|
||||||
} else {
|
|
||||||
// Use the last ancestry's ID as the next page.
|
|
||||||
lastIndex = len(ancestries) - 1
|
|
||||||
vulnPage.Next, err = tx.key.MarshalToken(Page{ancestries[len(ancestries)-1].id})
|
|
||||||
if err != nil {
|
|
||||||
return vulnPage, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vulnPage.Affected = map[int]string{}
|
|
||||||
for _, ancestry := range ancestries[0:lastIndex] {
|
|
||||||
vulnPage.Affected[int(ancestry.id)] = ancestry.name
|
|
||||||
}
|
|
||||||
|
|
||||||
vulnPage.Current, err = tx.key.MarshalToken(currentPage)
|
|
||||||
if err != nil {
|
|
||||||
return vulnPage, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return vulnPage, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *pgSession) FindVulnerabilityNotification(name string, limit int, oldPageToken pagination.Token, newPageToken pagination.Token) (
|
|
||||||
database.VulnerabilityNotificationWithVulnerable, bool, error) {
|
database.VulnerabilityNotificationWithVulnerable, bool, error) {
|
||||||
var (
|
var (
|
||||||
noti database.VulnerabilityNotificationWithVulnerable
|
noti database.VulnerabilityNotificationWithVulnerable
|
||||||
@ -294,7 +230,7 @@ func (tx *pgSession) FindVulnerabilityNotification(name string, limit int, oldPa
|
|||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return noti, false, nil
|
return noti, false, nil
|
||||||
}
|
}
|
||||||
return noti, false, handleError("searchNotification", err)
|
return noti, false, util.HandleError("searchNotification", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if created.Valid {
|
if created.Valid {
|
||||||
@ -310,7 +246,7 @@ func (tx *pgSession) FindVulnerabilityNotification(name string, limit int, oldPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
if oldVulnID.Valid {
|
if oldVulnID.Valid {
|
||||||
page, err := tx.findPagedVulnerableAncestries(oldVulnID.Int64, limit, oldPageToken)
|
page, err := vulnerability.FindPagedVulnerableAncestries(tx, oldVulnID.Int64, limit, oldPageToken, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return noti, false, err
|
return noti, false, err
|
||||||
}
|
}
|
||||||
@ -318,7 +254,7 @@ func (tx *pgSession) FindVulnerabilityNotification(name string, limit int, oldPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
if newVulnID.Valid {
|
if newVulnID.Valid {
|
||||||
page, err := tx.findPagedVulnerableAncestries(newVulnID.Int64, limit, newPageToken)
|
page, err := vulnerability.FindPagedVulnerableAncestries(tx, newVulnID.Int64, limit, newPageToken, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return noti, false, err
|
return noti, false, err
|
||||||
}
|
}
|
||||||
@ -328,44 +264,44 @@ func (tx *pgSession) FindVulnerabilityNotification(name string, limit int, oldPa
|
|||||||
return noti, true, nil
|
return noti, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *pgSession) MarkNotificationAsRead(name string) error {
|
func MarkNotificationAsRead(tx *sql.Tx, name string) error {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return commonerr.NewBadRequestError("Empty notification name is not allowed")
|
return commonerr.NewBadRequestError("Empty notification name is not allowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := tx.Exec(updatedNotificationAsRead, name)
|
r, err := tx.Exec(updatedNotificationAsRead, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleError("updatedNotificationAsRead", err)
|
return util.HandleError("updatedNotificationAsRead", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := r.RowsAffected()
|
affected, err := r.RowsAffected()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleError("updatedNotificationAsRead", err)
|
return util.HandleError("updatedNotificationAsRead", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if affected <= 0 {
|
if affected <= 0 {
|
||||||
return handleError("updatedNotificationAsRead", errNotificationNotFound)
|
return util.HandleError("updatedNotificationAsRead", errNotificationNotFound)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *pgSession) DeleteNotification(name string) error {
|
func DeleteNotification(tx *sql.Tx, name string) error {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return commonerr.NewBadRequestError("Empty notification name is not allowed")
|
return commonerr.NewBadRequestError("Empty notification name is not allowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := tx.Exec(removeNotification, name)
|
result, err := tx.Exec(removeNotification, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleError("removeNotification", err)
|
return util.HandleError("removeNotification", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := result.RowsAffected()
|
affected, err := result.RowsAffected()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleError("removeNotification", err)
|
return util.HandleError("removeNotification", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if affected <= 0 {
|
if affected <= 0 {
|
||||||
return handleError("removeNotification", commonerr.ErrNotFound)
|
return util.HandleError("removeNotification", commonerr.ErrNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
Loading…
Reference in New Issue
Block a user