From a4a399b8127b8930b7e725af55ed6d129b4c654e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?=
Date: Tue, 16 Apr 2019 00:07:00 +0200 Subject: [PATCH] sklad: prevent creating container cycles --- cmd/sklad/container.tmpl | 2 ++ cmd/sklad/db.go | 15 ++++++++++++--- cmd/sklad/main.go | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cmd/sklad/container.tmpl b/cmd/sklad/container.tmpl index b3ce98f..200bb19 100644 --- a/cmd/sklad/container.tmpl +++ b/cmd/sklad/container.tmpl @@ -12,6 +12,8 @@
Chyba: Řadu u neprázdných obalů nelze měnit. {{ else if .ErrorCannotChangeNumber }}
Chyba: Číslo obalu v řadě nelze měnit. +{{ else if .ErrorWouldContainItself }} +
Chyba: Obal by obsahoval sám sebe. {{ else if .ErrorContainerInUse }}
Chyba: Obal se používá. {{ else if .Error }} diff --git a/cmd/sklad/db.go b/cmd/sklad/db.go index a6cdda8..262a164 100644 --- a/cmd/sklad/db.go +++ b/cmd/sklad/db.go @@ -163,6 +163,7 @@ var errNoSuchContainer = errors.New("no such container") var errCannotChangeSeriesNotEmpty = errors.New( "cannot change the series of a non-empty container") var errCannotChangeNumber = errors.New("cannot change the number") +var errWouldContainItself = errors.New("container would contain itself") var errContainerInUse = errors.New("container is in use") // Find and filter out the container in O(n). @@ -204,19 +205,27 @@ func dbContainerCreate(c *Container) error { } func dbContainerUpdate(c *Container, updated Container) error { - newId := updated.Id() + newID := updated.Id() if updated.Series != c.Series && len(c.Children()) > 0 { return errCannotChangeSeriesNotEmpty } if updated.Number != c.Number { return errCannotChangeNumber } - if _, ok := indexContainer[newId]; ok && newId != c.Id() { + if _, ok := indexContainer[newID]; ok && newID != c.Id() { return errContainerAlreadyExists } if updated.Parent != c.Parent { + // Relying on the invariant that we can't change the ID + // of a non-empty container. + for pv := &updated; pv.Parent != ""; pv = indexContainer[pv.Parent] { + if pv.Parent == updated.Id() { + return errWouldContainItself + } + } + indexChildren[c.Parent] = filterContainer(indexChildren[c.Parent], c) - indexChildren[newId] = append(indexChildren[newId], c) + indexChildren[newID] = append(indexChildren[newID], c) } *c = updated return dbCommit() diff --git a/cmd/sklad/main.go b/cmd/sklad/main.go index 22d25b7..decd894 100644 --- a/cmd/sklad/main.go +++ b/cmd/sklad/main.go @@ -130,6 +130,7 @@ func handleContainer(w http.ResponseWriter, r *http.Request) { ErrorNoSuchContainer bool ErrorCannotChangeSeriesNotEmpty bool ErrorCannotChangeNumber bool + ErrorWouldContainItself bool ErrorContainerInUse bool Container *Container Children []*Container @@ -141,6 +142,7 @@ func handleContainer(w http.ResponseWriter, r *http.Request) { ErrorNoSuchContainer: err == errNoSuchContainer, ErrorCannotChangeSeriesNotEmpty: err == errCannotChangeSeriesNotEmpty, ErrorCannotChangeNumber: err == errCannotChangeNumber, + ErrorWouldContainItself: err == errWouldContainItself, ErrorContainerInUse: err == errContainerInUse, Container: container, Children: children,