create db schemas for accounts
This commit is contained in:
@ -28,9 +28,9 @@ import (
|
||||
|
||||
// Initialize will initialize the database given in the config for use with GoToSocial
|
||||
var Initialize action.GTSAction = func(ctx context.Context, c *config.Config, log *logrus.Logger) error {
|
||||
_, err := New(ctx, c, log)
|
||||
db, err := New(ctx, c, log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return db.CreateSchema(ctx)
|
||||
}
|
||||
|
@ -42,7 +42,15 @@ type DB interface {
|
||||
/*
|
||||
ANY ADDITIONAL DESIRED FUNCTIONS
|
||||
*/
|
||||
|
||||
// CreateSchema should populate the database with the required tables
|
||||
CreateSchema(context.Context) error
|
||||
|
||||
// Stop should stop and close the database connection cleanly, returning an error if this is not possible
|
||||
Stop(context.Context) error
|
||||
|
||||
// IsHealthy should return nil if the database connection is healthy, or an error if not
|
||||
IsHealthy(context.Context) error
|
||||
}
|
||||
|
||||
// New returns a new database service that satisfies the Service interface and, by extension,
|
||||
|
@ -28,8 +28,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/go-pg/pg"
|
||||
"github.com/go-pg/pg/extra/pgdebug"
|
||||
"github.com/go-pg/pg/v10"
|
||||
"github.com/go-pg/pg/v10/orm"
|
||||
"github.com/gotosocial/gotosocial/internal/config"
|
||||
"github.com/gotosocial/gotosocial/internal/model"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@ -47,9 +50,10 @@ func newPostgresService(ctx context.Context, c *config.Config, log *logrus.Entry
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create postgres service: %s", err)
|
||||
}
|
||||
log.Debugf("using pg options: %+v", opts)
|
||||
|
||||
readyChan := make(chan interface{})
|
||||
opts.OnConnect = func(c *pg.Conn) error {
|
||||
opts.OnConnect = func(ctx context.Context, c *pg.Conn) error {
|
||||
close(readyChan)
|
||||
return nil
|
||||
}
|
||||
@ -58,19 +62,30 @@ func newPostgresService(ctx context.Context, c *config.Config, log *logrus.Entry
|
||||
pgCtx, cancel := context.WithCancel(ctx)
|
||||
conn := pg.Connect(opts).WithContext(pgCtx)
|
||||
|
||||
// this will break the logfmt format we normally log in,
|
||||
// since we can't choose where pg outputs to and it defaults to
|
||||
// stdout. So use this option with care!
|
||||
if log.Logger.GetLevel() >= logrus.TraceLevel {
|
||||
conn.AddQueryHook(pgdebug.DebugHook{
|
||||
// Print all queries.
|
||||
Verbose: true,
|
||||
})
|
||||
}
|
||||
|
||||
// actually *begin* the connection so that we can tell if the db is there
|
||||
// and listening, and also trigger the opts.OnConnect function passed in above
|
||||
tx, err := conn.Begin()
|
||||
if err != nil {
|
||||
if err := conn.Ping(ctx); err != nil {
|
||||
cancel()
|
||||
return nil, fmt.Errorf("db connection error: %s", err)
|
||||
}
|
||||
|
||||
// close the transaction we just started so it doesn't hang around
|
||||
if err := tx.Rollback(); err != nil {
|
||||
// print out discovered postgres version
|
||||
var version string
|
||||
if _, err = conn.QueryOneContext(ctx, pg.Scan(&version), "SELECT version()"); err != nil {
|
||||
cancel()
|
||||
return nil, fmt.Errorf("db connection error: %s", err)
|
||||
}
|
||||
log.Infof("connected to postgres version: %s", version)
|
||||
|
||||
// make sure the opts.OnConnect function has been triggered
|
||||
// and closed the ready channel
|
||||
@ -82,6 +97,12 @@ func newPostgresService(ctx context.Context, c *config.Config, log *logrus.Entry
|
||||
return nil, errors.New("db connection timeout")
|
||||
}
|
||||
|
||||
acc := model.StubAccount()
|
||||
if _, err := conn.Model(acc).Returning("id").Insert(); err != nil {
|
||||
cancel()
|
||||
return nil, errors.New("db insert error")
|
||||
}
|
||||
|
||||
// we can confidently return this useable postgres service now
|
||||
return &postgresService{
|
||||
config: c.DBConfig,
|
||||
@ -242,3 +263,26 @@ func (ps *postgresService) Stop(ctx context.Context) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps *postgresService) CreateSchema(ctx context.Context) error {
|
||||
models := []interface{}{
|
||||
(*model.Account)(nil),
|
||||
}
|
||||
ps.log.Info("creating db schema")
|
||||
|
||||
for _, model := range models {
|
||||
err := ps.conn.Model(model).CreateTable(&orm.CreateTableOptions{
|
||||
IfNotExists: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ps.log.Info("db schema created")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps *postgresService) IsHealthy(ctx context.Context) error {
|
||||
return ps.conn.Ping(ctx)
|
||||
}
|
||||
|
80
internal/model/account.go
Normal file
80
internal/model/account.go
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Account represents a user account
|
||||
type Account struct {
|
||||
Avatar
|
||||
Header
|
||||
ID int `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
|
||||
Username string
|
||||
Domain string
|
||||
Secret string
|
||||
PrivateKey string
|
||||
PublicKey string
|
||||
RemoteURL *url.URL `pg:"type:text"`
|
||||
SalmonURL *url.URL `pg:"type:text"`
|
||||
HubURL *url.URL `pg:"type:text"`
|
||||
CreatedAt time.Time `pg:"type:timestamp,notnull"`
|
||||
UpdatedAt time.Time `pg:"type:timestamp,notnull"`
|
||||
Note string
|
||||
DisplayName string
|
||||
URI *url.URL `pg:"type:text"`
|
||||
URL *url.URL `pg:"type:text"`
|
||||
SubscriptionExpiresAt time.Time `pg:"type:timestamp"`
|
||||
Locked bool
|
||||
LastWebfingeredAt time.Time `pg:"type:timestamp"`
|
||||
InboxURL *url.URL `pg:"type:text"`
|
||||
OutboxURL *url.URL `pg:"type:text"`
|
||||
SharedInboxURL *url.URL `pg:"type:text"`
|
||||
FollowersURL *url.URL `pg:"type:text"`
|
||||
Protocol int
|
||||
Memorial bool
|
||||
MovedToAccountID int
|
||||
FeaturedCollectionURL *url.URL `pg:"type:text"`
|
||||
Fields map[string]string
|
||||
ActorType string
|
||||
Discoverable bool
|
||||
AlsoKnownAs string
|
||||
SilencedAt time.Time `pg:"type:timestamp"`
|
||||
SuspendedAt time.Time `pg:"type:timestamp"`
|
||||
TrustLevel int
|
||||
HideCollections bool
|
||||
DevicesURL *url.URL `pg:"type:text"`
|
||||
SensitizedAt time.Time `pg:"type:timestamp"`
|
||||
SuspensionOrigin int
|
||||
}
|
||||
|
||||
func StubAccount() *Account {
|
||||
|
||||
remoteURL, _ := url.Parse("https://example.org/@someuser")
|
||||
|
||||
return &Account{
|
||||
Username: "some_user",
|
||||
Domain: "example.org",
|
||||
RemoteURL: remoteURL,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
}
|
33
internal/model/avatar.go
Normal file
33
internal/model/avatar.go
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Avatar struct {
|
||||
AvatarFileName string
|
||||
AvatarContentType string
|
||||
AvatarFileSize int
|
||||
AvatarUpdatedAt *time.Time `pg:"type:timestamp"`
|
||||
AvatarRemoteURL *url.URL `pg:"type:text"`
|
||||
AvatarStorageSchemaVersion int
|
||||
}
|
33
internal/model/header.go
Normal file
33
internal/model/header.go
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Header struct {
|
||||
HeaderFileName string
|
||||
HeaderContentType string
|
||||
HeaderFileSize int
|
||||
HeaderUpdatedAt *time.Time `pg:"type:timestamp"`
|
||||
HeaderRemoteURL *url.URL `pg:"type:text"`
|
||||
HeaderStorageSchemaVersion int
|
||||
}
|
@ -38,6 +38,10 @@ var Run action.GTSAction = func(ctx context.Context, c *config.Config, log *logr
|
||||
return fmt.Errorf("error creating dbservice: %s", err)
|
||||
}
|
||||
|
||||
if err := dbService.CreateSchema(ctx); err != nil {
|
||||
return fmt.Errorf("error creating dbschema: %s", err)
|
||||
}
|
||||
|
||||
// catch shutdown signals from the operating system
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)
|
||||
|
Reference in New Issue
Block a user