Add (suspended|archived|deleted)_at fields & logic everywhere
Took 1 minute
This commit is contained in:
@@ -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
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
|
||||
|
||||
@@ -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
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
package sam
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Organisations
|
||||
type Organisation struct {
|
||||
ID uint64
|
||||
Name string
|
||||
|
||||
ArchivedAt *time.Time
|
||||
DeletedAt *time.Time
|
||||
|
||||
changed []string
|
||||
}
|
||||
|
||||
|
||||
23
sam/team.go
23
sam/team.go
@@ -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
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
50
sam/user.go
50
sam/user.go
@@ -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
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user