mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-07 23:00:55 +03:00
WebAdmin: allow to pre-select groups on add user page
The admin will still be able to choose different groups Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
@@ -35,7 +35,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
boltDatabaseVersion = 21
|
||||
boltDatabaseVersion = 22
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -372,6 +372,10 @@ func (p *BoltProvider) addAdmin(admin *Admin) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
groupBucket, err := p.getGroupsBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if a := bucket.Get([]byte(admin.Username)); a != nil {
|
||||
return fmt.Errorf("admin %v already exists", admin.Username)
|
||||
}
|
||||
@@ -383,6 +387,12 @@ func (p *BoltProvider) addAdmin(admin *Admin) error {
|
||||
admin.LastLogin = 0
|
||||
admin.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
|
||||
admin.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
|
||||
for idx := range admin.Groups {
|
||||
err = p.addAdminToGroupMapping(admin.Username, admin.Groups[idx].Name, groupBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
buf, err := json.Marshal(admin)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -401,8 +411,11 @@ func (p *BoltProvider) updateAdmin(admin *Admin) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
groupBucket, err := p.getGroupsBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var a []byte
|
||||
|
||||
if a = bucket.Get([]byte(admin.Username)); a == nil {
|
||||
return util.NewRecordNotFoundError(fmt.Sprintf("admin %v does not exist", admin.Username))
|
||||
}
|
||||
@@ -412,6 +425,18 @@ func (p *BoltProvider) updateAdmin(admin *Admin) error {
|
||||
return err
|
||||
}
|
||||
|
||||
for idx := range oldAdmin.Groups {
|
||||
err = p.removeAdminFromGroupMapping(oldAdmin.Username, oldAdmin.Groups[idx].Name, groupBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for idx := range admin.Groups {
|
||||
err = p.addAdminToGroupMapping(admin.Username, admin.Groups[idx].Name, groupBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
admin.ID = oldAdmin.ID
|
||||
admin.CreatedAt = oldAdmin.CreatedAt
|
||||
admin.LastLogin = oldAdmin.LastLogin
|
||||
@@ -431,9 +456,27 @@ func (p *BoltProvider) deleteAdmin(admin Admin) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if bucket.Get([]byte(admin.Username)) == nil {
|
||||
var a []byte
|
||||
if a = bucket.Get([]byte(admin.Username)); a == nil {
|
||||
return util.NewRecordNotFoundError(fmt.Sprintf("admin %v does not exist", admin.Username))
|
||||
}
|
||||
var oldAdmin Admin
|
||||
err = json.Unmarshal(a, &oldAdmin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(oldAdmin.Groups) > 0 {
|
||||
groupBucket, err := p.getGroupsBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for idx := range oldAdmin.Groups {
|
||||
err = p.removeAdminFromGroupMapping(oldAdmin.Username, oldAdmin.Groups[idx].Name, groupBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := p.deleteRelatedAPIKey(tx, admin.Username, APIKeyScopeAdmin); err != nil {
|
||||
return err
|
||||
@@ -1014,6 +1057,7 @@ func (p *BoltProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return fmt.Errorf("folder %v already exists", folder.Name)
|
||||
}
|
||||
folder.Users = nil
|
||||
folder.Groups = nil
|
||||
return p.addFolderInternal(*folder, bucket)
|
||||
})
|
||||
}
|
||||
@@ -1044,6 +1088,7 @@ func (p *BoltProvider) updateFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
folder.UsedQuotaFiles = oldFolder.UsedQuotaFiles
|
||||
folder.UsedQuotaSize = oldFolder.UsedQuotaSize
|
||||
folder.Users = oldFolder.Users
|
||||
folder.Groups = oldFolder.Groups
|
||||
buf, err := json.Marshal(folder)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1332,6 +1377,8 @@ func (p *BoltProvider) addGroup(group *Group) error {
|
||||
group.ID = int64(id)
|
||||
group.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
|
||||
group.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
|
||||
group.Users = nil
|
||||
group.Admins = nil
|
||||
for idx := range group.VirtualFolders {
|
||||
err = p.addRelationToFolderMapping(&group.VirtualFolders[idx].BaseVirtualFolder, nil, group, foldersBucket)
|
||||
if err != nil {
|
||||
@@ -1383,6 +1430,7 @@ func (p *BoltProvider) updateGroup(group *Group) error {
|
||||
group.ID = oldGroup.ID
|
||||
group.CreatedAt = oldGroup.CreatedAt
|
||||
group.Users = oldGroup.Users
|
||||
group.Admins = oldGroup.Admins
|
||||
group.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
|
||||
buf, err := json.Marshal(group)
|
||||
if err != nil {
|
||||
@@ -1408,17 +1456,31 @@ func (p *BoltProvider) deleteGroup(group Group) error {
|
||||
return err
|
||||
}
|
||||
if len(oldGroup.Users) > 0 {
|
||||
return util.NewValidationError(fmt.Sprintf("the group %#v is referenced, it cannot be removed", group.Name))
|
||||
return util.NewValidationError(fmt.Sprintf("the group %#v is referenced, it cannot be removed", oldGroup.Name))
|
||||
}
|
||||
foldersBucket, err := p.getFoldersBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for idx := range group.VirtualFolders {
|
||||
err = p.removeRelationFromFolderMapping(group.VirtualFolders[idx], "", group.Name, foldersBucket)
|
||||
if len(oldGroup.VirtualFolders) > 0 {
|
||||
foldersBucket, err := p.getFoldersBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for idx := range oldGroup.VirtualFolders {
|
||||
err = p.removeRelationFromFolderMapping(oldGroup.VirtualFolders[idx], "", oldGroup.Name, foldersBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(oldGroup.Admins) > 0 {
|
||||
adminsBucket, err := p.getAdminsBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for idx := range oldGroup.Admins {
|
||||
err = p.removeGroupFromAdminMapping(oldGroup.Name, oldGroup.Admins[idx], adminsBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bucket.Delete([]byte(group.Name))
|
||||
@@ -2517,23 +2579,23 @@ func (p *BoltProvider) migrateDatabase() error {
|
||||
providerLog(logger.LevelDebug, "bolt database is up to date, current version: %v", version)
|
||||
return ErrNoInitRequired
|
||||
case version < 19:
|
||||
err = fmt.Errorf("database version %v is too old, please see the upgrading docs", version)
|
||||
err = fmt.Errorf("database schema version %v is too old, please see the upgrading docs", version)
|
||||
providerLog(logger.LevelError, "%v", err)
|
||||
logger.ErrorToConsole("%v", err)
|
||||
return err
|
||||
case version == 19, version == 20:
|
||||
logger.InfoToConsole(fmt.Sprintf("updating database version: %d -> 21", version))
|
||||
providerLog(logger.LevelInfo, "updating database version: %d -> 21", version)
|
||||
return updateBoltDatabaseVersion(p.dbHandle, 21)
|
||||
case version == 19, version == 20, version == 21:
|
||||
logger.InfoToConsole(fmt.Sprintf("updating database schema version: %d -> 22", version))
|
||||
providerLog(logger.LevelInfo, "updating database schema version: %d -> 22", version)
|
||||
return updateBoltDatabaseVersion(p.dbHandle, 22)
|
||||
default:
|
||||
if version > boltDatabaseVersion {
|
||||
providerLog(logger.LevelError, "database version %v is newer than the supported one: %v", version,
|
||||
providerLog(logger.LevelError, "database schema version %v is newer than the supported one: %v", version,
|
||||
boltDatabaseVersion)
|
||||
logger.WarnToConsole("database version %v is newer than the supported one: %v", version,
|
||||
logger.WarnToConsole("database schema version %v is newer than the supported one: %v", version,
|
||||
boltDatabaseVersion)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("database version not handled: %v", version)
|
||||
return fmt.Errorf("database schema version not handled: %v", version)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2547,8 +2609,8 @@ func (p *BoltProvider) revertDatabase(targetVersion int) error {
|
||||
}
|
||||
switch dbVersion.Version {
|
||||
case 20, 21:
|
||||
logger.InfoToConsole("downgrading database version: %d -> 19", dbVersion.Version)
|
||||
providerLog(logger.LevelInfo, "downgrading database version: %d -> 19", dbVersion.Version)
|
||||
logger.InfoToConsole("downgrading database schema version: %d -> 19", dbVersion.Version)
|
||||
providerLog(logger.LevelInfo, "downgrading database schema version: %d -> 19", dbVersion.Version)
|
||||
err := p.dbHandle.Update(func(tx *bolt.Tx) error {
|
||||
for _, bucketName := range [][]byte{actionsBucket, rulesBucket} {
|
||||
err := tx.DeleteBucket(bucketName)
|
||||
@@ -2563,7 +2625,7 @@ func (p *BoltProvider) revertDatabase(targetVersion int) error {
|
||||
}
|
||||
return updateBoltDatabaseVersion(p.dbHandle, 19)
|
||||
default:
|
||||
return fmt.Errorf("database version not handled: %v", dbVersion.Version)
|
||||
return fmt.Errorf("database schema version not handled: %v", dbVersion.Version)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2766,14 +2828,32 @@ func (p *BoltProvider) removeUserFromGroupMapping(username, groupname string, bu
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if util.Contains(group.Users, username) {
|
||||
var users []string
|
||||
for _, u := range group.Users {
|
||||
if u != username {
|
||||
users = append(users, u)
|
||||
}
|
||||
var users []string
|
||||
for _, u := range group.Users {
|
||||
if u != username {
|
||||
users = append(users, u)
|
||||
}
|
||||
group.Users = util.RemoveDuplicates(users, false)
|
||||
}
|
||||
group.Users = util.RemoveDuplicates(users, false)
|
||||
buf, err := json.Marshal(group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return bucket.Put([]byte(group.Name), buf)
|
||||
}
|
||||
|
||||
func (p *BoltProvider) addAdminToGroupMapping(username, groupname string, bucket *bolt.Bucket) error {
|
||||
g := bucket.Get([]byte(groupname))
|
||||
if g == nil {
|
||||
return util.NewRecordNotFoundError(fmt.Sprintf("group %q does not exist", groupname))
|
||||
}
|
||||
var group Group
|
||||
err := json.Unmarshal(g, &group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !util.Contains(group.Admins, username) {
|
||||
group.Admins = append(group.Admins, username)
|
||||
buf, err := json.Marshal(group)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -2783,6 +2863,55 @@ func (p *BoltProvider) removeUserFromGroupMapping(username, groupname string, bu
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *BoltProvider) removeAdminFromGroupMapping(username, groupname string, bucket *bolt.Bucket) error {
|
||||
g := bucket.Get([]byte(groupname))
|
||||
if g == nil {
|
||||
return util.NewRecordNotFoundError(fmt.Sprintf("group %q does not exist", groupname))
|
||||
}
|
||||
var group Group
|
||||
err := json.Unmarshal(g, &group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var admins []string
|
||||
for _, a := range group.Admins {
|
||||
if a != username {
|
||||
admins = append(admins, a)
|
||||
}
|
||||
}
|
||||
group.Admins = util.RemoveDuplicates(admins, false)
|
||||
buf, err := json.Marshal(group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return bucket.Put([]byte(group.Name), buf)
|
||||
}
|
||||
|
||||
func (p *BoltProvider) removeGroupFromAdminMapping(groupName, adminName string, bucket *bolt.Bucket) error {
|
||||
var a []byte
|
||||
if a = bucket.Get([]byte(adminName)); a == nil {
|
||||
// the admin does not exist so there is no associated group
|
||||
return nil
|
||||
}
|
||||
var admin Admin
|
||||
err := json.Unmarshal(a, &admin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var newGroups []AdminGroupMapping
|
||||
for _, g := range admin.Groups {
|
||||
if g.Name != groupName {
|
||||
newGroups = append(newGroups, g)
|
||||
}
|
||||
}
|
||||
admin.Groups = newGroups
|
||||
buf, err := json.Marshal(admin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return bucket.Put([]byte(adminName), buf)
|
||||
}
|
||||
|
||||
func (p *BoltProvider) addRelationToFolderMapping(baseFolder *vfs.BaseVirtualFolder, user *User, group *Group, bucket *bolt.Bucket) error {
|
||||
f := bucket.Get([]byte(baseFolder.Name))
|
||||
if f == nil {
|
||||
@@ -2836,7 +2965,7 @@ func (p *BoltProvider) removeRelationFromFolderMapping(folder vfs.VirtualFolder,
|
||||
return err
|
||||
}
|
||||
found := false
|
||||
if username != "" && util.Contains(baseFolder.Users, username) {
|
||||
if username != "" {
|
||||
found = true
|
||||
var newUserMapping []string
|
||||
for _, u := range baseFolder.Users {
|
||||
@@ -2846,7 +2975,7 @@ func (p *BoltProvider) removeRelationFromFolderMapping(folder vfs.VirtualFolder,
|
||||
}
|
||||
baseFolder.Users = newUserMapping
|
||||
}
|
||||
if groupname != "" && util.Contains(baseFolder.Groups, groupname) {
|
||||
if groupname != "" {
|
||||
found = true
|
||||
var newGroupMapping []string
|
||||
for _, g := range baseFolder.Groups {
|
||||
@@ -3066,7 +3195,7 @@ func getBoltDatabaseVersion(dbHandle *bolt.DB) (schemaVersion, error) {
|
||||
err := dbHandle.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket(dbVersionBucket)
|
||||
if bucket == nil {
|
||||
return fmt.Errorf("unable to find database version bucket")
|
||||
return fmt.Errorf("unable to find database schema version bucket")
|
||||
}
|
||||
v := bucket.Get(dbVersionKey)
|
||||
if v == nil {
|
||||
@@ -3084,7 +3213,7 @@ func updateBoltDatabaseVersion(dbHandle *bolt.DB, version int) error {
|
||||
err := dbHandle.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket(dbVersionBucket)
|
||||
if bucket == nil {
|
||||
return fmt.Errorf("unable to find database version bucket")
|
||||
return fmt.Errorf("unable to find database schema version bucket")
|
||||
}
|
||||
newDbVersion := schemaVersion{
|
||||
Version: version,
|
||||
|
||||
Reference in New Issue
Block a user