upd(system-cli): roles reset with spf13/cobra
This commit is contained in:
committed by
Tit Petric
parent
78763c715d
commit
62933676dd
@@ -0,0 +1,53 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
systemCli "github.com/crusttech/crust/system/cli"
|
||||
)
|
||||
|
||||
func setupCobra() {
|
||||
// Main command.
|
||||
rootCmd := &cobra.Command{Use: "system-cli"}
|
||||
|
||||
// User management commands.
|
||||
var cmdUsers = &cobra.Command{
|
||||
Use: "users",
|
||||
Short: "User management",
|
||||
}
|
||||
rootCmd.AddCommand(cmdUsers)
|
||||
|
||||
// List users.
|
||||
var cmdUsersList = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List users",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
systemCli.UsersList()
|
||||
},
|
||||
}
|
||||
cmdUsers.AddCommand(cmdUsersList)
|
||||
|
||||
// Role management commands.
|
||||
var cmdRole = &cobra.Command{
|
||||
Use: "roles",
|
||||
Short: "Role management",
|
||||
}
|
||||
rootCmd.AddCommand(cmdRole)
|
||||
|
||||
// Reset permissions.
|
||||
var cmdRolesReset = &cobra.Command{
|
||||
Use: "reset",
|
||||
Short: "Reset roles",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
systemCli.RolesReset()
|
||||
},
|
||||
}
|
||||
cmdRole.AddCommand(cmdRolesReset)
|
||||
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
+5
-29
@@ -4,10 +4,9 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/crusttech/crust/system"
|
||||
systemService "github.com/crusttech/crust/system/service"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
system "github.com/crusttech/crust/system"
|
||||
systemService "github.com/crusttech/crust/system/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -15,33 +14,10 @@ func main() {
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
|
||||
flags("system", service.Flags, auth.Flags)
|
||||
flags("system", system.Flags, auth.Flags)
|
||||
|
||||
service.InitDatabase()
|
||||
system.InitDatabase()
|
||||
systemService.Init()
|
||||
|
||||
var commands []string
|
||||
if len(os.Args) > 0 {
|
||||
// @todo migrate to a proper solution (eg: https://github.com/spf13/cobra)
|
||||
commands = os.Args[1:]
|
||||
for a, arg := range os.Args {
|
||||
if arg == "--" && a+1 < len(os.Args) {
|
||||
commands = os.Args[a+1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cliRouter(commands...)
|
||||
}
|
||||
|
||||
func cliRouter(commands ...string) {
|
||||
if len(commands) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
switch commands[0] {
|
||||
case "users":
|
||||
cliExecUsers(commands[1:]...)
|
||||
default:
|
||||
}
|
||||
setupCobra()
|
||||
}
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
crmRepository "github.com/crusttech/crust/crm/repository"
|
||||
"github.com/crusttech/crust/internal/payload"
|
||||
messagingRepository "github.com/crusttech/crust/messaging/repository"
|
||||
"github.com/crusttech/crust/system/service"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
func cliExecUsers(commands ...string) {
|
||||
if len(commands) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
switch commands[0] {
|
||||
case "list":
|
||||
cliExecUsersList(commands[1:]...)
|
||||
case "merge":
|
||||
cliExecUsersMerge(commands[1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
func cliExecUsersList(params ...string) {
|
||||
var (
|
||||
upd, del string
|
||||
|
||||
err error
|
||||
uu types.UserSet
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
uf := &types.UserFilter{
|
||||
OrderBy: "updated_at",
|
||||
}
|
||||
|
||||
if uu, err = service.DefaultUser.With(ctx).Find(uf); err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("ID Updated Deleted [email / name / username]")
|
||||
for _, u := range uu {
|
||||
upd, del = "---- -- --", "---- -- --"
|
||||
|
||||
if u.UpdatedAt != nil {
|
||||
upd = u.UpdatedAt.Format("2006-01-02")
|
||||
}
|
||||
|
||||
if u.DeletedAt != nil {
|
||||
upd = u.DeletedAt.Format("2006-01-02")
|
||||
}
|
||||
|
||||
fmt.Printf(
|
||||
"%20d %s %s %s\n",
|
||||
u.ID,
|
||||
upd,
|
||||
del,
|
||||
u.Email+" / "+u.Name+" / "+u.Username)
|
||||
}
|
||||
}
|
||||
|
||||
func cliExecUsersMerge(params ...string) {
|
||||
var (
|
||||
err error
|
||||
uu = make([]*types.User, len(params))
|
||||
refs = make([]*userRefs, len(params))
|
||||
ids = payload.ParseUInt64s(params)
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
if len(ids) < 2 {
|
||||
fmt.Printf("Expecting 2+ user IDs (2nd, 3rd ... user ID will be merged into first one\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for i, id := range ids {
|
||||
if id == 0 {
|
||||
fmt.Printf("Error: Invalid user ID %q\n", params[i])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if uu[i], err = service.DefaultUser.With(ctx).FindByID(id); err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
db := messagingRepository.DB(ctx)
|
||||
|
||||
mergers := []struct {
|
||||
label string
|
||||
count func(userID uint64) (c int, err error)
|
||||
merge func(userID, target uint64) (err error)
|
||||
}{
|
||||
{label: "MsgOw",
|
||||
count: messagingRepository.Message(ctx, db).CountOwned,
|
||||
merge: messagingRepository.Message(ctx, db).ChangeOwner},
|
||||
{label: "MTags",
|
||||
count: messagingRepository.Message(ctx, db).CountUserTags,
|
||||
merge: messagingRepository.Message(ctx, db).ChangeUserTag},
|
||||
{label: "ChCre",
|
||||
count: messagingRepository.Channel(ctx, db).CountCreated,
|
||||
merge: messagingRepository.Channel(ctx, db).ChangeCreator},
|
||||
{label: "Membr",
|
||||
count: messagingRepository.ChannelMember(ctx, db).CountMemberships,
|
||||
merge: messagingRepository.ChannelMember(ctx, db).ChangeMembership},
|
||||
{label: "AttOw",
|
||||
count: messagingRepository.Attachment(ctx, db).CountOwned,
|
||||
merge: messagingRepository.Attachment(ctx, db).ChangeOwnership},
|
||||
{label: "Menti",
|
||||
count: messagingRepository.Mention(ctx, db).CountMentions,
|
||||
merge: messagingRepository.Mention(ctx, db).ChangeMention},
|
||||
{label: "Unrd",
|
||||
count: messagingRepository.Unread(ctx, db).CountOwned,
|
||||
merge: messagingRepository.Unread(ctx, db).ChangeOwner},
|
||||
{label: "CRAut",
|
||||
count: crmRepository.Record(ctx, db).CountAuthored,
|
||||
merge: crmRepository.Record(ctx, db).ChangeAuthor},
|
||||
{label: "CRRef",
|
||||
count: crmRepository.Record(ctx, db).CountReferenced,
|
||||
merge: crmRepository.Record(ctx, db).ChangeReferences},
|
||||
}
|
||||
|
||||
count := func(u *types.User, r *userRefs) (out string) {
|
||||
out = fmt.Sprintf(
|
||||
"%20d | %-40s",
|
||||
u.ID,
|
||||
u.Email+" / "+u.Name+" / "+u.Username,
|
||||
)
|
||||
|
||||
for _, m := range mergers {
|
||||
if count, err := m.count(u.ID); err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
} else {
|
||||
out = out + fmt.Sprintf(" | %5d", count)
|
||||
}
|
||||
}
|
||||
|
||||
return out + fmt.Sprintln()
|
||||
}
|
||||
|
||||
stats := fmt.Sprintf(
|
||||
"%20s | %40s",
|
||||
"ID",
|
||||
"Email",
|
||||
)
|
||||
|
||||
for _, m := range mergers {
|
||||
stats = stats + fmt.Sprintf(" | %5s", m.label)
|
||||
}
|
||||
|
||||
stats = stats + fmt.Sprintln() + fmt.Sprintf("Merge %d users:\n", len(uu)-1)
|
||||
for i := 1; i < len(uu); i++ {
|
||||
stats = stats + count(uu[i], refs[i])
|
||||
}
|
||||
stats = stats + fmt.Sprintln("Target") + count(uu[0], refs[0])
|
||||
|
||||
fmt.Println(stats)
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print("Merge [y/N]? ")
|
||||
text, _ := reader.ReadByte()
|
||||
if "y" != strings.ToLower(string(text)) {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
for i := 1; i < len(uu); i++ {
|
||||
for _, m := range mergers {
|
||||
if err := m.merge(uu[i].ID, uu[0].ID); err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Done.")
|
||||
}
|
||||
|
||||
type userRefs struct {
|
||||
messagesCreated int
|
||||
messagesTagged int
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
)
|
||||
|
||||
func RolesReset() {
|
||||
ctx := context.Background()
|
||||
db := repository.DB(ctx)
|
||||
|
||||
err := repository.Role(ctx, db).Reset()
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("Everyone and Administrators role were reset.")
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/crusttech/crust/system/service"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
func UsersList() {
|
||||
uf := &types.UserFilter{
|
||||
OrderBy: "updated_at",
|
||||
}
|
||||
|
||||
users, err := service.DefaultUser.With(context.Background()).Find(uf)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("ID Updated Deleted [email / name / username]")
|
||||
for _, u := range users {
|
||||
upd, del := "---- -- --", "---- -- --"
|
||||
|
||||
if u.UpdatedAt != nil {
|
||||
upd = u.UpdatedAt.Format("2006-01-02")
|
||||
}
|
||||
|
||||
if u.DeletedAt != nil {
|
||||
upd = u.DeletedAt.Format("2006-01-02")
|
||||
}
|
||||
|
||||
fmt.Printf(
|
||||
"%20d %s %s %s\n",
|
||||
u.ID,
|
||||
upd,
|
||||
del,
|
||||
u.Email+" / "+u.Name+" / "+u.Username)
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,8 @@ type (
|
||||
MemberFindByRoleID(roleID uint64) ([]*types.RoleMember, error)
|
||||
MemberAddByID(roleID, userID uint64) error
|
||||
MemberRemoveByID(roleID, userID uint64) error
|
||||
|
||||
Reset() error
|
||||
}
|
||||
|
||||
role struct {
|
||||
@@ -147,3 +149,84 @@ func (r *role) MemberRemoveByID(roleID, userID uint64) error {
|
||||
}
|
||||
return r.db().Delete(r.members, mod, "rel_role", "rel_user")
|
||||
}
|
||||
|
||||
func (r *role) Reset() error {
|
||||
sql := `REPLACE INTO sys_role (id, name, handle) VALUES
|
||||
(1, 'Everyone', 'everyone'),
|
||||
(2, 'Administrators', 'admins')
|
||||
`
|
||||
_, err := r.db().Exec(sql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Value: Allow (2), Deny (1), Inherit(0)
|
||||
sql = `REPLACE INTO sys_rules (rel_role, resource, operation, value) VALUES
|
||||
-- Everyone
|
||||
(1, 'compose:*', 'access', 2),
|
||||
(1, 'messaging:*', 'access', 2),
|
||||
-- Admins
|
||||
(2, 'compose', 'namespace.create', 2),
|
||||
(2, 'compose', 'access', 2),
|
||||
(2, 'compose', 'grant', 2),
|
||||
(2, 'compose:namespace:*', 'page.create', 2),
|
||||
(2, 'compose:namespace:*', 'read', 2),
|
||||
(2, 'compose:namespace:*', 'update', 2),
|
||||
(2, 'compose:namespace:*', 'delete', 2),
|
||||
(2, 'compose:namespace:*', 'module.create', 2),
|
||||
(2, 'compose:namespace:*', 'chart.create', 2),
|
||||
(2, 'compose:namespace:*', 'trigger.create', 2),
|
||||
(2, 'compose:chart:*', 'read', 2),
|
||||
(2, 'compose:chart:*', 'update', 2),
|
||||
(2, 'compose:chart:*', 'delete', 2),
|
||||
(2, 'compose:trigger:*', 'read', 2),
|
||||
(2, 'compose:trigger:*', 'update', 2),
|
||||
(2, 'compose:trigger:*', 'delete', 2),
|
||||
(2, 'compose:page:*', 'read', 2),
|
||||
(2, 'compose:page:*', 'update', 2),
|
||||
(2, 'compose:page:*', 'delete', 2),
|
||||
(2, 'system', 'access', 2),
|
||||
(2, 'system', 'grant', 2),
|
||||
(2, 'system', 'organisation.create', 2),
|
||||
(2, 'system', 'role.create', 2),
|
||||
(2, 'system:organisation:*', 'access', 2),
|
||||
(2, 'system:role:*', 'read', 2),
|
||||
(2, 'system:role:*', 'update', 2),
|
||||
(2, 'system:role:*', 'delete', 2),
|
||||
(2, 'system:role:*', 'members.manage', 2),
|
||||
(2, 'messaging', 'access', 2),
|
||||
(2, 'messaging', 'grant', 2),
|
||||
(2, 'messaging', 'channel.public.create', 2),
|
||||
(2, 'messaging', 'channel.private.create', 2),
|
||||
(2, 'messaging', 'channel.group.create', 2),
|
||||
(2, 'messaging:channel:*', 'update', 2),
|
||||
(2, 'messaging:channel:*', 'leave', 2),
|
||||
(2, 'messaging:channel:*', 'read', 2),
|
||||
(2, 'messaging:channel:*', 'join', 2),
|
||||
(2, 'messaging:channel:*', 'delete', 2),
|
||||
(2, 'messaging:channel:*', 'undelete', 2),
|
||||
(2, 'messaging:channel:*', 'archive', 2),
|
||||
(2, 'messaging:channel:*', 'unarchive', 2),
|
||||
(2, 'messaging:channel:*', 'members.manage', 2),
|
||||
(2, 'messaging:channel:*', 'webhooks.manage', 2),
|
||||
(2, 'messaging:channel:*', 'attachments.manage', 2),
|
||||
(2, 'messaging:channel:*', 'message.attach', 2),
|
||||
(2, 'messaging:channel:*', 'message.update.all', 2),
|
||||
(2, 'messaging:channel:*', 'message.update.own', 2),
|
||||
(2, 'messaging:channel:*', 'message.delete.all', 2),
|
||||
(2, 'messaging:channel:*', 'message.delete.own', 2),
|
||||
(2, 'messaging:channel:*', 'message.embed', 2),
|
||||
(2, 'messaging:channel:*', 'message.send', 2),
|
||||
(2, 'messaging:channel:*', 'message.reply', 2),
|
||||
(2, 'messaging:channel:*', 'message.react', 2),
|
||||
(2, 'compose:module:*', 'read', 2),
|
||||
(2, 'compose:module:*', 'update', 2),
|
||||
(2, 'compose:module:*', 'delete', 2),
|
||||
(2, 'compose:module:*', 'record.create', 2),
|
||||
(2, 'compose:module:*', 'record.read', 2),
|
||||
(2, 'compose:module:*', 'record.update', 2),
|
||||
(2, 'compose:module:*', 'record.delete', 2)
|
||||
`
|
||||
_, err = r.db().Exec(sql)
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user