Users database
This commit is contained in:
parent
d844432641
commit
9a50ccd2fc
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ calibre.db
|
|||||||
bouquins.json
|
bouquins.json
|
||||||
Gopkg.lock
|
Gopkg.lock
|
||||||
vendor/
|
vendor/
|
||||||
|
users.db
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
@ -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 RedirectHome(res, req)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("Unknown user")
|
return fmt.Errorf("Unknown user")
|
||||||
}
|
}
|
||||||
|
app.SessionSet(sessionUser, user.DisplayName, res, req)
|
||||||
|
log.Println("User logged in", user.DisplayName)
|
||||||
|
return RedirectHome(res, req)
|
||||||
|
}
|
||||||
|
@ -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"`
|
||||||
@ -86,11 +87,19 @@ 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"`
|
||||||
|
@ -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
11
bouquins/dbusers.go
Normal 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
36
main.go
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user