v0.2.0
This commit is contained in:
1 parent
23c7133fa9
commit
8c1b93c14e
16 files changed
+1187
-295
No files matched your search
@@ -0,0 +1,150 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
|
||||
"ssh-access-tui/internal/model"
|
||||
"ssh-access-tui/internal/sysadm"
|
||||
)
|
||||
|
||||
// updateConfirmAction drives the single generic "are you sure" screen that
|
||||
// backs every destructive action in the tool (lock/delete a user, delete a
|
||||
// host or a service). Nothing the action does runs until this confirms it;
|
||||
// esc/n cancels with zero effect.
|
||||
func (m Model) updateConfirmAction(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if key, ok := msg.(tea.KeyMsg); ok {
|
||||
switch key.String() {
|
||||
case "esc", "n":
|
||||
m.pendingConfirm = confirmNone
|
||||
m.screen = m.confirmReturnTo
|
||||
return m, nil
|
||||
case "enter", "y":
|
||||
return m.executeConfirmedAction()
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m Model) viewConfirmAction() string {
|
||||
body := warnStyle.Render("ТРЕБУЕТСЯ ПОДТВЕРЖДЕНИЕ") + "\n\n"
|
||||
body += m.confirmMessage + "\n\n"
|
||||
body += "[enter/y] подтвердить [esc/n] отмена, ничего не изменится"
|
||||
return borderStyle.Render(body)
|
||||
}
|
||||
|
||||
func (m Model) executeConfirmedAction() (tea.Model, tea.Cmd) {
|
||||
kind := m.pendingConfirm
|
||||
target := m.confirmTarget
|
||||
m.pendingConfirm = confirmNone
|
||||
m.err, m.status = "", ""
|
||||
|
||||
switch kind {
|
||||
case confirmLockUser:
|
||||
return m.doLockUser(target)
|
||||
case confirmDeleteUser:
|
||||
return m.doDeleteUser(target)
|
||||
case confirmDeleteHost:
|
||||
return m.doDeleteHost(target)
|
||||
case confirmDeleteService:
|
||||
return m.doDeleteService(target)
|
||||
}
|
||||
m.screen = m.confirmReturnTo
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m Model) doLockUser(username string) (tea.Model, tea.Cmd) {
|
||||
if err := sysadm.LockSystemUser(username); err != nil {
|
||||
m.err = err.Error()
|
||||
m.screen = scrUsers
|
||||
return m, nil
|
||||
}
|
||||
_ = sysadm.DisableAuthorizedKeys(username)
|
||||
m.mutate("заблокирован пользователь "+username, func(st *model.State) error {
|
||||
u := st.FindUser(username)
|
||||
if u == nil {
|
||||
return fmt.Errorf("user %s not found in state", username)
|
||||
}
|
||||
now := time.Now()
|
||||
u.Status = model.StatusLocked
|
||||
u.LockedAt = &now
|
||||
return nil
|
||||
})
|
||||
m.logAudit(username, "admin", "locked")
|
||||
m.screen = scrUsers
|
||||
m.refreshUsersList()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m Model) doDeleteUser(username string) (tea.Model, tea.Cmd) {
|
||||
if err := sysadm.DeleteSystemUser(username); err != nil {
|
||||
m.err = err.Error()
|
||||
m.screen = scrUsers
|
||||
return m, nil
|
||||
}
|
||||
m.mutate("удалён пользователь "+username, func(st *model.State) error {
|
||||
for i := range st.Users {
|
||||
if st.Users[i].Username == username {
|
||||
st.Users = append(st.Users[:i], st.Users[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
m.logAudit(username, "admin", "deleted")
|
||||
m.screen = scrUsers
|
||||
m.refreshUsersList()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// doDeleteHost removes a host (and all its services) from m.selectedGroup,
|
||||
// then resyncs authorized_keys for every affected user.
|
||||
func (m Model) doDeleteHost(hostName string) (tea.Model, tea.Cmd) {
|
||||
groupName := m.selectedGroup
|
||||
m.mutate(fmt.Sprintf("удалён хост %s из группы %s", hostName, groupName), func(st *model.State) error {
|
||||
g := st.FindGroup(groupName)
|
||||
if g == nil {
|
||||
return fmt.Errorf("group %s not found", groupName)
|
||||
}
|
||||
for i := range g.Hosts {
|
||||
if g.Hosts[i].Name == hostName {
|
||||
g.Hosts = append(g.Hosts[:i], g.Hosts[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
return resyncGroupUsers(st, groupName)
|
||||
})
|
||||
m.screen = scrGroupHosts
|
||||
m.refreshHostsList()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// doDeleteService removes a service from m.selectedHost within
|
||||
// m.selectedGroup, then resyncs authorized_keys for every affected user.
|
||||
func (m Model) doDeleteService(serviceName string) (tea.Model, tea.Cmd) {
|
||||
groupName, hostName := m.selectedGroup, m.selectedHost
|
||||
m.mutate(fmt.Sprintf("удалён сервис %s у хоста %s", serviceName, hostName), func(st *model.State) error {
|
||||
g := st.FindGroup(groupName)
|
||||
if g == nil {
|
||||
return fmt.Errorf("group %s not found", groupName)
|
||||
}
|
||||
for hi := range g.Hosts {
|
||||
if g.Hosts[hi].Name != hostName {
|
||||
continue
|
||||
}
|
||||
svcs := g.Hosts[hi].Services
|
||||
for si := range svcs {
|
||||
if svcs[si].Name == serviceName {
|
||||
g.Hosts[hi].Services = append(svcs[:si], svcs[si+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return resyncGroupUsers(st, groupName)
|
||||
})
|
||||
m.screen = scrHostServices
|
||||
m.refreshServicesList()
|
||||
return m, nil
|
||||
}
|
||||
Reference in new issue
Block a user