Merge pull request #265 from openziti/v0.4_soft_deletes

Soft Deletes (#262)
This commit is contained in:
Michael Quigley 2023-03-10 13:52:08 -05:00 committed by GitHub
commit 86380d1836
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 98 additions and 72 deletions

View File

@ -2,6 +2,8 @@
FEATURE: New metrics infrastructure based on OpenZiti usage events (https://github.com/openziti/zrok/issues/128). See the [v0.4 Metrics Guide](docs/guides/v0.4_metrics.md) for more information.
CHANGE: The underlying database store now utilizes a `deleted` flag on all tables to implement "soft deletes". This was necessary for the new metrics infrastructure, where we need to account for metrics data that arrived after the lifetime of a share or environment; and also we're going to need this for limits, where we need to see historical information about activity in the past (https://github.com/openziti/zrok/issues/262)
# v0.3.4
CHANGE: `zrok test endpoint` incorporates `--ziti` mode (and related flags) to allow direct endpoint listening on a Ziti service

View File

@ -36,6 +36,10 @@ func (h *disableHandler) Handle(params environment.DisableParams, principal *res
logrus.Errorf("error getting environment for user '%v': %v", principal.Email, err)
return environment.NewDisableInternalServerError()
}
if env.Deleted {
logrus.Errorf("environment '%v' for user '%v' deleted", env.ZId, principal.Email)
return environment.NewDisableUnauthorized()
}
edge, err := zrokEdgeSdk.Client(cfg.Ziti)
if err != nil {
logrus.Errorf("error getting edge client for user '%v': %v", principal.Email, err)
@ -85,29 +89,31 @@ func (h *disableHandler) removeSharesForEnvironment(envId int, tx *sqlx.Tx, edge
if err != nil {
return err
}
shrs, err := str.FindSharesForEnvironment(envId, tx)
if err != nil {
return err
}
for _, shr := range shrs {
shrToken := shr.Token
logrus.Infof("garbage collecting share '%v' for environment '%v'", shrToken, env.ZId)
if err := zrokEdgeSdk.DeleteServiceEdgeRouterPolicy(env.ZId, shrToken, edge); err != nil {
logrus.Error(err)
if !env.Deleted {
shrs, err := str.FindSharesForEnvironment(envId, tx)
if err != nil {
return err
}
if err := zrokEdgeSdk.DeleteServicePolicyDial(env.ZId, shrToken, edge); err != nil {
logrus.Error(err)
for _, shr := range shrs {
shrToken := shr.Token
logrus.Infof("garbage collecting share '%v' for environment '%v'", shrToken, env.ZId)
if err := zrokEdgeSdk.DeleteServiceEdgeRouterPolicy(env.ZId, shrToken, edge); err != nil {
logrus.Error(err)
}
if err := zrokEdgeSdk.DeleteServicePolicyDial(env.ZId, shrToken, edge); err != nil {
logrus.Error(err)
}
if err := zrokEdgeSdk.DeleteServicePolicyBind(env.ZId, shrToken, edge); err != nil {
logrus.Error(err)
}
if err := zrokEdgeSdk.DeleteConfig(env.ZId, shrToken, edge); err != nil {
logrus.Error(err)
}
if err := zrokEdgeSdk.DeleteService(env.ZId, shr.ZId, edge); err != nil {
logrus.Error(err)
}
logrus.Infof("removed share '%v' for environment '%v'", shr.Token, env.ZId)
}
if err := zrokEdgeSdk.DeleteServicePolicyBind(env.ZId, shrToken, edge); err != nil {
logrus.Error(err)
}
if err := zrokEdgeSdk.DeleteConfig(env.ZId, shrToken, edge); err != nil {
logrus.Error(err)
}
if err := zrokEdgeSdk.DeleteService(env.ZId, shr.ZId, edge); err != nil {
logrus.Error(err)
}
logrus.Infof("removed share '%v' for environment '%v'", shr.Token, env.ZId)
}
return nil
}
@ -117,13 +123,15 @@ func (h *disableHandler) removeFrontendsForEnvironment(envId int, tx *sqlx.Tx, e
if err != nil {
return err
}
fes, err := str.FindFrontendsForEnvironment(envId, tx)
if err != nil {
return err
}
for _, fe := range fes {
if err := zrokEdgeSdk.DeleteServicePolicy(env.ZId, fmt.Sprintf("tags.zrokFrontendToken=\"%v\" and type=1", fe.Token), edge); err != nil {
logrus.Errorf("error removing frontend access for '%v': %v", fe.Token, err)
if !env.Deleted {
fes, err := str.FindFrontendsForEnvironment(envId, tx)
if err != nil {
return err
}
for _, fe := range fes {
if err := zrokEdgeSdk.DeleteServicePolicy(env.ZId, fmt.Sprintf("tags.zrokFrontendToken=\"%v\" and type=1", fe.Token), edge); err != nil {
logrus.Errorf("error removing frontend access for '%v': %v", fe.Token, err)
}
}
}
return nil

View File

@ -37,7 +37,7 @@ func GC(inCfg *Config) error {
return err
}
defer func() { _ = tx.Rollback() }()
sshrs, err := str.GetAllShares(tx)
sshrs, err := str.FindAllShares(tx)
if err != nil {
return err
}

View File

@ -3,7 +3,6 @@ package controller
import (
"github.com/go-openapi/runtime/middleware"
"github.com/openziti/zrok/controller/store"
"github.com/openziti/zrok/rest_model_zrok"
"github.com/openziti/zrok/rest_server_zrok/operations/account"
"github.com/openziti/zrok/util"
"github.com/sirupsen/logrus"
@ -19,7 +18,7 @@ func newInviteHandler(cfg *Config) *inviteHandler {
}
}
func (self *inviteHandler) Handle(params account.InviteParams) middleware.Responder {
func (h *inviteHandler) Handle(params account.InviteParams) middleware.Responder {
if params.Body == nil || params.Body.Email == "" {
logrus.Errorf("missing email")
return account.NewInviteBadRequest()
@ -38,11 +37,11 @@ func (self *inviteHandler) Handle(params account.InviteParams) middleware.Respon
}
defer func() { _ = tx.Rollback() }()
if self.cfg.Registration != nil && self.cfg.Registration.TokenStrategy == "store" {
inviteToken, err := str.GetInviteTokenByToken(params.Body.Token, tx)
if h.cfg.Registration != nil && h.cfg.Registration.TokenStrategy == "store" {
inviteToken, err := str.FindInviteTokenByToken(params.Body.Token, tx)
if err != nil {
logrus.Errorf("cannot get invite token '%v' for '%v': %v", params.Body.Token, params.Body.Email, err)
return account.NewInviteBadRequest().WithPayload(rest_model_zrok.ErrorMessage("Missing invite token"))
return account.NewInviteBadRequest().WithPayload("missing invite token")
}
if err := str.DeleteInviteToken(inviteToken.Id, tx); err != nil {
logrus.Error(err)
@ -62,9 +61,10 @@ func (self *inviteHandler) Handle(params account.InviteParams) middleware.Respon
SourceAddress: params.HTTPRequest.RemoteAddr,
}
if _, err := str.FindAccountWithEmail(params.Body.Email, tx); err == nil {
// deleted accounts still exist as far as invites are concerned (ignore deleted flag)
if _, err := str.FindAccountWithEmailAndDeleted(params.Body.Email, tx); err == nil {
logrus.Errorf("found account for '%v', cannot process account request", params.Body.Email)
return account.NewInviteBadRequest().WithPayload(rest_model_zrok.ErrorMessage("Duplicate email found"))
return account.NewInviteBadRequest().WithPayload("duplicate email found")
} else {
logrus.Infof("no account found for '%v': %v", params.Body.Email, err)
}

View File

@ -23,7 +23,7 @@ func (sc *shareCache) getToken(svcZId string) (string, error) {
return "", err
}
defer func() { _ = tx.Rollback() }()
shr, err := sc.str.FindShareWithZId(svcZId, tx)
shr, err := sc.str.FindShareWithZIdAndDeleted(svcZId, tx)
if err != nil {
return "", err
}

View File

@ -37,6 +37,10 @@ func (handler *resetPasswordHandler) Handle(params account.ResetPasswordParams)
logrus.Errorf("error finding account for '%v': %v", params.Body.Token, err)
return account.NewResetPasswordNotFound()
}
if a.Deleted {
logrus.Errorf("account '%v' for '%v' deleted", a.Email, a.Token)
return account.NewResetPasswordNotFound()
}
hpwd, err := hashPassword(params.Body.Password)
if err != nil {
logrus.Errorf("error hashing password for '%v' (%v): %v", params.Body.Token, a.Email, err)

View File

@ -42,7 +42,7 @@ func (handler *resetPasswordRequestHandler) Handle(params account.ResetPasswordR
a, err := str.FindAccountWithEmail(params.Body.EmailAddress, tx)
if err != nil {
logrus.Infof("no account found for '%v': %v", params.Body.EmailAddress, err)
logrus.Errorf("no account found for '%v': %v", params.Body.EmailAddress, err)
return account.NewResetPasswordRequestInternalServerError()
}

View File

@ -37,15 +37,23 @@ func (self *Store) GetAccount(id int, tx *sqlx.Tx) (*Account, error) {
func (self *Store) FindAccountWithEmail(email string, tx *sqlx.Tx) (*Account, error) {
a := &Account{}
if err := tx.QueryRowx("select * from accounts where email = $1", email).StructScan(a); err != nil {
if err := tx.QueryRowx("select * from accounts where email = $1 and not deleted", email).StructScan(a); err != nil {
return nil, errors.Wrap(err, "error selecting account by email")
}
return a, nil
}
func (self *Store) FindAccountWithEmailAndDeleted(email string, tx *sqlx.Tx) (*Account, error) {
a := &Account{}
if err := tx.QueryRowx("select * from accounts where email = $1", email).StructScan(a); err != nil {
return nil, errors.Wrap(err, "error selecting acount by email")
}
return a, nil
}
func (self *Store) FindAccountWithToken(token string, tx *sqlx.Tx) (*Account, error) {
a := &Account{}
if err := tx.QueryRowx("select * from accounts where token = $1", token).StructScan(a); err != nil {
if err := tx.QueryRowx("select * from accounts where token = $1 and not deleted", token).StructScan(a); err != nil {
return nil, errors.Wrap(err, "error selecting account by token")
}
return a, nil

View File

@ -39,7 +39,7 @@ func (self *Store) GetAccountRequest(id int, tx *sqlx.Tx) (*AccountRequest, erro
func (self *Store) FindAccountRequestWithToken(token string, tx *sqlx.Tx) (*AccountRequest, error) {
ar := &AccountRequest{}
if err := tx.QueryRowx("select * from account_requests where token = $1", token).StructScan(ar); err != nil {
if err := tx.QueryRowx("select * from account_requests where token = $1 and not deleted", token).StructScan(ar); err != nil {
return nil, errors.Wrap(err, "error selecting account_request by token")
}
return ar, nil
@ -49,10 +49,10 @@ func (self *Store) FindExpiredAccountRequests(before time.Time, limit int, tx *s
var sql string
switch self.cfg.Type {
case "postgres":
sql = "select * from account_requests where created_at < $1 limit %d for update"
sql = "select * from account_requests where created_at < $1 and not deleted limit %d for update"
case "sqlite3":
sql = "select * from account_requests where created_at < $1 limit %d"
sql = "select * from account_requests where created_at < $1 and not deleted limit %d"
default:
return nil, errors.Errorf("unknown database type '%v'", self.cfg.Type)
@ -75,14 +75,14 @@ func (self *Store) FindExpiredAccountRequests(before time.Time, limit int, tx *s
func (self *Store) FindAccountRequestWithEmail(email string, tx *sqlx.Tx) (*AccountRequest, error) {
ar := &AccountRequest{}
if err := tx.QueryRowx("select * from account_requests where email = $1", email).StructScan(ar); err != nil {
if err := tx.QueryRowx("select * from account_requests where email = $1 and not deleted", email).StructScan(ar); err != nil {
return nil, errors.Wrap(err, "error selecting account_request by email")
}
return ar, nil
}
func (self *Store) DeleteAccountRequest(id int, tx *sqlx.Tx) error {
stmt, err := tx.Prepare("delete from account_requests where id = $1")
stmt, err := tx.Prepare("update account_requests set deleted = true, updated_at = current_timestamp where id = $1")
if err != nil {
return errors.Wrap(err, "error preparing account_requests delete statement")
}
@ -106,7 +106,7 @@ func (self *Store) DeleteMultipleAccountRequests(ids []int, tx *sqlx.Tx) error {
indexes[i] = fmt.Sprintf("$%d", i+1)
}
stmt, err := tx.Prepare(fmt.Sprintf("delete from account_requests where id in (%s)", strings.Join(indexes, ",")))
stmt, err := tx.Prepare(fmt.Sprintf("update account_requests set deleted = true, updated_at = current_timestamp where id in (%s)", strings.Join(indexes, ",")))
if err != nil {
return errors.Wrap(err, "error preparing account_requests delete multiple statement")
}

View File

@ -48,7 +48,7 @@ func (self *Store) GetEnvironment(id int, tx *sqlx.Tx) (*Environment, error) {
}
func (self *Store) FindEnvironmentsForAccount(accountId int, tx *sqlx.Tx) ([]*Environment, error) {
rows, err := tx.Queryx("select environments.* from environments where account_id = $1", accountId)
rows, err := tx.Queryx("select environments.* from environments where account_id = $1 and not deleted", accountId)
if err != nil {
return nil, errors.Wrap(err, "error selecting environments by account id")
}
@ -65,14 +65,14 @@ func (self *Store) FindEnvironmentsForAccount(accountId int, tx *sqlx.Tx) ([]*En
func (self *Store) FindEnvironmentForAccount(envZId string, accountId int, tx *sqlx.Tx) (*Environment, error) {
env := &Environment{}
if err := tx.QueryRowx("select environments.* from environments where z_id = $1 and account_id = $2", envZId, accountId).StructScan(env); err != nil {
if err := tx.QueryRowx("select environments.* from environments where z_id = $1 and account_id = $2 and not deleted", envZId, accountId).StructScan(env); err != nil {
return nil, errors.Wrap(err, "error finding environment by z_id and account_id")
}
return env, nil
}
func (self *Store) DeleteEnvironment(id int, tx *sqlx.Tx) error {
stmt, err := tx.Prepare("delete from environments where id = $1")
stmt, err := tx.Prepare("update environments set updated_at = current_timestamp, deleted = true where id = $1")
if err != nil {
return errors.Wrap(err, "error preparing environments delete statement")
}

View File

@ -26,6 +26,7 @@ func TestEphemeralEnvironment(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, env)
assert.Nil(t, env.AccountId)
assert.False(t, env.Deleted)
}
func TestEnvironment(t *testing.T) {
@ -57,4 +58,5 @@ func TestEnvironment(t *testing.T) {
assert.NotNil(t, env)
assert.NotNil(t, env.AccountId)
assert.Equal(t, acctId, *env.AccountId)
assert.False(t, env.Deleted)
}

View File

@ -50,7 +50,7 @@ func (str *Store) GetFrontend(id int, tx *sqlx.Tx) (*Frontend, error) {
func (str *Store) FindFrontendWithToken(token string, tx *sqlx.Tx) (*Frontend, error) {
i := &Frontend{}
if err := tx.QueryRowx("select frontends.* from frontends where token = $1", token).StructScan(i); err != nil {
if err := tx.QueryRowx("select frontends.* from frontends where token = $1 and not deleted", token).StructScan(i); err != nil {
return nil, errors.Wrap(err, "error selecting frontend by name")
}
return i, nil
@ -58,7 +58,7 @@ func (str *Store) FindFrontendWithToken(token string, tx *sqlx.Tx) (*Frontend, e
func (str *Store) FindFrontendWithZId(zId string, tx *sqlx.Tx) (*Frontend, error) {
i := &Frontend{}
if err := tx.QueryRowx("select frontends.* from frontends where z_id = $1", zId).StructScan(i); err != nil {
if err := tx.QueryRowx("select frontends.* from frontends where z_id = $1 and not deleted", zId).StructScan(i); err != nil {
return nil, errors.Wrap(err, "error selecting frontend by ziti id")
}
return i, nil
@ -66,14 +66,14 @@ func (str *Store) FindFrontendWithZId(zId string, tx *sqlx.Tx) (*Frontend, error
func (str *Store) FindFrontendPubliclyNamed(publicName string, tx *sqlx.Tx) (*Frontend, error) {
i := &Frontend{}
if err := tx.QueryRowx("select frontends.* from frontends where public_name = $1", publicName).StructScan(i); err != nil {
if err := tx.QueryRowx("select frontends.* from frontends where public_name = $1 and not deleted", publicName).StructScan(i); err != nil {
return nil, errors.Wrap(err, "error selecting frontend by public_name")
}
return i, nil
}
func (str *Store) FindFrontendsForEnvironment(envId int, tx *sqlx.Tx) ([]*Frontend, error) {
rows, err := tx.Queryx("select frontends.* from frontends where environment_id = $1", envId)
rows, err := tx.Queryx("select frontends.* from frontends where environment_id = $1 and not deleted", envId)
if err != nil {
return nil, errors.Wrap(err, "error selecting frontends by environment_id")
}
@ -89,7 +89,7 @@ func (str *Store) FindFrontendsForEnvironment(envId int, tx *sqlx.Tx) ([]*Fronte
}
func (str *Store) FindPublicFrontends(tx *sqlx.Tx) ([]*Frontend, error) {
rows, err := tx.Queryx("select frontends.* from frontends where environment_id is null and reserved = true")
rows, err := tx.Queryx("select frontends.* from frontends where environment_id is null and reserved = true and not deleted")
if err != nil {
return nil, errors.Wrap(err, "error selecting public frontends")
}
@ -119,7 +119,7 @@ func (str *Store) UpdateFrontend(fe *Frontend, tx *sqlx.Tx) error {
func (str *Store) DeleteFrontend(id int, tx *sqlx.Tx) error {
stmt, err := tx.Prepare("delete from frontends where id = $1")
stmt, err := tx.Prepare("update frontends set updated_at = current_timestamp, deleted = true where id = $1")
if err != nil {
return errors.Wrap(err, "error preparing frontends delete statement")
}

View File

@ -42,6 +42,7 @@ func TestPublicFrontend(t *testing.T) {
assert.NotNil(t, fe)
assert.Equal(t, envId, *fe.EnvironmentId)
assert.Equal(t, feName, *fe.PublicName)
assert.False(t, fe.Deleted)
fe0, err := str.FindFrontendPubliclyNamed(feName, tx)
assert.Nil(t, err)
@ -56,6 +57,7 @@ func TestPublicFrontend(t *testing.T) {
assert.Nil(t, fe0)
fe0, err = str.GetFrontend(fe.Id, tx)
assert.NotNil(t, err)
assert.Nil(t, fe0)
assert.Nil(t, err)
assert.NotNil(t, fe0)
assert.True(t, fe0.Deleted)
}

View File

@ -32,16 +32,16 @@ func (str *Store) CreateInviteTokens(inviteTokens []*InviteToken, tx *sqlx.Tx) e
return nil
}
func (str *Store) GetInviteTokenByToken(token string, tx *sqlx.Tx) (*InviteToken, error) {
func (str *Store) FindInviteTokenByToken(token string, tx *sqlx.Tx) (*InviteToken, error) {
inviteToken := &InviteToken{}
if err := tx.QueryRowx("select * from invite_tokens where token = $1", token).StructScan(inviteToken); err != nil {
if err := tx.QueryRowx("select * from invite_tokens where token = $1 and not deleted", token).StructScan(inviteToken); err != nil {
return nil, errors.Wrap(err, "error getting unused invite_token")
}
return inviteToken, nil
}
func (str *Store) DeleteInviteToken(id int, tx *sqlx.Tx) error {
stmt, err := tx.Prepare("delete from invite_tokens where id = $1")
stmt, err := tx.Prepare("update invite_tokens set updated_at = current_timestamp, deleted = true where id = $1")
if err != nil {
return errors.Wrap(err, "error preparing invite_tokens delete statement")
}

View File

@ -30,7 +30,7 @@ func (self *Store) CreatePasswordResetRequest(prr *PasswordResetRequest, tx *sql
func (self *Store) FindPasswordResetRequestWithToken(token string, tx *sqlx.Tx) (*PasswordResetRequest, error) {
prr := &PasswordResetRequest{}
if err := tx.QueryRowx("select * from password_reset_requests where token = $1", token).StructScan(prr); err != nil {
if err := tx.QueryRowx("select * from password_reset_requests where token = $1 and not deleted", token).StructScan(prr); err != nil {
return nil, errors.Wrap(err, "error selecting password_reset_requests by token")
}
return prr, nil
@ -40,10 +40,10 @@ func (self *Store) FindExpiredPasswordResetRequests(before time.Time, limit int,
var sql string
switch self.cfg.Type {
case "postgres":
sql = "select * from password_reset_requests where created_at < $1 limit %d for update"
sql = "select * from password_reset_requests where created_at < $1 and not deleted limit %d for update"
case "sqlite3":
sql = "select * from password_reset_requests where created_at < $1 limit %d"
sql = "select * from password_reset_requests where created_at < $1 and not deleted limit %d"
default:
return nil, errors.Errorf("unknown database type '%v'", self.cfg.Type)
}
@ -64,7 +64,7 @@ func (self *Store) FindExpiredPasswordResetRequests(before time.Time, limit int,
}
func (self *Store) DeletePasswordResetRequest(id int, tx *sqlx.Tx) error {
stmt, err := tx.Prepare("delete from password_reset_requests where id = $1")
stmt, err := tx.Prepare("update password_reset_requests set updated_at = current_timestamp, deleted = true where id = $1")
if err != nil {
return errors.Wrap(err, "error preparing password_reset_requests delete statement")
}
@ -88,7 +88,7 @@ func (self *Store) DeleteMultiplePasswordResetRequests(ids []int, tx *sqlx.Tx) e
indexes[i] = fmt.Sprintf("$%d", i+1)
}
stmt, err := tx.Prepare(fmt.Sprintf("delete from password_reset_requests where id in (%s)", strings.Join(indexes, ",")))
stmt, err := tx.Prepare(fmt.Sprintf("update password_reset_requests set updated_at = current_timestamp, deleted = true where id in (%s)", strings.Join(indexes, ",")))
if err != nil {
return errors.Wrap(err, "error preparing password_reset_requests delete multiple statement")
}

View File

@ -39,8 +39,8 @@ func (self *Store) GetShare(id int, tx *sqlx.Tx) (*Share, error) {
return shr, nil
}
func (self *Store) GetAllShares(tx *sqlx.Tx) ([]*Share, error) {
rows, err := tx.Queryx("select * from shares order by id")
func (self *Store) FindAllShares(tx *sqlx.Tx) ([]*Share, error) {
rows, err := tx.Queryx("select * from shares where not deleted order by id")
if err != nil {
return nil, errors.Wrap(err, "error selecting all shares")
}
@ -57,13 +57,13 @@ func (self *Store) GetAllShares(tx *sqlx.Tx) ([]*Share, error) {
func (self *Store) FindShareWithToken(shrToken string, tx *sqlx.Tx) (*Share, error) {
shr := &Share{}
if err := tx.QueryRowx("select * from shares where token = $1", shrToken).StructScan(shr); err != nil {
if err := tx.QueryRowx("select * from shares where token = $1 and not deleted", shrToken).StructScan(shr); err != nil {
return nil, errors.Wrap(err, "error selecting share by token")
}
return shr, nil
}
func (self *Store) FindShareWithZId(zId string, tx *sqlx.Tx) (*Share, error) {
func (self *Store) FindShareWithZIdAndDeleted(zId string, tx *sqlx.Tx) (*Share, error) {
shr := &Share{}
if err := tx.QueryRowx("select * from shares where z_id = $1", zId).StructScan(shr); err != nil {
return nil, errors.Wrap(err, "error selecting share by z_id")
@ -72,7 +72,7 @@ func (self *Store) FindShareWithZId(zId string, tx *sqlx.Tx) (*Share, error) {
}
func (self *Store) FindSharesForEnvironment(envId int, tx *sqlx.Tx) ([]*Share, error) {
rows, err := tx.Queryx("select shares.* from shares where environment_id = $1", envId)
rows, err := tx.Queryx("select shares.* from shares where environment_id = $1 and not deleted", envId)
if err != nil {
return nil, errors.Wrap(err, "error selecting shares by environment id")
}
@ -101,7 +101,7 @@ func (self *Store) UpdateShare(shr *Share, tx *sqlx.Tx) error {
}
func (self *Store) DeleteShare(id int, tx *sqlx.Tx) error {
stmt, err := tx.Prepare("delete from shares where id = $1")
stmt, err := tx.Prepare("update shares set updated_at = current_timestamp, deleted = true where id = $1")
if err != nil {
return errors.Wrap(err, "error preparing shares delete statement")
}

View File

@ -26,7 +26,7 @@ func (self *verifyHandler) Handle(params account.VerifyParams) middleware.Respon
ar, err := str.FindAccountRequestWithToken(params.Body.Token, tx)
if err != nil {
logrus.Errorf("error finding account with token '%v': %v", params.Body.Token, err)
logrus.Errorf("error finding account request with token '%v': %v", params.Body.Token, err)
return account.NewVerifyNotFound()
}