additional work on Import User Accounts (unfinished)
This commit is contained in:
@@ -655,6 +655,9 @@ func AmGetCommunityTx(ctx context.Context, tx *sqlx.Tx, id int32) (*Community, e
|
|||||||
func AmGetCommunityByAlias(ctx context.Context, alias string) (*Community, error) {
|
func AmGetCommunityByAlias(ctx context.Context, alias string) (*Community, error) {
|
||||||
var cid int32
|
var cid int32
|
||||||
if err := amdb.GetContext(ctx, &cid, "SELECT commid FROM communities WHERE alias = ?", alias); err != nil {
|
if err := amdb.GetContext(ctx, &cid, "SELECT commid FROM communities WHERE alias = ?", alias); err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = ErrNoCommunity
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return AmGetCommunity(ctx, cid)
|
return AmGetCommunity(ctx, cid)
|
||||||
@@ -672,6 +675,9 @@ func AmGetCommunityByAlias(ctx context.Context, alias string) (*Community, error
|
|||||||
func AmGetCommunityByAliasTx(ctx context.Context, tx *sqlx.Tx, alias string) (*Community, error) {
|
func AmGetCommunityByAliasTx(ctx context.Context, tx *sqlx.Tx, alias string) (*Community, error) {
|
||||||
var cid int32
|
var cid int32
|
||||||
if err := tx.GetContext(ctx, &cid, "SELECT commid FROM communities WHERE alias = ?", alias); err != nil {
|
if err := tx.GetContext(ctx, &cid, "SELECT commid FROM communities WHERE alias = ?", alias); err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = ErrNoCommunity
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return AmGetCommunityTx(ctx, tx, cid)
|
return AmGetCommunityTx(ctx, tx, cid)
|
||||||
|
|||||||
+19
-4
@@ -35,6 +35,9 @@ import (
|
|||||||
// ErrNoUser is an error returned if the user is not found in the database.
|
// ErrNoUser is an error returned if the user is not found in the database.
|
||||||
var ErrNoUser error = errors.New("no such user")
|
var ErrNoUser error = errors.New("no such user")
|
||||||
|
|
||||||
|
// ErrUserExists is an error returned if the user name already exists when trying to create a user.
|
||||||
|
var ErrUserExists error = errors.New("that user name already exists. Please try again")
|
||||||
|
|
||||||
// UserPrefs represents the user's preferences in a table (one row per user).
|
// UserPrefs represents the user's preferences in a table (one row per user).
|
||||||
type UserPrefs struct {
|
type UserPrefs struct {
|
||||||
Uid int32 `db:"uid"` // user ID
|
Uid int32 `db:"uid"` // user ID
|
||||||
@@ -63,14 +66,15 @@ func (p *UserPrefs) Save(ctx context.Context, u, setter *User, ipaddr string) er
|
|||||||
if u != nil && u.Uid != p.Uid {
|
if u != nil && u.Uid != p.Uid {
|
||||||
return errors.New("internal mismatch of IDs")
|
return errors.New("internal mismatch of IDs")
|
||||||
}
|
}
|
||||||
var old *UserPrefs
|
var old *UserPrefs = nil
|
||||||
if setter.Uid != u.Uid {
|
if setter.Uid != u.Uid {
|
||||||
var pref UserPrefs
|
var pref UserPrefs
|
||||||
err := amdb.GetContext(ctx, &pref, "SELECT * FROM userprefs WHERE uid = ?", u.Uid)
|
err := amdb.GetContext(ctx, &pref, "SELECT * FROM userprefs WHERE uid = ?", u.Uid)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
|
old = &pref
|
||||||
|
} else if err != sql.ErrNoRows {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
old = &pref
|
|
||||||
}
|
}
|
||||||
_, err := amdb.NamedExecContext(ctx, "UPDATE userprefs SET localeid = :localeid, tzid = :tzid WHERE uid = :uid", p)
|
_, err := amdb.NamedExecContext(ctx, "UPDATE userprefs SET localeid = :localeid, tzid = :tzid WHERE uid = :uid", p)
|
||||||
if err == nil && u != nil {
|
if err == nil && u != nil {
|
||||||
@@ -444,6 +448,17 @@ func (u *User) SetSecurityData(ctx context.Context, baseLevel uint16, lockout, v
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetHashedPassword sets the hashed password for the user. Should only be used by import.
|
||||||
|
func (u *User) SetHashedPassword(ctx context.Context, hashValue string) error {
|
||||||
|
u.Mutex.Lock()
|
||||||
|
defer u.Mutex.Unlock()
|
||||||
|
_, err := amdb.ExecContext(ctx, "UPDATE users SET passhash = ? WHERE uid = ?", hashValue, u.Uid)
|
||||||
|
if err != nil {
|
||||||
|
u.Passhash = hashValue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
/* AmGetUser returns a reference to the specified user.
|
/* AmGetUser returns a reference to the specified user.
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* ctx - Standard Go context value.
|
* ctx - Standard Go context value.
|
||||||
@@ -736,7 +751,7 @@ func AmCreateNewUser(ctx context.Context, username string, password string, remi
|
|||||||
err := tx.GetContext(ctx, &tmpuid, "SELECT uid FROM users WHERE username = ?", username)
|
err := tx.GetContext(ctx, &tmpuid, "SELECT uid FROM users WHERE username = ?", username)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Warnf("username \"%s\" already exists", username)
|
log.Warnf("username \"%s\" already exists", username)
|
||||||
return nil, errors.New("that user name already exists. Please try again")
|
return nil, ErrUserExists
|
||||||
} else if err != sql.ErrNoRows {
|
} else if err != sql.ErrNoRows {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ func VCardFromContactInfo(ctx context.Context, target *VCard, ci *database.Conta
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// VCardSetContactINfo fills the ContactInfo object with data from the VCard.
|
// VCardSetContactInfo fills the ContactInfo object with data from the VCard.
|
||||||
func VCardSetContactInfo(ci *database.ContactInfo, vc *VCard) {
|
func VCardSetContactInfo(ci *database.ContactInfo, vc *VCard) {
|
||||||
ci.GivenName = util.IIF(vc.Name.Given == "", nil, &vc.Name.Given)
|
ci.GivenName = util.IIF(vc.Name.Given == "", nil, &vc.Name.Given)
|
||||||
ci.FamilyName = util.IIF(vc.Name.Family == "", nil, &vc.Name.Family)
|
ci.FamilyName = util.IIF(vc.Name.Family == "", nil, &vc.Name.Family)
|
||||||
|
|||||||
+71
-1
@@ -198,7 +198,9 @@ func VIUStreamCommunityMemberList(ctx context.Context, w io.Writer, comm *databa
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VIUCreateUser creates a new user based on the import data.
|
||||||
func VIUCreateUser(ctx context.Context, udata *VIUUser, loader *database.User, ipaddr string) error {
|
func VIUCreateUser(ctx context.Context, udata *VIUUser, loader *database.User, ipaddr string) error {
|
||||||
|
// Do some initial error checking and pre-parsing.
|
||||||
if !database.AmIsValidAmsterdamID(udata.Username) {
|
if !database.AmIsValidAmsterdamID(udata.Username) {
|
||||||
return fmt.Errorf("the username \"%s\" is not a valid Amsterdam ID", udata.Username)
|
return fmt.Errorf("the username \"%s\" is not a valid Amsterdam ID", udata.Username)
|
||||||
}
|
}
|
||||||
@@ -220,11 +222,32 @@ func VIUCreateUser(ctx context.Context, udata *VIUUser, loader *database.User, i
|
|||||||
if udata.Password.Prehashed {
|
if udata.Password.Prehashed {
|
||||||
pwd = ""
|
pwd = ""
|
||||||
}
|
}
|
||||||
|
role := database.AmRole(udata.Options.Role)
|
||||||
|
if role == nil {
|
||||||
|
return fmt.Errorf("the security role \"%s\" is not found", udata.Options.Role)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the user and set its direct information.
|
||||||
user, err := database.AmCreateNewUser(ctx, udata.Username, pwd, udata.PasswordReminder, dob, ipaddr)
|
user, err := database.AmCreateNewUser(ctx, udata.Username, pwd, udata.PasswordReminder, dob, ipaddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = user.SetProfileData(ctx, udata.PasswordReminder, dob, util.IIF(udata.Description == "", nil, &udata.Description), loader, ipaddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = user.SetSecurityData(ctx, role.Level(), udata.Options.Locked, udata.Options.Confirmed, loader, ipaddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if udata.Password.Prehashed {
|
||||||
|
err = user.SetHashedPassword(ctx, udata.Password.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the contact info.
|
||||||
ci := database.AmNewUserContactInfo(user.Uid)
|
ci := database.AmNewUserContactInfo(user.Uid)
|
||||||
VCardSetContactInfo(ci, &(udata.VCard))
|
VCardSetContactInfo(ci, &(udata.VCard))
|
||||||
ci.PrivateAddr = udata.Options.HideAddr
|
ci.PrivateAddr = udata.Options.HideAddr
|
||||||
@@ -239,10 +262,57 @@ func VIUCreateUser(ctx context.Context, udata *VIUUser, loader *database.User, i
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// TODO
|
|
||||||
|
// Set the user preferences and flags.
|
||||||
|
prefs := database.UserPrefs{
|
||||||
|
Uid: user.Uid,
|
||||||
|
LocaleID: udata.Options.Locale,
|
||||||
|
TimeZoneID: udata.Options.ZoneHint,
|
||||||
|
}
|
||||||
|
err = prefs.Save(ctx, user, loader, ipaddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flags := util.NewOptionSet()
|
||||||
|
flags.Set(database.UserFlagDisallowSetPhoto, udata.Options.NoPhoto)
|
||||||
|
flags.Set(database.UserFlagMassMailOptOut, udata.Options.OptOut)
|
||||||
|
flags.Set(database.UserFlagPicturesInPosts, udata.Options.PostPictures)
|
||||||
|
err = user.SaveFlags(ctx, flags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Autojoin base communities.
|
||||||
|
if udata.Options.AutoJoin {
|
||||||
|
err := database.AmAutoJoinCommunities(ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set community membership based on the joins listed.
|
||||||
|
for _, j := range udata.Joins {
|
||||||
|
role = database.AmRole(j.Role)
|
||||||
|
if role == nil {
|
||||||
|
return fmt.Errorf("the security role \"%s\" is not found", udata.Options.Role)
|
||||||
|
}
|
||||||
|
comm, err := database.AmGetCommunityByAlias(ctx, j.Community)
|
||||||
|
if err == database.ErrNoCommunity {
|
||||||
|
log.Warnf("community \"%s\" not found, skipping", j.Community)
|
||||||
|
continue
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = comm.SetMembership(ctx, user, role.Level(), false, loader.Uid, ipaddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VIUImportUserList takes a list of user accounts in VIU XML format and imports them.
|
||||||
func VIUImportUserList(ctx context.Context, r io.Reader, loader *database.User, ipaddr string) (int, []string, error) {
|
func VIUImportUserList(ctx context.Context, r io.Reader, loader *database.User, ipaddr string) (int, []string, error) {
|
||||||
dec := xml.NewDecoder(r)
|
dec := xml.NewDecoder(r)
|
||||||
var importData VIUBase
|
var importData VIUBase
|
||||||
|
|||||||
+9
-1
@@ -21,6 +21,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.erbosoft.com/amy/amsterdam/database"
|
"git.erbosoft.com/amy/amsterdam/database"
|
||||||
|
"git.erbosoft.com/amy/amsterdam/exports"
|
||||||
"git.erbosoft.com/amy/amsterdam/ui"
|
"git.erbosoft.com/amy/amsterdam/ui"
|
||||||
"git.erbosoft.com/amy/amsterdam/util"
|
"git.erbosoft.com/amy/amsterdam/util"
|
||||||
"github.com/CloudyKit/jet/v6"
|
"github.com/CloudyKit/jet/v6"
|
||||||
@@ -792,8 +793,15 @@ func UserImport(ctxt ui.AmContext) (string, any) {
|
|||||||
ctxt.SetFrameTitle("Import User Accounts")
|
ctxt.SetFrameTitle("Import User Accounts")
|
||||||
return "framed", "import_users.jet"
|
return "framed", "import_users.jet"
|
||||||
}
|
}
|
||||||
|
count, scroll, err := exports.VIUImportUserList(ctxt.Ctx(), f, ctxt.CurrentUser(), ctxt.RemoteIP())
|
||||||
f.Close()
|
f.Close()
|
||||||
|
if err != nil {
|
||||||
|
ctxt.VarMap().Set("errorMessage", err.Error())
|
||||||
|
ctxt.SetFrameTitle("Import User Accounts")
|
||||||
|
return "framed", "import_users.jet"
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = count
|
||||||
|
_ = scroll
|
||||||
return "error", "Not yet implemented"
|
return "error", "Not yet implemented"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user