add in-memory DB for accounts, with tests!

This commit is contained in:
ari melody 2026-07-31 04:20:39 +01:00
parent 49e14b5bc5
commit 5a540184c9
Signed by: ari
GPG key ID: CF99829C92678188
9 changed files with 534 additions and 45 deletions

View file

@ -0,0 +1,185 @@
package account
import (
"arimelody-web/model"
"database/sql"
"errors"
"strconv"
)
type (
AccountRepositoryMemory struct {
accounts []*model.Account
}
)
var _ AccountRepository = new(AccountRepositoryMemory)
func NewAccountRepositoryMemory() *AccountRepositoryMemory {
return &AccountRepositoryMemory{ accounts: make([]*model.Account, 0) }
}
func (repo *AccountRepositoryMemory) GetAll() ([]*model.Account, error) {
return repo.accounts, nil
}
func (repo *AccountRepositoryMemory) GetCount() (int, error) {
return len(repo.accounts), nil
}
func (repo *AccountRepositoryMemory) GetByID(id string) (*model.Account, error) {
for _, account := range repo.accounts {
if account.ID == id { return account, nil }
}
return nil, nil
}
func (repo *AccountRepositoryMemory) GetByUsername(username string) (*model.Account, error) {
for _, account := range repo.accounts {
if account.Username == username { return account, nil }
}
return nil, nil
}
func (repo *AccountRepositoryMemory) GetByEmail(email string) (*model.Account, error) {
for _, account := range repo.accounts {
if account.Email.Valid && account.Email.String == email {
return account, nil
}
}
return nil, nil
}
// Create an account, returning the new account ID.
func (repo *AccountRepositoryMemory) Create(username string, password string, email *string, avatarURL *string) (string, error) {
if account, err := repo.GetByUsername(username); err != nil {
return "", errors.New("Failed to fetch other acccounts by username")
} else if account != nil {
return "", errors.New("Account with this username already exists")
}
emailRef := ""
if email != nil { emailRef = *email }
avatarURLRef := ""
if avatarURL != nil { avatarURLRef = *avatarURL }
id := strconv.Itoa(len(repo.accounts))
repo.accounts = append(repo.accounts, &model.Account{
ID: id,
Username: username,
Password: password,
Email: sql.NullString{ String: emailRef, Valid: email != nil },
AvatarURL: sql.NullString{ String: avatarURLRef, Valid: avatarURL != nil },
})
return id, nil
}
// Intended for large profile updates. For smaller adjusments,
// more specialised Change* and Remove* functions should be used.
func (repo *AccountRepositoryMemory) Update(id string, username string, password string, email *string, avatarUrl *string) error {
if account, err := repo.GetByUsername(username); err != nil {
return errors.New("Failed to fetch other acccounts by username")
} else if account != nil && account.ID != id {
return errors.New("Account with this username already exists")
}
account, err := repo.GetByID(id)
if err != nil { return err }
account.Username = username
account.Password = password
account.Email.Valid = email != nil
if account.Email.Valid { account.Email.String = *email }
account.AvatarURL.Valid = avatarUrl != nil
if account.AvatarURL.Valid { account.AvatarURL.String = *avatarUrl }
return nil
}
func (repo *AccountRepositoryMemory) ChangeUsername(id string, username string) error {
if account, err := repo.GetByUsername(username); err != nil {
return errors.New("Failed to fetch other acccounts by username")
} else if account != nil && account.ID != id {
return errors.New("Account with this username already exists")
}
account, err := repo.GetByID(id)
if err != nil { return err }
account.Username = username
return nil
}
func (repo *AccountRepositoryMemory) ChangePassword(id string, password string) error {
account, err := repo.GetByID(id)
if err != nil { return err }
account.Password = password
return nil
}
func (repo *AccountRepositoryMemory) ChangeEmail(id string, email string) error {
account, err := repo.GetByID(id)
if err != nil { return err }
account.Email.Valid = true
account.Email.String = email
return nil
}
func (repo *AccountRepositoryMemory) RemoveEmail(id string) error {
account, err := repo.GetByID(id)
if err != nil { return err }
account.Email.Valid = false
account.Email.String = ""
return nil
}
func (repo *AccountRepositoryMemory) ChangeAvatarURL(id string, avatarURL string) error {
account, err := repo.GetByID(id)
if err != nil { return err }
account.AvatarURL.Valid = true
account.AvatarURL.String = avatarURL
return nil
}
func (repo *AccountRepositoryMemory) RemoveAvatar(id string) error {
account, err := repo.GetByID(id)
if err != nil { return err }
account.AvatarURL.Valid = false
account.AvatarURL.String = ""
return nil
}
func (repo *AccountRepositoryMemory) Delete(id string) error {
accountIndex := -1
for index, account := range repo.accounts {
if account.ID == id {
accountIndex = index
break
}
}
if accountIndex == -1 { return nil }
repo.accounts = append(
repo.accounts[:accountIndex],
repo.accounts[accountIndex+1:]...,
)
return nil
}
// Increment the number of account login failure attempts,
// returning the current fail count.
func (repo *AccountRepositoryMemory) IncrementFails(id string) (int, error) {
account, err := repo.GetByID(id)
if err != nil { return 0, err }
account.FailAttempts += 1
return account.FailAttempts, nil
}
func (repo *AccountRepositoryMemory) ResetFails(id string) error {
account, err := repo.GetByID(id)
if err != nil { return err }
account.FailAttempts = 0
return nil
}
func (repo *AccountRepositoryMemory) Lock(id string) error {
account, err := repo.GetByID(id)
if err != nil { return err }
account.Locked = true
return nil
}
func (repo *AccountRepositoryMemory) Unlock(id string) error {
account, err := repo.GetByID(id)
if err != nil { return err }
account.Locked = false
return nil
}