Users database

This commit is contained in:
Meutel 2017-09-09 17:12:37 +02:00
parent d844432641
commit 9a50ccd2fc
7 changed files with 75 additions and 21 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ calibre.db
bouquins.json bouquins.json
Gopkg.lock Gopkg.lock
vendor/ vendor/
users.db

View File

@ -8,6 +8,7 @@ Bouquins in Go
* tests * tests
* auth downloads * auth downloads
* csrf * csrf
* userdb commands (init, migrate, add/remove user/email)
## Minify JS ## Minify JS
@ -47,6 +48,7 @@ Options:
* calibre-path path to calibre data * calibre-path path to calibre data
* db-path path to calibre SQLite database (default <calibre-path>/metadata.db) * db-path path to calibre SQLite database (default <calibre-path>/metadata.db)
* user-db-path path to users SQLite database (default ./users.db)
* bind-address HTTP socket bind address * bind-address HTTP socket bind address
* prod (boolean) use minified javascript/CSS * prod (boolean) use minified javascript/CSS
* cookie-secret random string for cookie encryption * cookie-secret random string for cookie encryption
@ -55,3 +57,9 @@ Options:
* name provider name * name provider name
* client-id OAuth client ID * client-id OAuth client ID
* client-secret OAuth secret * client-secret OAuth secret
## Users SQL
CREATE TABLE accounts (id varchar(36) PRIMARY KEY NOT NULL, name varchar(255) NOT NULL);
CREATE TABLE authentifiers (id varchar(36) NOT NULL, authentifier varchar(320) PRIMARY KEY NOT NULL, FOREIGN KEY(id) REFERENCES account(id));

View File

@ -127,11 +127,12 @@ func (app *Bouquins) CallbackPage(res http.ResponseWriter, req *http.Request) er
if err != nil { if err != nil {
return err return err
} }
// FIXME list allowed users user, err := Account(userEmail)
if userEmail == "meutel@gmail.com" || userEmail == "meutel+github@meutel.net" { if err != nil {
app.SessionSet(sessionUser, "Meutel", res, req) log.Println("Error loading user", err)
log.Println("User logged in", userEmail) return fmt.Errorf("Unknown user")
return RedirectHome(res, req)
} }
return fmt.Errorf("Unknown user") app.SessionSet(sessionUser, user.DisplayName, res, req)
log.Println("User logged in", user.DisplayName)
return RedirectHome(res, req)
} }

View File

