feat(db): enable sqlite for storing users
This commit is contained in:
parent
f95a611204
commit
59a39efc4a
10 changed files with 791 additions and 59 deletions
|
@ -50,3 +50,4 @@ site:
|
||||||
align: "fixed"
|
align: "fixed"
|
||||||
db:
|
db:
|
||||||
dbPath: "tmp/quickshare.db"
|
dbPath: "tmp/quickshare.db"
|
||||||
|
dbType: "rdb"
|
|
@ -1,6 +1,7 @@
|
||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -157,6 +158,25 @@ type UploadInfo struct {
|
||||||
Uploaded int64 `json:"uploaded" yaml:"uploaded"`
|
Uploaded int64 `json:"uploaded" yaml:"uploaded"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IUserStore interface {
|
||||||
|
Init(ctx context.Context, rootName, rootPwd string) error
|
||||||
|
IsInited() bool
|
||||||
|
AddUser(ctx context.Context, user *User) error
|
||||||
|
DelUser(ctx context.Context, id uint64) error
|
||||||
|
GetUser(ctx context.Context, id uint64) (*User, error)
|
||||||
|
GetUserByName(ctx context.Context, name string) (*User, error)
|
||||||
|
SetInfo(ctx context.Context, id uint64, user *User) error
|
||||||
|
SetUsed(ctx context.Context, id uint64, incr bool, capacity int64) error
|
||||||
|
ResetUsed(ctx context.Context, id uint64, used int64) error
|
||||||
|
SetPwd(ctx context.Context, id uint64, pwd string) error
|
||||||
|
SetPreferences(ctx context.Context, id uint64, settings *Preferences) error
|
||||||
|
ListUsers(context.Context) ([]*User, error)
|
||||||
|
ListUserIDs(context.Context) (map[string]string, error)
|
||||||
|
AddRole(role string) error
|
||||||
|
DelRole(role string) error
|
||||||
|
ListRoles() (map[string]bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
func ComparePreferences(p1, p2 *Preferences) bool {
|
func ComparePreferences(p1, p2 *Preferences) bool {
|
||||||
return p1.CSSURL == p2.CSSURL &&
|
return p1.CSSURL == p2.CSSURL &&
|
||||||
p1.LanPackURL == p2.LanPackURL &&
|
p1.LanPackURL == p2.LanPackURL &&
|
||||||
|
|
|
@ -2,6 +2,7 @@ package sqlite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
|
||||||
"github.com/ihexxa/quickshare/src/db/rdb"
|
"github.com/ihexxa/quickshare/src/db/rdb"
|
||||||
|
@ -13,7 +14,7 @@ type SQLite struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSQLite(dbPath string) (*SQLite, error) {
|
func NewSQLite(dbPath string) (*SQLite, error) {
|
||||||
db, err := sql.Open("sqlite3", dbPath)
|
db, err := sql.Open("sqlite3", fmt.Sprintf("%s?_synchronous=FULL", dbPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
418
src/db/rdb/sqlite/users.go
Normal file
418
src/db/rdb/sqlite/users.go
Normal file
|
@ -0,0 +1,418 @@
|
||||||
|
package sqlite
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
// "errors"
|
||||||
|
"fmt"
|
||||||
|
// "sync"
|
||||||
|
// "time"
|
||||||
|
|
||||||
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
|
"github.com/ihexxa/quickshare/src/db/rdb"
|
||||||
|
// "github.com/ihexxa/quickshare/src/kvstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: use sync.Pool instead
|
||||||
|
|
||||||
|
const (
|
||||||
|
VisitorID = uint64(1)
|
||||||
|
VisitorName = "visitor"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrReachedLimit = errors.New("reached space limit")
|
||||||
|
ErrUserNotFound = errors.New("user not found")
|
||||||
|
ErrNegtiveUsedSpace = errors.New("used space can not be negative")
|
||||||
|
)
|
||||||
|
|
||||||
|
type SQLiteUsers struct {
|
||||||
|
db rdb.IDB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSQLiteUsers(db rdb.IDB) (*SQLiteUsers, error) {
|
||||||
|
return &SQLiteUsers{db: db}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) Init(ctx context.Context, rootName, rootPwd string) error {
|
||||||
|
_, err := u.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`create table if not exists t_user (
|
||||||
|
id bigint not null,
|
||||||
|
name varchar not null,
|
||||||
|
pwd varchar not null,
|
||||||
|
role integer not null,
|
||||||
|
used_space bigint not null,
|
||||||
|
quota varchar not null,
|
||||||
|
preference varchar not null,
|
||||||
|
primary key(id)
|
||||||
|
)`,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
admin := &db.User{
|
||||||
|
ID: 0,
|
||||||
|
Name: rootName,
|
||||||
|
Pwd: rootPwd,
|
||||||
|
Role: db.AdminRole,
|
||||||
|
Quota: &db.Quota{
|
||||||
|
SpaceLimit: db.DefaultSpaceLimit,
|
||||||
|
UploadSpeedLimit: db.DefaultUploadSpeedLimit,
|
||||||
|
DownloadSpeedLimit: db.DefaultDownloadSpeedLimit,
|
||||||
|
},
|
||||||
|
Preferences: &db.DefaultPreferences,
|
||||||
|
}
|
||||||
|
visitor := &db.User{
|
||||||
|
ID: VisitorID,
|
||||||
|
Name: VisitorName,
|
||||||
|
Pwd: rootPwd,
|
||||||
|
Role: db.VisitorRole,
|
||||||
|
Quota: &db.Quota{
|
||||||
|
SpaceLimit: 0,
|
||||||
|
UploadSpeedLimit: db.VisitorUploadSpeedLimit,
|
||||||
|
DownloadSpeedLimit: db.VisitorDownloadSpeedLimit,
|
||||||
|
},
|
||||||
|
Preferences: &db.DefaultPreferences,
|
||||||
|
}
|
||||||
|
for _, user := range []*db.User{admin, visitor} {
|
||||||
|
err = u.AddUser(ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) IsInited() bool {
|
||||||
|
// always try to init the db
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// t_users
|
||||||
|
// id, name, pwd, role, used_space, config
|
||||||
|
func (u *SQLiteUsers) setUser(ctx context.Context, tx *sql.Tx, user *db.User) error {
|
||||||
|
var err error
|
||||||
|
if err = db.CheckUser(user, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
quotaStr, err := json.Marshal(user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
preferencesStr, err := json.Marshal(user.Preferences)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tx.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set name=?, pwd=?, role=?, used_space=?, quota=?, preference=?
|
||||||
|
where id=?`,
|
||||||
|
user.Name,
|
||||||
|
user.Pwd,
|
||||||
|
user.Role,
|
||||||
|
user.UsedSpace,
|
||||||
|
quotaStr,
|
||||||
|
preferencesStr,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) getUser(ctx context.Context, tx *sql.Tx, id uint64) (*db.User, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
user := &db.User{}
|
||||||
|
var quotaStr, preferenceStr string
|
||||||
|
err = tx.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
`select id, name, pwd, role, used_space, quota, preference
|
||||||
|
from t_user
|
||||||
|
where id=?`,
|
||||||
|
id,
|
||||||
|
).Scan(
|
||||||
|
&user.ID,
|
||||||
|
&user.Name,
|
||||||
|
&user.Pwd,
|
||||||
|
&user.Role,
|
||||||
|
&user.UsedSpace,
|
||||||
|
"aStr,
|
||||||
|
&preferenceStr,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, ErrUserNotFound
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(quotaStr), &user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal([]byte(preferenceStr), &user.Preferences)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) AddUser(ctx context.Context, user *db.User) error {
|
||||||
|
quotaStr, err := json.Marshal(user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
preferenceStr, err := json.Marshal(user.Preferences)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = u.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`insert into t_user (id, name, pwd, role, used_space, quota, preference) values (?, ?, ?, ?, ?, ?, ?)`,
|
||||||
|
user.ID,
|
||||||
|
user.Name,
|
||||||
|
user.Pwd,
|
||||||
|
user.Role,
|
||||||
|
user.UsedSpace,
|
||||||
|
quotaStr,
|
||||||
|
preferenceStr,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) DelUser(ctx context.Context, id uint64) error {
|
||||||
|
_, err := u.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`delete from t_user where id=?`,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) GetUser(ctx context.Context, id uint64) (*db.User, error) {
|
||||||
|
tx, err := u.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := u.getUser(ctx, tx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) GetUserByName(ctx context.Context, name string) (*db.User, error) {
|
||||||
|
user := &db.User{}
|
||||||
|
var quotaStr, preferenceStr string
|
||||||
|
err := u.db.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
`select id, name, role, used_space, quota, preference
|
||||||
|
from t_user
|
||||||
|
where name=?`,
|
||||||
|
name,
|
||||||
|
).Scan(
|
||||||
|
&user.ID,
|
||||||
|
&user.Name,
|
||||||
|
&user.Role,
|
||||||
|
&user.UsedSpace,
|
||||||
|
"aStr,
|
||||||
|
&preferenceStr,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, ErrUserNotFound
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(quotaStr), &user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal([]byte(preferenceStr), &user.Preferences)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) SetPwd(ctx context.Context, id uint64, pwd string) error {
|
||||||
|
_, err := u.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set pwd=?
|
||||||
|
where id=?`,
|
||||||
|
pwd,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// role + quota
|
||||||
|
func (u *SQLiteUsers) SetInfo(ctx context.Context, id uint64, user *db.User) error {
|
||||||
|
quotaStr, err := json.Marshal(user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = u.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set role=?, quota=?
|
||||||
|
where id=?`,
|
||||||
|
user.Role, quotaStr,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) SetPreferences(ctx context.Context, id uint64, prefers *db.Preferences) error {
|
||||||
|
preferenceStr, err := json.Marshal(prefers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = u.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set preference=?
|
||||||
|
where id=?`,
|
||||||
|
preferenceStr,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) SetUsed(ctx context.Context, id uint64, incr bool, capacity int64) error {
|
||||||
|
tx, err := u.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
gotUser, err := u.getUser(ctx, tx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if incr && gotUser.UsedSpace+capacity > int64(gotUser.Quota.SpaceLimit) {
|
||||||
|
return ErrReachedLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
if incr {
|
||||||
|
gotUser.UsedSpace = gotUser.UsedSpace + capacity
|
||||||
|
} else {
|
||||||
|
if gotUser.UsedSpace-capacity < 0 {
|
||||||
|
return ErrNegtiveUsedSpace
|
||||||
|
}
|
||||||
|
gotUser.UsedSpace = gotUser.UsedSpace - capacity
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set used_space=?
|
||||||
|
where id=?`,
|
||||||
|
gotUser.UsedSpace,
|
||||||
|
gotUser.ID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) ResetUsed(ctx context.Context, id uint64, used int64) error {
|
||||||
|
_, err := u.db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`update t_user
|
||||||
|
set used_space=?
|
||||||
|
where id=?`,
|
||||||
|
used,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) ListUsers(ctx context.Context) ([]*db.User, error) {
|
||||||
|
// TODO: support pagination
|
||||||
|
rows, err := u.db.QueryContext(
|
||||||
|
ctx,
|
||||||
|
`select id, name, role, used_space, quota, preference
|
||||||
|
from t_user`,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, ErrUserNotFound
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close() // TODO: check error
|
||||||
|
|
||||||
|
users := []*db.User{}
|
||||||
|
for rows.Next() {
|
||||||
|
user := &db.User{}
|
||||||
|
var quotaStr, preferenceStr string
|
||||||
|
err = rows.Scan(
|
||||||
|
&user.ID,
|
||||||
|
&user.Name,
|
||||||
|
&user.Role,
|
||||||
|
&user.UsedSpace,
|
||||||
|
"aStr,
|
||||||
|
&preferenceStr,
|
||||||
|
)
|
||||||
|
err = json.Unmarshal([]byte(quotaStr), &user.Quota)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal([]byte(preferenceStr), &user.Preferences)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
users = append(users, user)
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
return nil, rows.Err()
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) ListUserIDs(ctx context.Context) (map[string]string, error) {
|
||||||
|
users, err := u.ListUsers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nameToId := map[string]string{}
|
||||||
|
for _, user := range users {
|
||||||
|
nameToId[user.Name] = fmt.Sprint(user.ID)
|
||||||
|
}
|
||||||
|
return nameToId, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) AddRole(role string) error {
|
||||||
|
// TODO: implement this after adding grant/revoke
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) DelRole(role string) error {
|
||||||
|
// TODO: implement this after adding grant/revoke
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SQLiteUsers) ListRoles() (map[string]bool, error) {
|
||||||
|
// TODO: implement this after adding grant/revoke
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
293
src/db/rdb/sqlite/users_test.go
Normal file
293
src/db/rdb/sqlite/users_test.go
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
package sqlite
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUserStores(t *testing.T) {
|
||||||
|
rootName, rootPwd := "root", "rootPwd"
|
||||||
|
|
||||||
|
testUserMethods := func(t *testing.T, store db.IUserStore) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
root, err := store.GetUser(ctx, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if root.Name != rootName {
|
||||||
|
t.Fatal("root user not found")
|
||||||
|
}
|
||||||
|
if root.Pwd != rootPwd {
|
||||||
|
t.Fatalf("passwords not match (%s) (%s)", root.Pwd, rootPwd)
|
||||||
|
}
|
||||||
|
if root.Role != db.AdminRole {
|
||||||
|
t.Fatalf("incorrect root role")
|
||||||
|
}
|
||||||
|
if root.Quota.SpaceLimit != db.DefaultSpaceLimit {
|
||||||
|
t.Fatalf("incorrect root SpaceLimit")
|
||||||
|
}
|
||||||
|
if root.Quota.UploadSpeedLimit != db.DefaultUploadSpeedLimit {
|
||||||
|
t.Fatalf("incorrect root UploadSpeedLimit")
|
||||||
|
}
|
||||||
|
if root.Quota.DownloadSpeedLimit != db.DefaultDownloadSpeedLimit {
|
||||||
|
t.Fatalf("incorrect root DownloadSpeedLimit")
|
||||||
|
}
|
||||||
|
if !db.ComparePreferences(root.Preferences, &db.DefaultPreferences) {
|
||||||
|
t.Fatalf("incorrect preference %v %v", root.Preferences, db.DefaultPreferences)
|
||||||
|
}
|
||||||
|
|
||||||
|
visitor, err := store.GetUser(ctx, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if visitor.Name != VisitorName {
|
||||||
|
t.Fatal("visitor not found")
|
||||||
|
}
|
||||||
|
if visitor.Pwd != rootPwd {
|
||||||
|
t.Fatalf("passwords not match %s", err)
|
||||||
|
}
|
||||||
|
if visitor.Role != db.VisitorRole {
|
||||||
|
t.Fatalf("incorrect visitor role")
|
||||||
|
}
|
||||||
|
if visitor.Quota.SpaceLimit != 0 {
|
||||||
|
t.Fatalf("incorrect visitor SpaceLimit")
|
||||||
|
}
|
||||||
|
if visitor.Quota.UploadSpeedLimit != db.VisitorUploadSpeedLimit {
|
||||||
|
t.Fatalf("incorrect visitor UploadSpeedLimit")
|
||||||
|
}
|
||||||
|
if visitor.Quota.DownloadSpeedLimit != db.VisitorDownloadSpeedLimit {
|
||||||
|
t.Fatalf("incorrect visitor DownloadSpeedLimit")
|
||||||
|
}
|
||||||
|
if !db.ComparePreferences(visitor.Preferences, &db.DefaultPreferences) {
|
||||||
|
t.Fatalf("incorrect preference")
|
||||||
|
}
|
||||||
|
|
||||||
|
id, name1 := uint64(2), "test_user1"
|
||||||
|
pwd1, pwd2 := "666", "888"
|
||||||
|
role1, role2 := db.UserRole, db.AdminRole
|
||||||
|
spaceLimit1, upLimit1, downLimit1 := int64(17), 5, 7
|
||||||
|
spaceLimit2, upLimit2, downLimit2 := int64(19), 13, 17
|
||||||
|
|
||||||
|
err = store.AddUser(ctx, &db.User{
|
||||||
|
ID: id,
|
||||||
|
Name: name1,
|
||||||
|
Pwd: pwd1,
|
||||||
|
Role: role1,
|
||||||
|
Quota: &db.Quota{
|
||||||
|
SpaceLimit: spaceLimit1,
|
||||||
|
UploadSpeedLimit: upLimit1,
|
||||||
|
DownloadSpeedLimit: downLimit1,
|
||||||
|
},
|
||||||
|
Preferences: &db.DefaultPreferences,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("there should be no error")
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := store.GetUser(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if user.Name != name1 {
|
||||||
|
t.Fatalf("names not matched %s %s", name1, user.Name)
|
||||||
|
}
|
||||||
|
if user.Pwd != pwd1 {
|
||||||
|
t.Fatalf("passwords not match %s", err)
|
||||||
|
}
|
||||||
|
if user.Role != role1 {
|
||||||
|
t.Fatalf("roles not matched %s %s", role1, user.Role)
|
||||||
|
}
|
||||||
|
if user.Quota.SpaceLimit != spaceLimit1 {
|
||||||
|
t.Fatalf("space limit not matched %d %d", spaceLimit1, user.Quota.SpaceLimit)
|
||||||
|
}
|
||||||
|
if user.Quota.UploadSpeedLimit != upLimit1 {
|
||||||
|
t.Fatalf("up limit not matched %d %d", upLimit1, user.Quota.UploadSpeedLimit)
|
||||||
|
}
|
||||||
|
if user.Quota.DownloadSpeedLimit != downLimit1 {
|
||||||
|
t.Fatalf("down limit not matched %d %d", downLimit1, user.Quota.DownloadSpeedLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
users, err := store.ListUsers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(users) != 3 {
|
||||||
|
t.Fatalf("users size should be 3 (%d)", len(users))
|
||||||
|
}
|
||||||
|
for _, user := range users {
|
||||||
|
if user.ID == 0 {
|
||||||
|
if user.Name != rootName || user.Role != db.AdminRole {
|
||||||
|
t.Fatalf("incorrect root info %v", user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if user.ID == id {
|
||||||
|
if user.Name != name1 || user.Role != role1 {
|
||||||
|
t.Fatalf("incorrect user info %v", user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if user.Pwd != "" {
|
||||||
|
t.Fatalf("password must be empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = store.SetPwd(ctx, id, pwd2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
store.SetInfo(ctx, id, &db.User{
|
||||||
|
ID: id,
|
||||||
|
Role: role2,
|
||||||
|
Quota: &db.Quota{
|
||||||
|
SpaceLimit: spaceLimit2,
|
||||||
|
UploadSpeedLimit: upLimit2,
|
||||||
|
DownloadSpeedLimit: downLimit2,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
usedIncr, usedDecr := int64(spaceLimit2), int64(7)
|
||||||
|
err = store.SetUsed(ctx, id, true, usedIncr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = store.SetUsed(ctx, id, false, usedDecr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = store.SetUsed(ctx, id, true, int64(spaceLimit2)-(usedIncr-usedDecr)+1)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "reached space limit") {
|
||||||
|
t.Fatal("should reject big file")
|
||||||
|
} else {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err = store.GetUser(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if user.Pwd != pwd2 {
|
||||||
|
t.Fatalf("passwords not match %s %s", user.Pwd, pwd2)
|
||||||
|
}
|
||||||
|
if user.Role != role2 {
|
||||||
|
t.Fatalf("roles not matched %s %s", role2, user.Role)
|
||||||
|
}
|
||||||
|
if user.Quota.SpaceLimit != spaceLimit2 {
|
||||||
|
t.Fatalf("space limit not matched %d %d", spaceLimit2, user.Quota.SpaceLimit)
|
||||||
|
}
|
||||||
|
if user.Quota.UploadSpeedLimit != upLimit2 {
|
||||||
|
t.Fatalf("up limit not matched %d %d", upLimit2, user.Quota.UploadSpeedLimit)
|
||||||
|
}
|
||||||
|
if user.Quota.DownloadSpeedLimit != downLimit2 {
|
||||||
|
t.Fatalf("down limit not matched %d %d", downLimit2, user.Quota.DownloadSpeedLimit)
|
||||||
|
}
|
||||||
|
if user.UsedSpace != usedIncr-usedDecr {
|
||||||
|
t.Fatalf("used space not matched %d %d", user.UsedSpace, usedIncr-usedDecr)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
newPrefer := &db.Preferences{
|
||||||
|
Bg: &db.BgConfig{
|
||||||
|
Url: "/url",
|
||||||
|
Repeat: "repeat",
|
||||||
|
Position: "center",
|
||||||
|
Align: "fixed",
|
||||||
|
BgColor: "#333",
|
||||||
|
},
|
||||||
|
CSSURL: "/cssurl",
|
||||||
|
LanPackURL: "lanPackURL",
|
||||||
|
Lan: "zhCN",
|
||||||
|
Theme: "dark",
|
||||||
|
Avatar: "/avatar",
|
||||||
|
Email: "foo@gmail.com",
|
||||||
|
}
|
||||||
|
err = store.SetPreferences(ctx, id, newPrefer)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err = store.GetUserByName(ctx, name1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if user.ID != id {
|
||||||
|
t.Fatalf("ids not matched %d %d", id, user.ID)
|
||||||
|
}
|
||||||
|
if user.Pwd != pwd2 {
|
||||||
|
t.Fatalf("passwords not match %s", err)
|
||||||
|
}
|
||||||
|
if user.Role != role2 {
|
||||||
|
t.Fatalf("roles not matched %s %s", role2, user.Role)
|
||||||
|
}
|
||||||
|
if user.Quota.SpaceLimit != spaceLimit2 {
|
||||||
|
t.Fatalf("space limit not matched %d %d", spaceLimit2, user.Quota.SpaceLimit)
|
||||||
|
}
|
||||||
|
if user.Quota.UploadSpeedLimit != upLimit2 {
|
||||||
|
t.Fatalf("up limit not matched %d %d", upLimit2, user.Quota.UploadSpeedLimit)
|
||||||
|
}
|
||||||
|
if user.Quota.DownloadSpeedLimit != downLimit2 {
|
||||||
|
t.Fatalf("down limit not matched %d %d", downLimit2, user.Quota.DownloadSpeedLimit)
|
||||||
|
}
|
||||||
|
if !db.ComparePreferences(user.Preferences, newPrefer) {
|
||||||
|
t.Fatalf("preferences not matched %v %v", user.Preferences, newPrefer)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = store.DelUser(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
users, err = store.ListUsers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(users) != 2 {
|
||||||
|
t.Fatalf("users size should be 2 (%d)", len(users))
|
||||||
|
}
|
||||||
|
for _, user := range users {
|
||||||
|
if user.ID == 0 && user.Name != rootName && user.Role != db.AdminRole {
|
||||||
|
t.Fatalf("incorrect root info %v", user)
|
||||||
|
}
|
||||||
|
if user.ID == VisitorID && user.Name != VisitorName && user.Role != db.VisitorRole {
|
||||||
|
t.Fatalf("incorrect visitor info %v", user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nameToID, err := store.ListUserIDs(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(nameToID) != len(users) {
|
||||||
|
t.Fatalf("nameToID size (%d) should be same as (%d)", len(nameToID), len(users))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("testing UserStore sqlite", func(t *testing.T) {
|
||||||
|
rootPath, err := ioutil.TempDir("./", "quickshare_userstore_test_")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(rootPath)
|
||||||
|
|
||||||
|
dbPath := filepath.Join(rootPath, "quickshare.sqlite")
|
||||||
|
sqliteDB, err := NewSQLite(dbPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer sqliteDB.Close()
|
||||||
|
|
||||||
|
store, err := NewSQLiteUsers(sqliteDB)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("fail to new user store", err)
|
||||||
|
}
|
||||||
|
if err = store.Init(context.TODO(), rootName, rootPwd); err != nil {
|
||||||
|
t.Fatal("fail to init user store", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testUserMethods(t, store)
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package userstore
|
package userstore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -24,25 +25,6 @@ var (
|
||||||
ErrNegtiveUsedSpace = errors.New("used space can not be negative")
|
ErrNegtiveUsedSpace = errors.New("used space can not be negative")
|
||||||
)
|
)
|
||||||
|
|
||||||
type IUserStore interface {
|
|
||||||
Init(rootName, rootPwd string) error
|
|
||||||
IsInited() bool
|
|
||||||
AddUser(user *db.User) error
|
|
||||||
DelUser(id uint64) error
|
|
||||||
GetUser(id uint64) (*db.User, error)
|
|
||||||
GetUserByName(name string) (*db.User, error)
|
|
||||||
SetInfo(id uint64, user *db.User) error
|
|
||||||
SetUsed(id uint64, incr bool, capacity int64) error
|
|
||||||
ResetUsed(id uint64, used int64) error
|
|
||||||
SetPwd(id uint64, pwd string) error
|
|
||||||
SetPreferences(id uint64, settings *db.Preferences) error
|
|
||||||
ListUsers() ([]*db.User, error)
|
|
||||||
ListUserIDs() (map[string]string, error)
|
|
||||||
AddRole(role string) error
|
|
||||||
DelRole(role string) error
|
|
||||||
ListRoles() (map[string]bool, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type KVUserStore struct {
|
type KVUserStore struct {
|
||||||
store kvstore.IKVStore
|
store kvstore.IKVStore
|
||||||
mtx *sync.RWMutex
|
mtx *sync.RWMutex
|
||||||
|
@ -55,7 +37,7 @@ func NewKVUserStore(store kvstore.IKVStore) (*KVUserStore, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) Init(rootName, rootPwd string) error {
|
func (us *KVUserStore) Init(ctx context.Context, rootName, rootPwd string) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
for _, namespace := range []string{
|
for _, namespace := range []string{
|
||||||
|
@ -99,7 +81,7 @@ func (us *KVUserStore) Init(rootName, rootPwd string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, user := range []*db.User{admin, visitor} {
|
for _, user := range []*db.User{admin, visitor} {
|
||||||
err = us.AddUser(user)
|
err = us.AddUser(context.TODO(), user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -181,14 +163,14 @@ func (us *KVUserStore) getUserByName(name string) (*db.User, error) {
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) AddUser(user *db.User) error {
|
func (us *KVUserStore) AddUser(ctx context.Context, user *db.User) error {
|
||||||
us.mtx.Lock()
|
us.mtx.Lock()
|
||||||
defer us.mtx.Unlock()
|
defer us.mtx.Unlock()
|
||||||
|
|
||||||
return us.setUser(user)
|
return us.setUser(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) DelUser(id uint64) error {
|
func (us *KVUserStore) DelUser(ctx context.Context, id uint64) error {
|
||||||
us.mtx.Lock()
|
us.mtx.Lock()
|
||||||
defer us.mtx.Unlock()
|
defer us.mtx.Unlock()
|
||||||
|
|
||||||
|
@ -206,21 +188,21 @@ func (us *KVUserStore) DelUser(id uint64) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) GetUser(id uint64) (*db.User, error) {
|
func (us *KVUserStore) GetUser(ctx context.Context, id uint64) (*db.User, error) {
|
||||||
us.mtx.RLock()
|
us.mtx.RLock()
|
||||||
defer us.mtx.RUnlock()
|
defer us.mtx.RUnlock()
|
||||||
|
|
||||||
return us.getUser(id)
|
return us.getUser(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) GetUserByName(name string) (*db.User, error) {
|
func (us *KVUserStore) GetUserByName(ctx context.Context, name string) (*db.User, error) {
|
||||||
us.mtx.RLock()
|
us.mtx.RLock()
|
||||||
defer us.mtx.RUnlock()
|
defer us.mtx.RUnlock()
|
||||||
|
|
||||||
return us.getUserByName(name)
|
return us.getUserByName(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) SetPwd(id uint64, pwd string) error {
|
func (us *KVUserStore) SetPwd(ctx context.Context, id uint64, pwd string) error {
|
||||||
us.mtx.Lock()
|
us.mtx.Lock()
|
||||||
defer us.mtx.Unlock()
|
defer us.mtx.Unlock()
|
||||||
|
|
||||||
|
@ -233,7 +215,7 @@ func (us *KVUserStore) SetPwd(id uint64, pwd string) error {
|
||||||
return us.setUser(user)
|
return us.setUser(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) SetInfo(id uint64, user *db.User) error {
|
func (us *KVUserStore) SetInfo(ctx context.Context, id uint64, user *db.User) error {
|
||||||
us.mtx.Lock()
|
us.mtx.Lock()
|
||||||
defer us.mtx.Unlock()
|
defer us.mtx.Unlock()
|
||||||
|
|
||||||
|
@ -248,7 +230,7 @@ func (us *KVUserStore) SetInfo(id uint64, user *db.User) error {
|
||||||
return us.setUser(gotUser)
|
return us.setUser(gotUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) SetPreferences(id uint64, prefers *db.Preferences) error {
|
func (us *KVUserStore) SetPreferences(ctx context.Context, id uint64, prefers *db.Preferences) error {
|
||||||
us.mtx.Lock()
|
us.mtx.Lock()
|
||||||
defer us.mtx.Unlock()
|
defer us.mtx.Unlock()
|
||||||
|
|
||||||
|
@ -261,7 +243,7 @@ func (us *KVUserStore) SetPreferences(id uint64, prefers *db.Preferences) error
|
||||||
return us.setUser(user)
|
return us.setUser(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) SetUsed(id uint64, incr bool, capacity int64) error {
|
func (us *KVUserStore) SetUsed(ctx context.Context, id uint64, incr bool, capacity int64) error {
|
||||||
us.mtx.Lock()
|
us.mtx.Lock()
|
||||||
defer us.mtx.Unlock()
|
defer us.mtx.Unlock()
|
||||||
|
|
||||||
|
@ -286,7 +268,7 @@ func (us *KVUserStore) SetUsed(id uint64, incr bool, capacity int64) error {
|
||||||
return us.setUser(gotUser)
|
return us.setUser(gotUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) ResetUsed(id uint64, used int64) error {
|
func (us *KVUserStore) ResetUsed(ctx context.Context, id uint64, used int64) error {
|
||||||
us.mtx.Lock()
|
us.mtx.Lock()
|
||||||
defer us.mtx.Unlock()
|
defer us.mtx.Unlock()
|
||||||
|
|
||||||
|
@ -299,7 +281,7 @@ func (us *KVUserStore) ResetUsed(id uint64, used int64) error {
|
||||||
return us.setUser(gotUser)
|
return us.setUser(gotUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) ListUsers() ([]*db.User, error) {
|
func (us *KVUserStore) ListUsers(ctx context.Context) ([]*db.User, error) {
|
||||||
us.mtx.RLock()
|
us.mtx.RLock()
|
||||||
defer us.mtx.RUnlock()
|
defer us.mtx.RUnlock()
|
||||||
|
|
||||||
|
@ -355,7 +337,7 @@ func (us *KVUserStore) ListUsers() ([]*db.User, error) {
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) ListUserIDs() (map[string]string, error) {
|
func (us *KVUserStore) ListUserIDs(ctx context.Context) (map[string]string, error) {
|
||||||
us.mtx.RLock()
|
us.mtx.RLock()
|
||||||
defer us.mtx.RUnlock()
|
defer us.mtx.RUnlock()
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/ihexxa/quickshare/src/db/fileinfostore"
|
"github.com/ihexxa/quickshare/src/db/fileinfostore"
|
||||||
"github.com/ihexxa/quickshare/src/db/rdb"
|
"github.com/ihexxa/quickshare/src/db/rdb"
|
||||||
"github.com/ihexxa/quickshare/src/db/sitestore"
|
"github.com/ihexxa/quickshare/src/db/sitestore"
|
||||||
"github.com/ihexxa/quickshare/src/db/userstore"
|
|
||||||
"github.com/ihexxa/quickshare/src/fs"
|
"github.com/ihexxa/quickshare/src/fs"
|
||||||
"github.com/ihexxa/quickshare/src/idgen"
|
"github.com/ihexxa/quickshare/src/idgen"
|
||||||
"github.com/ihexxa/quickshare/src/iolimiter"
|
"github.com/ihexxa/quickshare/src/iolimiter"
|
||||||
|
@ -31,7 +30,7 @@ type Deps struct {
|
||||||
fs fs.ISimpleFS
|
fs fs.ISimpleFS
|
||||||
token cryptoutil.ITokenEncDec
|
token cryptoutil.ITokenEncDec
|
||||||
kv kvstore.IKVStore
|
kv kvstore.IKVStore
|
||||||
users userstore.IUserStore
|
users db.IUserStore
|
||||||
fileInfos fileinfostore.IFileInfoStore
|
fileInfos fileinfostore.IFileInfoStore
|
||||||
siteStore sitestore.ISiteStore
|
siteStore sitestore.ISiteStore
|
||||||
id idgen.IIDGen
|
id idgen.IIDGen
|
||||||
|
@ -88,11 +87,11 @@ func (deps *Deps) SetLog(logger *zap.SugaredLogger) {
|
||||||
deps.logger = logger
|
deps.logger = logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (deps *Deps) Users() userstore.IUserStore {
|
func (deps *Deps) Users() db.IUserStore {
|
||||||
return deps.users
|
return deps.users
|
||||||
}
|
}
|
||||||
|
|
||||||
func (deps *Deps) SetUsers(users userstore.IUserStore) {
|
func (deps *Deps) SetUsers(users db.IUserStore) {
|
||||||
deps.users = users
|
deps.users = users
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ func (h *MultiUsersSvc) Init(adminName, adminPwd string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: return "" for being compatible with singleuser service, should remove this
|
// TODO: return "" for being compatible with singleuser service, should remove this
|
||||||
err = h.deps.Users().Init(adminName, adminPwd)
|
err = h.deps.Users().Init(c, adminName, adminPwd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ func (h *MultiUsersSvc) Init(adminName, adminPwd string) (string, error) {
|
||||||
Preferences: &preferences,
|
Preferences: &preferences,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.deps.Users().AddUser(user)
|
err = h.deps.Users().AddUser(c, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.deps.Log().Warn("warning: failed to add user(%s): %s", user, err)
|
h.deps.Log().Warn("warning: failed to add user(%s): %s", user, err)
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -243,7 +243,7 @@ func (h *MultiUsersSvc) Login(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := h.deps.Users().GetUserByName(req.User)
|
user, err := h.deps.Users().GetUserByName(c, req.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, userstore.ErrUserNotFound) {
|
if errors.Is(err, userstore.ErrUserNotFound) {
|
||||||
c.JSON(q.ErrResp(c, 403, err))
|
c.JSON(q.ErrResp(c, 403, err))
|
||||||
|
@ -320,7 +320,7 @@ func (h *MultiUsersSvc) SetPwd(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := h.deps.Users().GetUser(uid)
|
user, err := h.deps.Users().GetUser(c, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 402, err))
|
c.JSON(q.ErrResp(c, 402, err))
|
||||||
return
|
return
|
||||||
|
@ -338,7 +338,7 @@ func (h *MultiUsersSvc) SetPwd(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.deps.Users().SetPwd(uid, string(newHash))
|
err = h.deps.Users().SetPwd(c, uid, string(newHash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -364,7 +364,7 @@ func (h *MultiUsersSvc) ForceSetPwd(c *gin.Context) {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
targetUser, err := h.deps.Users().GetUser(targetUID)
|
targetUser, err := h.deps.Users().GetUser(c, targetUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -380,7 +380,7 @@ func (h *MultiUsersSvc) ForceSetPwd(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.deps.Users().SetPwd(targetUser.ID, string(newHash))
|
err = h.deps.Users().SetPwd(c, targetUser.ID, string(newHash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -437,7 +437,7 @@ func (h *MultiUsersSvc) AddUser(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
newPreferences := db.DefaultPreferences
|
newPreferences := db.DefaultPreferences
|
||||||
err = h.deps.Users().AddUser(&db.User{
|
err = h.deps.Users().AddUser(c, &db.User{
|
||||||
ID: uid,
|
ID: uid,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Pwd: string(pwdHash),
|
Pwd: string(pwdHash),
|
||||||
|
@ -483,7 +483,7 @@ func (h *MultiUsersSvc) DelUser(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: try to make following atomic
|
// TODO: try to make following atomic
|
||||||
err = h.deps.Users().DelUser(userID)
|
err = h.deps.Users().DelUser(c, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -514,7 +514,7 @@ func (h *MultiUsersSvc) ListUsers(c *gin.Context) {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
users, err := h.deps.Users().ListUsers()
|
users, err := h.deps.Users().ListUsers(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -651,7 +651,7 @@ func (h *MultiUsersSvc) Self(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := h.deps.Users().GetUserByName(claims[q.UserParam])
|
user, err := h.deps.Users().GetUserByName(c, claims[q.UserParam])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -686,7 +686,7 @@ func (h *MultiUsersSvc) SetUser(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := h.deps.Users().SetInfo(req.ID, &db.User{
|
err := h.deps.Users().SetInfo(c, req.ID, &db.User{
|
||||||
Role: req.Role,
|
Role: req.Role,
|
||||||
Quota: req.Quota,
|
Quota: req.Quota,
|
||||||
})
|
})
|
||||||
|
@ -721,7 +721,7 @@ func (h *MultiUsersSvc) SetPreferences(c *gin.Context) {
|
||||||
req.Preferences.Bg = db.DefaultBgConfig
|
req.Preferences.Bg = db.DefaultBgConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.deps.Users().SetPreferences(uid, req.Preferences)
|
err = h.deps.Users().SetPreferences(c, uid, req.Preferences)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -740,7 +740,7 @@ func (h *MultiUsersSvc) ResetUsedSpace(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userInfo, err := h.deps.Users().GetUser(req.UserID)
|
userInfo, err := h.deps.Users().GetUser(c, req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
|
|
@ -9,7 +9,8 @@ import (
|
||||||
const fileIndexPath = "/fileindex.jsonl"
|
const fileIndexPath = "/fileindex.jsonl"
|
||||||
|
|
||||||
type DbConfig struct {
|
type DbConfig struct {
|
||||||
DbPath string `json:"dbPath" yaml:"dbPath"`
|
DbPath string `json:"dbPath" yaml:"dbPath"`
|
||||||
|
RdbPath string `json:"rdbPath" yaml:"rdbPath"` // valid values: rdb, kv
|
||||||
}
|
}
|
||||||
|
|
||||||
type FSConfig struct {
|
type FSConfig struct {
|
||||||
|
@ -140,7 +141,8 @@ func DefaultConfigStruct() *Config {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Db: &DbConfig{
|
Db: &DbConfig{
|
||||||
DbPath: "quickshare.db",
|
DbPath: "quickshare.db",
|
||||||
|
RdbPath: "quickshare.sqlite",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ihexxa/quickshare/src/db"
|
"github.com/ihexxa/quickshare/src/db"
|
||||||
"github.com/ihexxa/quickshare/src/db/boltstore"
|
"github.com/ihexxa/quickshare/src/db/boltstore"
|
||||||
"github.com/ihexxa/quickshare/src/db/fileinfostore"
|
"github.com/ihexxa/quickshare/src/db/fileinfostore"
|
||||||
|
"github.com/ihexxa/quickshare/src/db/rdb/sqlite"
|
||||||
"github.com/ihexxa/quickshare/src/db/sitestore"
|
"github.com/ihexxa/quickshare/src/db/sitestore"
|
||||||
"github.com/ihexxa/quickshare/src/db/userstore"
|
"github.com/ihexxa/quickshare/src/db/userstore"
|
||||||
"github.com/ihexxa/quickshare/src/depidx"
|
"github.com/ihexxa/quickshare/src/depidx"
|
||||||
|
@ -65,7 +66,7 @@ func NewServer(cfg gocfg.ICfg) (*Server, error) {
|
||||||
|
|
||||||
err = checkCompatibility(deps)
|
err = checkCompatibility(deps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("fail to check compatibility: %w", err)
|
return nil, fmt.Errorf("failed to check compatibility: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
port := cfg.GrabInt("Server.Port")
|
port := cfg.GrabInt("Server.Port")
|
||||||
|
@ -152,19 +153,33 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
|
||||||
kv := boltdbpvd.New(dbPath, 1024)
|
kv := boltdbpvd.New(dbPath, 1024)
|
||||||
users, err := userstore.NewKVUserStore(kv)
|
users, err := userstore.NewKVUserStore(kv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("fail to init user store: %s", err))
|
panic(fmt.Sprintf("failed to init user store: %s", err))
|
||||||
}
|
}
|
||||||
fileInfos, err := fileinfostore.NewFileInfoStore(kv)
|
fileInfos, err := fileinfostore.NewFileInfoStore(kv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("fail to init file info store: %s", err))
|
panic(fmt.Sprintf("failed to init file info store: %s", err))
|
||||||
}
|
}
|
||||||
siteStore, err := sitestore.NewSiteStore(kv)
|
siteStore, err := sitestore.NewSiteStore(kv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("fail to init site config store: %s", err))
|
panic(fmt.Sprintf("failed to init site config store: %s", err))
|
||||||
}
|
}
|
||||||
boltDB, err := boltstore.NewBoltStore(kv.Bolt())
|
boltDB, err := boltstore.NewBoltStore(kv.Bolt())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("fail to init bolt store: %s", err))
|
panic(fmt.Sprintf("failed to init bolt store: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
rdbPath := cfg.GrabString("Db.RdbPath")
|
||||||
|
if rdbPath == "" {
|
||||||
|
panic("rdbPath is blank")
|
||||||
|
}
|
||||||
|
rdbDir := filepath.Dir(rdbPath)
|
||||||
|
if err = filesystem.MkdirAll(rdbDir); err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to create path for rdb: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
rdb, err := sqlite.NewSQLite(rdbPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to open sqlite: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = siteStore.Init(&db.SiteConfig{
|
err = siteStore.Init(&db.SiteConfig{
|
||||||
|
@ -181,7 +196,7 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("fail to init site config store: %s", err))
|
panic(fmt.Sprintf("failed to init site config store: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
limiterCap := cfg.IntOr("Users.LimiterCapacity", 10000)
|
limiterCap := cfg.IntOr("Users.LimiterCapacity", 10000)
|
||||||
|
@ -199,6 +214,7 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
|
||||||
deps.SetID(ider)
|
deps.SetID(ider)
|
||||||
deps.SetLog(logger)
|
deps.SetLog(logger)
|
||||||
deps.SetLimiter(limiter)
|
deps.SetLimiter(limiter)
|
||||||
|
deps.SetDB(rdb)
|
||||||
|
|
||||||
queueSize := cfg.GrabInt("Workers.QueueSize")
|
queueSize := cfg.GrabInt("Workers.QueueSize")
|
||||||
sleepCyc := cfg.GrabInt("Workers.SleepCyc")
|
sleepCyc := cfg.GrabInt("Workers.SleepCyc")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue