summaryrefslogtreecommitdiff
path: root/owner
diff options
context:
space:
mode:
authorVitaly Minko <vitaly.minko@gmail.com>2018-10-22 18:45:56 +0300
committerVitaly Minko <vitaly.minko@gmail.com>2018-10-22 18:45:56 +0300
commit7cf13227aee08432b885051cd7fe2d9a81cf7db4 (patch)
tree7d59a18d9de1a91246887bd459f411b8440c71a2 /owner
parent3f16780b47ccf36d53d2dfcf80e2896e37380567 (diff)
Implemented second part of moderation feature.
Added profile database, implemented moderation business logic.
Diffstat (limited to 'owner')
-rw-r--r--owner/owner.go30
-rw-r--r--owner/profile.go96
2 files changed, 118 insertions, 8 deletions
diff --git a/owner/owner.go b/owner/owner.go
index 58c977f..7bc2c16 100644
--- a/owner/owner.go
+++ b/owner/owner.go
@@ -27,6 +27,7 @@ import (
"vminko.org/dscuss/entity"
"vminko.org/dscuss/errors"
"vminko.org/dscuss/log"
+ "vminko.org/dscuss/sqlite"
"vminko.org/dscuss/storage"
"vminko.org/dscuss/subs"
)
@@ -34,13 +35,15 @@ import (
type Owner struct {
User *entity.User
Subs subs.Subscriptions
+ Profile *Profile
Signer *crypto.Signer
storage *storage.Storage
}
const (
- privKeyFileName string = "privkey.pem"
- subscriptionsFileName string = "subscriptions.txt"
+ privKeyFileName string = "privkey.pem"
+ subscriptionsFileName string = "subscriptions.txt"
+ profileDatabaseFileName string = "profile.db"
)
func Register(dir, nickname, info string, subs subs.Subscriptions, s *storage.Storage) error {
@@ -103,12 +106,12 @@ func Register(dir, nickname, info string, subs subs.Subscriptions, s *storage.St
return nil
}
-func New(dir, nickname string, s *storage.Storage) (*Owner, error) {
+func New(dir, nickname string, stor *storage.Storage) (*Owner, error) {
userDir := filepath.Join(dir, nickname)
- log.Debugf("Login uses the following user directory: %s", userDir)
+ log.Debugf("Owner uses the following user directory: %s", userDir)
if _, err := os.Stat(userDir); os.IsNotExist(err) {
log.Warningf("User directory '%s' does not exist", userDir)
- return nil, errors.Filesystem
+ return nil, errors.NoSuchUser
}
privKeyPath := filepath.Join(userDir, privKeyFileName)
@@ -125,7 +128,7 @@ func New(dir, nickname string, s *storage.Storage) (*Owner, error) {
}
eid := entity.NewID(privKey.Public().EncodeToDER())
- u, err := s.GetUser(&eid)
+ u, err := stor.GetUser(&eid)
if err != nil {
log.Errorf("Can't fetch the user with id '%x' from the storage: %v", eid, err)
return nil, err
@@ -140,14 +143,25 @@ func New(dir, nickname string, s *storage.Storage) (*Owner, error) {
return nil, err
}
+ profileDatabasePath := filepath.Join(userDir, profileDatabaseFileName)
+ db, err := sqlite.OpenProfileDatabase(profileDatabasePath)
+ if err != nil {
+ log.Errorf("Can't open profile database file %s: %v", profileDatabasePath, err)
+ return nil, errors.Database
+ }
+
return &Owner{
User: u,
Subs: sub,
+ Profile: NewProfile(db, u.ID()),
Signer: crypto.NewSigner(privKey),
- storage: s,
+ storage: stor,
}, nil
}
func (o *Owner) Close() {
- // Detach from storage, for example
+ err := o.Profile.Close()
+ if err != nil {
+ log.Errorf("Error closing entity storage: %v", err)
+ }
}
diff --git a/owner/profile.go b/owner/profile.go
new file mode 100644
index 0000000..cfb7f42
--- /dev/null
+++ b/owner/profile.go
@@ -0,0 +1,96 @@
+/*
+This file is part of Dscuss.
+Copyright (C) 2018 Vitaly Minko
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package owner
+
+import (
+ "sync"
+ "vminko.org/dscuss/entity"
+ "vminko.org/dscuss/errors"
+ "vminko.org/dscuss/sqlite"
+)
+
+// Profile is a proxy for the entity database, which implements caching and
+// provides few additional functions for managing owner's settings.
+type Profile struct {
+ db *sqlite.ProfileDatabase
+ moderators []*entity.ID
+ modersMx sync.Mutex
+ self *entity.ID
+}
+
+func NewProfile(db *sqlite.ProfileDatabase, id *entity.ID) *Profile {
+ return &Profile{db: db, self: id}
+}
+
+func (p *Profile) Close() error {
+ return p.db.Close()
+}
+
+func (p *Profile) PutModerator(id *entity.ID) error {
+ if *id == *p.self {
+ return errors.AlreadyModerator
+ }
+ p.modersMx.Lock()
+ defer p.modersMx.Unlock()
+ p.moderators = nil
+ return p.db.PutModerator(id)
+}
+
+func (p *Profile) RemoveModerator(id *entity.ID) error {
+ if *id == *p.self {
+ return errors.ForbiddenOperation
+ }
+ p.modersMx.Lock()
+ defer p.modersMx.Unlock()
+ p.moderators = nil
+ return p.db.RemoveModerator(id)
+}
+
+func (p *Profile) HasModerator(id *entity.ID) (bool, error) {
+ if *id == *p.self {
+ return true, nil
+ }
+ p.modersMx.Lock()
+ defer p.modersMx.Unlock()
+ if p.moderators != nil {
+ var err error
+ p.moderators, err = p.db.GetModerators()
+ if err != nil {
+ return false, err
+ }
+ }
+ for _, m := range p.moderators {
+ if *m == *id {
+ return true, nil
+ }
+ }
+ return false, nil
+}
+
+func (p *Profile) GetModerators() ([]*entity.ID, error) {
+ p.modersMx.Lock()
+ defer p.modersMx.Unlock()
+ if p.moderators != nil {
+ var err error
+ p.moderators, err = p.db.GetModerators()
+ if err != nil {
+ return nil, err
+ }
+ }
+ return append(p.moderators, p.self), nil
+}