diff options
| author | raven <citrons@mondecitronne.com> | 2025-10-20 18:06:13 -0500 |
|---|---|---|
| committer | raven <citrons@mondecitronne.com> | 2025-10-20 18:06:13 -0500 |
| commit | 5320b561c592e875f0523760d4d20df8d66b30a7 (patch) | |
| tree | 1b2f6cb8edc6a4b9cdd5d138b8528f04ff46971d /server/user/user.go | |
| parent | 9e08d84af7d975ef540a67b54ecc9b3c0e4d084c (diff) | |
user and channel saving
Diffstat (limited to 'server/user/user.go')
| -rw-r--r-- | server/user/user.go | 124 |
1 files changed, 99 insertions, 25 deletions
diff --git a/server/user/user.go b/server/user/user.go index 17063b4..46eda35 100644 --- a/server/user/user.go +++ b/server/user/user.go @@ -5,29 +5,31 @@ import ( "citrons.xyz/talk/server/session" "citrons.xyz/talk/server/validate" "citrons.xyz/talk/proto" + bolt "go.etcd.io/bbolt" + "log" ) -type UserStore struct { +type UserKind struct { world *object.World - byName map[string]*User + db *bolt.DB } type User struct { - store *UserStore + kind *UserKind name string id string status string description string Stream session.Stream - Channels map[string]bool - Anonymous bool + anonymous bool + Channels map[string]bool // TODO: remove } -func NewStore(world *object.World) *UserStore { - return &UserStore {world, make(map[string]*User)} +func Kind(world *object.World) *UserKind { + return &UserKind {world, world.DB()} } -func (us *UserStore) CreateUser(name string) (*User, *proto.Fail) { +func (us *UserKind) CreateUser(name string) (*User, *proto.Fail) { if us.ByName(name) != nil { return nil, &proto.Fail { "name-taken", "", map[string]string {"": name}, @@ -39,44 +41,107 @@ func (us *UserStore) CreateUser(name string) (*User, *proto.Fail) { } } var u User - u.store = us + u.kind = us u.name = name - us.byName[validate.Fold(name)] = &u - u.id = us.world.NewObject(&u) + u.id = proto.GenId() + u.anonymous = true u.Channels = make(map[string]bool) + u.Save() return &u, nil } -func (us *UserStore) ByName(name string) *User { - return us.byName[validate.Fold(name)] +func (us *UserKind) ByName(name string) *User { + switch u := us.world.Lookup("u", name).(type) { + case *User: + return u + default: + return nil + } +} + +func (us *UserKind) DeleteAnonUsers() { + var anon []string + err := us.db.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket([]byte("anonymous users")) + if bucket == nil { + return nil + } + bucket.ForEach(func(k, v []byte) error { + anon = append(anon, string(k)) + return nil + }) + return nil + }) + if err != nil { + log.Fatal("error reading database: ", err) + } + for _, id := range anon { + switch u := us.world.GetObject(id).(type) { + case *User: + u.Delete() + } + } +} + +func (us *UserKind) Undata(o proto.Object) object.Object { + var u User + u.kind = us + u.id = o.Id + u.name = o.Fields[""] + u.status = o.Fields["status"] + u.description = o.Fields["description"] + u.anonymous = o.Fields["anonymous"] == "yes" + return &u +} + +func (u *User) Data() proto.Object { + data := u.InfoFor("") + data.Fields["description"] = u.description + return data } func (u *User) Name() string { return u.name } +func (u *User) Handle() string { + return u.Name() +} + func (u *User) Id() string { return u.id } +func (u *User) Save() { + err := u.kind.db.Update(func(tx *bolt.Tx) error { + bucket, _ := tx.CreateBucketIfNotExists([]byte("anonymous users")) + if u.anonymous { + bucket.Put([]byte(u.id), []byte("yes")) + } else { + bucket.Delete([]byte(u.id)) + } + return nil + }) + if err != nil { + log.Fatal("error updating database: ", err) + } + u.kind.world.PutObject(u.id, u) +} + func (u *User) Rename(name string) *proto.Fail { if !validate.Name(name) { return &proto.Fail { "invalid-name", "", map[string]string {"": name}, } } - if validate.Fold(name) == validate.Fold(u.name) { - u.name = name - return nil - } - if u.store.ByName(name) != nil { + if u.kind.ByName(name) != nil && + validate.Fold(name) != validate.Fold(u.name) { return &proto.Fail { "name-taken", "", map[string]string {"": name}, } } - u.store.byName[validate.Fold(u.name)] = nil - u.store.byName[validate.Fold(name)] = u u.name = name + u.Save() return nil } @@ -84,13 +149,18 @@ func (u *User) Delete() { u.Stream.Event(proto.NewCmd("delete", u.id)) u.Stream.UnsubscribeAll() - delete(u.store.byName, validate.Fold(u.name)) - u.store.world.RemoveObject(u.id) - gone := object.Tombstone { u.id, map[string]string {"": u.name, "kind": "u"}, } - u.store.world.PutObject(u.id, gone) + u.kind.world.PutObject(u.id, gone) + err := u.kind.db.Update(func(tx *bolt.Tx) error { + bucket, _ := tx.CreateBucketIfNotExists([]byte("anonymous users")) + bucket.Delete([]byte(u.id)) + return nil + }) + if err != nil { + log.Fatal("error updating database: ", err) + } } func (u *User) InfoFor(uid string) proto.Object { @@ -98,10 +168,14 @@ func (u *User) InfoFor(uid string) proto.Object { if u.status != "" { i["status"] = u.status } - if u.Anonymous { + if u.anonymous { i["anonymous"] = "yes" } else { i["anonymous"] = "no" } return proto.Object {"u", u.id, i} } + +func (u *User) IsAnonymous() bool { + return u.anonymous +} |
