3
0

upd(system-cli): roles reset with spf13/cobra

This commit is contained in:
Mitja Zivkovic
2019-03-18 11:51:01 +01:00
committed by Tit Petric
parent 78763c715d
commit 62933676dd
6 changed files with 205 additions and 219 deletions
+53
View File
@@ -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
View File
@@ -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()
}
-190
View File
@@ -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
}
+22
View File
@@ -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.")
}
+42
View File
@@ -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)
}
}
+83
View File
@@ -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
}