3
0

Add (suspended|archived|deleted)_at fields & logic everywhere

Took 1 minute
This commit is contained in:
Denis Arh
2018-07-06 10:22:19 +02:00
parent 2a6336ca72
commit ef46e643af
9 changed files with 139 additions and 18 deletions

View File

@@ -9,6 +9,11 @@ import (
var _ = errors.Wrap
const (
sqlChannelScope = "deleted_at IS NULL AND archived_at IS NULL"
sqlChannelSelect = "SELECT * FROM channels WHERE " + sqlChannelScope
)
func (*Channel) Edit(r *channelEditRequest) (interface{}, error) {
db, err := factory.Database.Get()
if err != nil {
@@ -19,6 +24,7 @@ func (*Channel) Edit(r *channelEditRequest) (interface{}, error) {
// @todo: channel name change message/log entry
// @todo: permission check if user can edit channel
// @todo: permission check if user can add channel
// @todo: make sure archived & deleted entries can not be edited
c := Channel{}.new().SetID(r.id).SetName(r.name).SetTopic(r.topic)
if c.GetID() > 0 {
@@ -37,12 +43,14 @@ func (*Channel) Remove(r *channelRemoveRequest) (interface{}, error) {
return nil, err
}
// @todo: don't actually delete the channel (mark as deleted, history becomes unavailable)
// @todo: make history unavailable
// @todo: notify users that channel has been removed (remove from web UI)
// @todo: permissions check if user cah remove channel
stmt := "UPDATE channels SET deleted_at = NOW() WHERE id = ? AND deleted_at IS NULL"
return nil, func() error {
_, err := db.Exec("delete from channel where id=?", r.id)
_, err := db.Exec(stmt, r.id)
return err
}()
}
@@ -56,7 +64,7 @@ func (*Channel) Read(r *channelReadRequest) (interface{}, error) {
// @todo: permission check if user can read channel
c := Channel{}.new()
return c, db.Get(c, "select * from channel where id=?", r.id)
return c, db.Get(c, sqlChannelSelect+" AND id = ?", r.id)
}
func (*Channel) Search(r *channelSearchRequest) (interface{}, error) {
@@ -69,7 +77,7 @@ func (*Channel) Search(r *channelSearchRequest) (interface{}, error) {
// @todo: actual searching not just a full select
res := make([]Channel, 0)
err = db.Select(&res, "select * from channel order by name asc")
err = db.Select(&res, sqlChannelSelect+" ORDER BY name ASC")
return res, err
}
@@ -79,12 +87,15 @@ func (*Channel) Archive(r *channelArchiveRequest) (interface{}, error) {
return nil, err
}
// @todo: don't actually delete the channel (mark as archived, history stays available)
// @todo: notify users that channel has been archived (last message - archival, disable new messages)
// @todo: permissions check if user cah archive channel
// @todo: permissions check if user can archive channel
stmt := fmt.Sprintf(
"UPDATE channels SET archived_at = NOW() WHERE %s AND id = ?",
sqlChannelScope)
return nil, func() error {
_, err = db.Exec("delete from channel where id=?", r.id)
_, err = db.Exec(stmt, r.id)
return err
}()
}

View File

@@ -1,11 +1,18 @@
package sam
import (
"time"
)
// Channels
type Channel struct {
ID uint64
Name string
Topic string
ArchivedAt *time.Time `json:",omitempty"`
DeletedAt *time.Time `json:",omitempty"`
changed []string
}

View File

@@ -4,6 +4,9 @@ CREATE TABLE organisations (
fqn TEXT NOT NULL, -- fully qualified name of the organisation
label TEXT NOT NULL, -- display name of the organisation
archived_at DATETIME NULL,
deleted_at DATETIME NULL, -- organisation soft delete
PRIMARY KEY (id)
);
@@ -13,6 +16,9 @@ CREATE TABLE teams (
label TEXT NOT NULL, -- display name of the team
handle TEXT NOT NULL, -- team handle string
archived_at DATETIME NULL,
deleted_at DATETIME NULL, -- team soft delete
PRIMARY KEY (id)
);
@@ -22,6 +28,9 @@ CREATE TABLE channels (
label TEXT NOT NULL, -- display name of the channel
meta JSON NOT NULL,
archived_at DATETIME NULL,
deleted_at DATETIME NULL, -- channel soft delete
PRIMARY KEY (id)
);
@@ -35,6 +44,9 @@ CREATE TABLE users (
rel_organisation BIGINT UNSIGNED NOT NULL REFERENCES organisation(id),
suspended_at DATETIME NULL,
deleted_at DATETIME NULL, -- user soft delete
PRIMARY KEY (id)
);

View File

@@ -1,12 +1,18 @@
package sam
import (
"fmt"
"github.com/pkg/errors"
"github.com/titpetric/factory"
)
var _ = errors.Wrap
const (
sqlOrganisationScope = "deleted_at IS NULL AND archived_at IS NULL"
sqlOrganisationSelect = "SELECT * FROM organisations WHERE " + sqlOrganisationScope
)
func (*Organisation) Edit(r *organisationEditRequest) (interface{}, error) {
db, err := factory.Database.Get()
if err != nil {
@@ -14,6 +20,7 @@ func (*Organisation) Edit(r *organisationEditRequest) (interface{}, error) {
}
// @todo: permission check if user can add/edit organisation
// @todo: make sure archived & deleted entries can not be edited
o := Organisation{}.new().SetID(r.id).SetName(r.name)
if o.GetID() > 0 {
@@ -32,8 +39,10 @@ func (*Organisation) Remove(r *organisationRemoveRequest) (interface{}, error) {
// @todo: permission check
// @todo: don't actually delete organisation?!
stmt := "UPDATE organisationss SET deleted_at = NOW() WHERE deleted_at IS NULL AND id = ?"
return nil, func() error {
_, err := db.Exec("delete from organisation where id=?", r.id)
_, err := db.Exec(stmt, r.id)
return err
}()
}
@@ -47,7 +56,7 @@ func (*Organisation) Read(r *organisationReadRequest) (interface{}, error) {
// @todo: permissions check
o := Organisation{}.new()
return o, db.Get(o, "select * from organisation where id=?", r.id)
return o, db.Get(o, sqlOrganisationSelect+" AND id = ?", r.id)
}
func (*Organisation) Search(r *organisationSearchRequest) (interface{}, error) {
@@ -60,7 +69,7 @@ func (*Organisation) Search(r *organisationSearchRequest) (interface{}, error) {
// @todo: actual search for org
res := make([]Organisation, 0)
err = db.Select(&res, "select * from organisation order by name asc")
err = db.Select(&res, sqlOrganisationSelect+" WHERE label LIKE = ? ORDER BY label ASC", r.query+"%")
return res, err
}
@@ -71,10 +80,13 @@ func (*Organisation) Archive(r *organisationArchiveRequest) (interface{}, error)
}
// @todo: permission check
// @todo: don't actually delete organisation?!
stmt := fmt.Sprintf(
"UPDATE organisation SET archived_at = NOW() WHERE %s AND id = ?",
sqlChannelScope)
return nil, func() error {
_, err := db.Exec("delete from organisation where id=?", r.id)
_, err := db.Exec(stmt, r.id)
return err
}()
}

View File

@@ -1,10 +1,17 @@
package sam
import (
"time"
)
// Organisations
type Organisation struct {
ID uint64
Name string
ArchivedAt *time.Time
DeletedAt *time.Time
changed []string
}

View File

@@ -1,18 +1,27 @@
package sam
import (
"fmt"
"github.com/pkg/errors"
"github.com/titpetric/factory"
)
var _ = errors.Wrap
const (
sqlTeamScope = "deleted_at IS NULL AND archived_at IS NULL"
sqlTeamSelect = "SELECT * FROM teams WHERE " + sqlTeamScope
)
func (*Team) Edit(r *teamEditRequest) (interface{}, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, err
}
// @todo: permission check if user can add/edit the team
// @todo: make sure archived & deleted entries can not be edited
t := Team{}.new()
t.SetID(r.id).SetName(r.name).SetMemberIDs(r.members)
if t.GetID() > 0 {
@@ -28,8 +37,10 @@ func (*Team) Remove(r *teamRemoveRequest) (interface{}, error) {
return nil, err
}
stmt := "UPDATE teams SET deleted_at = NOW() WHERE deleted_at IS NULL AND id = ?"
return nil, func() error {
_, err := db.Exec("delete from team where id=?", r.id)
_, err := db.Exec(stmt, r.id)
return err
}()
}
@@ -41,7 +52,7 @@ func (*Team) Read(r *teamReadRequest) (interface{}, error) {
}
t := Team{}.new()
return t, db.Get(t, "select * from team where id=?", r.id)
return t, db.Get(t, sqlTeamSelect+" AND id = ?", r.id)
}
func (*Team) Search(r *teamSearchRequest) (interface{}, error) {
@@ -51,7 +62,7 @@ func (*Team) Search(r *teamSearchRequest) (interface{}, error) {
}
res := make([]Team, 0)
err = db.Select(&res, "select * from team order by name asc")
err = db.Select(&res, sqlTeamSelect+" ORDER BY name ASC")
return res, err
}
@@ -61,8 +72,12 @@ func (*Team) Archive(r *teamArchiveRequest) (interface{}, error) {
return nil, err
}
stmt := fmt.Sprintf(
"UPDATE teams SET archived_at = NOW() WHERE %s AND id = ?",
sqlTeamScope)
return nil, func() error {
_, err := db.Exec("delete from team where id=?", r.id)
_, err := db.Exec(stmt, r.id)
return err
}()
}

View File

@@ -1,5 +1,9 @@
package sam
import (
"time"
)
// Teams
type Team struct {
ID uint64
@@ -7,6 +11,9 @@ type Team struct {
MemberIDs []uint64 `json:"-"`
Members []User `json:",omitempty"`
ArchivedAt *time.Time `json:",omitempty"`
DeletedAt *time.Time `json:",omitempty"`
changed []string
}

View File

@@ -1,12 +1,28 @@
package sam
import (
"fmt"
"github.com/pkg/errors"
"github.com/titpetric/factory"
)
var _ = errors.Wrap
const (
sqlUserScope = "suspended_at IS NULL AND archived_at IS NULL"
sqlUserSelect = "SELECT * FROM users WHERE " + sqlUserScope
)
func (*User) Read(r *teamReadRequest) (interface{}, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, err
}
t := User{}.new()
return t, db.Get(t, sqlUserSelect+" AND id = ?", r.id)
}
// User lookup & login
func (*User) Login(r *userLoginRequest) (interface{}, error) {
db, err := factory.Database.Get()
@@ -15,7 +31,7 @@ func (*User) Login(r *userLoginRequest) (interface{}, error) {
}
u := &User{}
if err != db.Get(u, "SELECT * FROM users WHERE username = ?", r.username) {
if err != db.Get(u, sqlUserSelect+" AND username = ?", r.username) {
return nil, err
}
@@ -39,9 +55,39 @@ func (*User) Search(r *userSearchRequest) (interface{}, error) {
uu := []*User{}
if err != db.Get(uu, "SELECT * FROM users WHERE username LIKE ?", r.query+"%") {
if err != db.Get(uu, sqlUserSelect+" AND username LIKE ?", r.query+"%") {
return nil, err
}
return uu, nil
}
func (*User) Remove(r *teamRemoveRequest) (interface{}, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, err
}
stmt := "UPDATE users SET deleted_at = NOW() WHERE deleted_at IS NULL AND id = ?"
return nil, func() error {
_, err := db.Exec(stmt, r.id)
return err
}()
}
func (*User) Archive(r *teamArchiveRequest) (interface{}, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, err
}
stmt := fmt.Sprintf(
"UPDATE users SET archived_at = NOW() WHERE %s AND id = ?",
sqlUserScope)
return nil, func() error {
_, err := db.Exec(stmt, r.id)
return err
}()
}

View File

@@ -2,6 +2,7 @@ package sam
import (
"golang.org/x/crypto/bcrypt"
"time"
)
// Users
@@ -10,6 +11,9 @@ type User struct {
Username string
Password []byte `json:"-"`
SuspendedAt *time.Time `json:",omitempty"`
DeletedAt *time.Time `json:",omitempty"`
changed []string
}