@ -71,6 +71,7 @@ type Conf struct {
DbPath string `json:"db-path"` DbPath string `json:"db-path"`
CalibrePath string `json:"calibre-path"` CalibrePath string `json:"calibre-path"`
Prod bool `json:"prod"` Prod bool `json:"prod"`
UserDbPath string `json:"user-db-path"`
CookieSecret string `json:"cookie-secret"` CookieSecret string `json:"cookie-secret"`
ExternalURL string `json:"external-url"` ExternalURL string `json:"external-url"`
ProvidersConf []ProviderConf `json:"providers"` ProvidersConf []ProviderConf `json:"providers"`
@ -85,12 +86,20 @@ type ProviderConf struct {
// Bouquins contains application common resources: templates, database // Bouquins contains application common resources: templates, database
type Bouquins struct { type Bouquins struct {
Tpl *template.Template Tpl *template.Template
DB *sql.DB *sql.DB
UserDB *sql.DB
*Conf
OAuthConf map[string]*oauth2.Config OAuthConf map[string]*oauth2.Config
Cookies *sessions.CookieStore Cookies *sessions.CookieStore
} }
// UserAccount is an user account
type UserAccount struct {
ID string // UUID
DisplayName string
}
// Series is a book series. // Series is a book series.
type Series struct { type Series struct {
ID int64 `json:"id,omitempty"` ID int64 `json:"id,omitempty"`

View File

@ -104,6 +104,8 @@ const (
AND authors.id != ? ORDER BY authors.id` AND authors.id != ? ORDER BY authors.id`
sqlAuthor = "SELECT name FROM authors WHERE id = ?" sqlAuthor = "SELECT name FROM authors WHERE id = ?"
sqlAccount = "SELECT accounts.id, name FROM accounts, authentifiers WHERE authentifiers.id = accounts.id AND authentifiers.authentifier = ?"
defaultLimit = 10 defaultLimit = 10
qtBook QueryType = iota qtBook QueryType = iota
@ -162,7 +164,10 @@ var queries = map[Query]string{
Query{qtAuthorBooks, false, false}: sqlAuthorBooks, Query{qtAuthorBooks, false, false}: sqlAuthorBooks,
Query{qtAuthorCoauthors, false, false}: sqlAuthorAuthors, Query{qtAuthorCoauthors, false, false}: sqlAuthorAuthors,
} }
var stmts = make(map[Query]*sql.Stmt) var (
stmts = make(map[Query]*sql.Stmt)
stmtAccount *sql.Stmt
)
// QueryType is a type of query, with variants for sort and order // QueryType is a type of query, with variants for sort and order
type QueryType uint type QueryType uint
@ -214,6 +219,13 @@ func (app *Bouquins) PrepareAll() error {
} }
stmts[q] = stmt stmts[q] = stmt
} }
// users.db
var err error
stmtAccount, err = app.UserDB.Prepare(sqlAccount)
if err != nil {
log.Println(err, sqlAccount)
errcount++
}
if errcount > 0 { if errcount > 0 {
return fmt.Errorf("%d errors on queries, see logs", errcount) return fmt.Errorf("%d errors on queries, see logs", errcount)
} }

11
bouquins/dbusers.go Normal file
View File

@ -0,0 +1,11 @@
package bouquins
// Account returns user account from authentifier
func Account(authentifier string) (*UserAccount, error) {
account := new(UserAccount)
err := stmtAccount.QueryRow(authentifier).Scan(&account.ID, &account.DisplayName)
if err != nil {
return nil, err
}
return account, nil
}

36
main.go
View File

@ -15,8 +15,6 @@ import (
"meutel.net/meutel/go-bouquins/bouquins" "meutel.net/meutel/go-bouquins/bouquins"
) )
var db *sql.DB
// ReadConfig loads configuration file and initialize default value // ReadConfig loads configuration file and initialize default value
func ReadConfig() (*bouquins.Conf, error) { func ReadConfig() (*bouquins.Conf, error) {
conf := new(bouquins.Conf) conf := new(bouquins.Conf)
@ -39,13 +37,16 @@ func ReadConfig() (*bouquins.Conf, error) {
if conf.DbPath == "" { if conf.DbPath == "" {
conf.DbPath = conf.CalibrePath + "/metadata.db" conf.DbPath = conf.CalibrePath + "/metadata.db"
} }
if conf.UserDbPath == "" {
conf.UserDbPath = "./users.db"
}
if conf.BindAddress == "" { if conf.BindAddress == "" {
conf.BindAddress = ":9000" conf.BindAddress = ":9000"
} }
return conf, err return conf, err
} }
func initApp() *bouquins.Conf { func initApp() *bouquins.Bouquins {
log.SetFlags(log.LstdFlags | log.Lshortfile) log.SetFlags(log.LstdFlags | log.Lshortfile)
conf, err := ReadConfig() conf, err := ReadConfig()
if err != nil { if err != nil {
@ -56,23 +57,33 @@ func initApp() *bouquins.Conf {
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
db, err = sql.Open("sqlite3", conf.DbPath) db, err := sql.Open("sqlite3", conf.DbPath)
if err != nil {
log.Fatalln(err)
}
userdb, err := sql.Open("sqlite3", conf.UserDbPath)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
oauthConf := make(map[string]*oauth2.Config) app := &bouquins.Bouquins{
for _, provider := range bouquins.Providers { Tpl: tpl,
oauthConf[provider.Name()] = provider.Config(conf) DB: db,
UserDB: userdb,
Conf: conf,
OAuthConf: make(map[string]*oauth2.Config),
Cookies: sessions.NewCookieStore([]byte(conf.CookieSecret)),
}
for _, provider := range bouquins.Providers {
app.OAuthConf[provider.Name()] = provider.Config(conf)
} }
app := &bouquins.Bouquins{Tpl: tpl, DB: db, OAuthConf: oauthConf, Cookies: sessions.NewCookieStore([]byte(conf.CookieSecret))}
err = app.PrepareAll() err = app.PrepareAll()
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
assets(conf.CalibrePath) assets(conf.CalibrePath)
router(app) router(app)
return conf return app
} }
func assets(calibre string) { func assets(calibre string) {
@ -109,7 +120,8 @@ func router(app *bouquins.Bouquins) {
} }
func main() { func main() {
conf := initApp() app := initApp()
defer db.Close() defer app.DB.Close()
http.ListenAndServe(conf.BindAddress, nil) defer app.UserDB.Close()
http.ListenAndServe(app.Conf.BindAddress, nil)
} }