diff --git a/assets/migrations/2_external.up.sql b/assets/migrations/2_external.up.sql new file mode 100644 index 0000000..763913f --- /dev/null +++ b/assets/migrations/2_external.up.sql @@ -0,0 +1,17 @@ +CREATE TABLE "external_auth" ( + "id" bigserial NOT NULL, + "name" text NOT NULL, + "type" text NOT NULL, + "config" jsonb NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX ON "external_auth" ("type"); + +CREATE TABLE "external_user" ( + "external_auth_id" bigint NOT NULL, + "foreign_id" text NOT NULL, + "user_id" bigint NOT NULL, + FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE, + FOREIGN KEY ("external_auth_id") REFERENCES "external_auth" ("id") ON DELETE CASCADE, + PRIMARY KEY ("external_auth_id", "foreign_id") +); \ No newline at end of file diff --git a/internal/database/confirmation.xo.go b/internal/database/confirmation.xo.go new file mode 100644 index 0000000..222bf8a --- /dev/null +++ b/internal/database/confirmation.xo.go @@ -0,0 +1,233 @@ +// Package database contains the types for schema 'public'. +package database + +// Code generated by xo. DO NOT EDIT. + +import ( + "errors" + "time" +) + +// Confirmation represents a row from '"public"."confirmation"'. +type Confirmation struct { + EmailAddress string `db:"email_address"` // email_address + UserID int64 `db:"user_id"` // user_id + Selector string `db:"selector"` // selector + Verifier []byte `db:"verifier"` // verifier + ExpiresAt time.Time `db:"expires_at"` // expires_at + + // xo fields + _exists, _deleted bool +} + +// Exists determines if the Confirmation exists in the database. +func (c *Confirmation) Exists() bool { + return c._exists +} + +// Deleted provides information if the Confirmation has been deleted from the database. +func (c *Confirmation) Deleted() bool { + return c._deleted +} + +// Insert inserts the Confirmation to the database. +func (c *Confirmation) Insert(db XODB) error { + var err error + + // if already exist, bail + if c._exists { + return errors.New("insert failed: already exists") + } + + // sql insert query, primary key must be provided + const sqlstr = `INSERT INTO "public"."confirmation" (` + + `"email_address", "user_id", "selector", "verifier", "expires_at"` + + `) VALUES (` + + `$1, $2, $3, $4, $5` + + `)` + + // run query + XOLog(sqlstr, c.EmailAddress, c.UserID, c.Selector, c.Verifier, c.ExpiresAt) + _, err = db.Exec(sqlstr, c.EmailAddress, c.UserID, c.Selector, c.Verifier, c.ExpiresAt) + if err != nil { + return err + } + + // set existence + c._exists = true + + return nil +} + +// Update updates the Confirmation in the database. +func (c *Confirmation) Update(db XODB) error { + var err error + + // if doesn't exist, bail + if !c._exists { + return errors.New("update failed: does not exist") + } + + // if deleted, bail + if c._deleted { + return errors.New("update failed: marked for deletion") + } + + // sql query + const sqlstr = `UPDATE "public"."confirmation" SET (` + + `"email_address", "user_id", "verifier", "expires_at"` + + `) = ( ` + + `$1, $2, $3, $4` + + `) WHERE "selector" = $5` + + // run query + XOLog(sqlstr, c.EmailAddress, c.UserID, c.Verifier, c.ExpiresAt, c.Selector) + _, err = db.Exec(sqlstr, c.EmailAddress, c.UserID, c.Verifier, c.ExpiresAt, c.Selector) + return err +} + +// Save saves the Confirmation to the database. +func (c *Confirmation) Save(db XODB) error { + if c.Exists() { + return c.Update(db) + } + + return c.Insert(db) +} + +// Upsert performs an upsert for Confirmation. +// +// NOTE: PostgreSQL 9.5+ only +func (c *Confirmation) Upsert(db XODB) error { + var err error + + // if already exist, bail + if c._exists { + return errors.New("insert failed: already exists") + } + + // sql query + const sqlstr = `INSERT INTO "public"."confirmation" (` + + `"email_address", "user_id", "selector", "verifier", "expires_at"` + + `) VALUES (` + + `$1, $2, $3, $4, $5` + + `) ON CONFLICT ("selector") DO UPDATE SET (` + + `"email_address", "user_id", "selector", "verifier", "expires_at"` + + `) = (` + + `EXCLUDED."email_address", EXCLUDED."user_id", EXCLUDED."selector", EXCLUDED."verifier", EXCLUDED."expires_at"` + + `)` + + // run query + XOLog(sqlstr, c.EmailAddress, c.UserID, c.Selector, c.Verifier, c.ExpiresAt) + _, err = db.Exec(sqlstr, c.EmailAddress, c.UserID, c.Selector, c.Verifier, c.ExpiresAt) + if err != nil { + return err + } + + // set existence + c._exists = true + + return nil +} + +// Delete deletes the Confirmation from the database. +func (c *Confirmation) Delete(db XODB) error { + var err error + + // if doesn't exist, bail + if !c._exists { + return nil + } + + // if deleted, bail + if c._deleted { + return nil + } + + // sql query + const sqlstr = `DELETE FROM "public"."confirmation" WHERE "selector" = $1` + + // run query + XOLog(sqlstr, c.Selector) + _, err = db.Exec(sqlstr, c.Selector) + if err != nil { + return err + } + + // set deleted + c._deleted = true + + return nil +} + +// User returns the User associated with the Confirmation's UserID (user_id). +// +// Generated from foreign key 'confirmation_user_id_fkey'. +func (c *Confirmation) User(db XODB) (*User, error) { + return UserByID(db, c.UserID) +} + +// ConfirmationBySelector retrieves a row from '"public"."confirmation"' as a Confirmation. +// +// Generated from index 'confirmation_pkey'. +func ConfirmationBySelector(db XODB, selector string) (*Confirmation, error) { + var err error + + // sql query + const sqlstr = `SELECT ` + + `"email_address", "user_id", "selector", "verifier", "expires_at" ` + + `FROM "public"."confirmation" ` + + `WHERE "selector" = $1` + + // run query + XOLog(sqlstr, selector) + c := Confirmation{ + _exists: true, + } + + err = db.QueryRow(sqlstr, selector).Scan(&c.EmailAddress, &c.UserID, &c.Selector, &c.Verifier, &c.ExpiresAt) + if err != nil { + return nil, err + } + + return &c, nil +} + +// ConfirmationsByUserID retrieves a row from '"public"."confirmation"' as a Confirmation. +// +// Generated from index 'confirmation_user_id_idx'. +func ConfirmationsByUserID(db XODB, userID int64) ([]*Confirmation, error) { + var err error + + // sql query + const sqlstr = `SELECT ` + + `"email_address", "user_id", "selector", "verifier", "expires_at" ` + + `FROM "public"."confirmation" ` + + `WHERE "user_id" = $1` + + // run query + XOLog(sqlstr, userID) + q, err := db.Query(sqlstr, userID) + if err != nil { + return nil, err + } + defer q.Close() + + // load results + res := []*Confirmation{} + for q.Next() { + c := Confirmation{ + _exists: true, + } + + // scan + err = q.Scan(&c.EmailAddress, &c.UserID, &c.Selector, &c.Verifier, &c.ExpiresAt) + if err != nil { + return nil, err + } + + res = append(res, &c) + } + + return res, nil +} diff --git a/internal/database/reset.xo.go b/internal/database/reset.xo.go new file mode 100644 index 0000000..2f2485d --- /dev/null +++ b/internal/database/reset.xo.go @@ -0,0 +1,219 @@ +// Package database contains the types for schema 'public'. +package database + +// Code generated by xo. DO NOT EDIT. + +import ( + "errors" + "time" +) + +// Reset represents a row from '"public"."reset"'. +type Reset struct { + UserID int64 `db:"user_id"` // user_id + Selector string `db:"selector"` // selector + Verifier []byte `db:"verifier"` // verifier + ExpiresAt time.Time `db:"expires_at"` // expires_at + + // xo fields + _exists, _deleted bool +} + +// Exists determines if the Reset exists in the database. +func (r *Reset) Exists() bool { + return r._exists +} + +// Deleted provides information if the Reset has been deleted from the database. +func (r *Reset) Deleted() bool { + return r._deleted +} + +// Insert inserts the Reset to the database. +func (r *Reset) Insert(db XODB) error { + var err error + + // if already exist, bail + if r._exists { + return errors.New("insert failed: already exists") + } + + // sql insert query, primary key must be provided + const sqlstr = `INSERT INTO "public"."reset" (` + + `"user_id", "selector", "verifier", "expires_at"` + + `) VALUES (` + + `$1, $2, $3, $4` + + `)` + + // run query + XOLog(sqlstr, r.UserID, r.Selector, r.Verifier, r.ExpiresAt) + _, err = db.Exec(sqlstr, r.UserID, r.Selector, r.Verifier, r.ExpiresAt) + if err != nil { + return err + } + + // set existence + r._exists = true + + return nil +} + +// Update updates the Reset in the database. +func (r *Reset) Update(db XODB) error { + var err error + + // if doesn't exist, bail + if !r._exists { + return errors.New("update failed: does not exist") + } + + // if deleted, bail + if r._deleted { + return errors.New("update failed: marked for deletion") + } + + // sql query + const sqlstr = `UPDATE "public"."reset" SET (` + + `"user_id", "verifier", "expires_at"` + + `) = ( ` + + `$1, $2, $3` + + `) WHERE "selector" = $4` + + // run query + XOLog(sqlstr, r.UserID, r.Verifier, r.ExpiresAt, r.Selector) + _, err = db.Exec(sqlstr, r.UserID, r.Verifier, r.ExpiresAt, r.Selector) + return err +} + +// Save saves the Reset to the database. +func (r *Reset) Save(db XODB) error { + if r.Exists() { + return r.Update(db) + } + + return r.Insert(db) +} + +// Upsert performs an upsert for Reset. +// +// NOTE: PostgreSQL 9.5+ only +func (r *Reset) Upsert(db XODB) error { + var err error + + // if already exist, bail + if r._exists { + return errors.New("insert failed: already exists") + } + + // sql query + const sqlstr = `INSERT INTO "public"."reset" (` + + `"user_id", "selector", "verifier", "expires_at"` + + `) VALUES (` + + `$1, $2, $3, $4` + + `) ON CONFLICT ("selector") DO UPDATE SET (` + + `"user_id", "selector", "verifier", "expires_at"` + + `) = (` + + `EXCLUDED."user_id", EXCLUDED."selector", EXCLUDED."verifier", EXCLUDED."expires_at"` + + `)` + + // run query + XOLog(sqlstr, r.UserID, r.Selector, r.Verifier, r.ExpiresAt) + _, err = db.Exec(sqlstr, r.UserID, r.Selector, r.Verifier, r.ExpiresAt) + if err != nil { + return err + } + + // set existence + r._exists = true + + return nil +} + +// Delete deletes the Reset from the database. +func (r *Reset) Delete(db XODB) error { + var err error + + // if doesn't exist, bail + if !r._exists { + return nil + } + + // if deleted, bail + if r._deleted { + return nil + } + + // sql query + const sqlstr = `DELETE FROM "public"."reset" WHERE "selector" = $1` + + // run query + XOLog(sqlstr, r.Selector) + _, err = db.Exec(sqlstr, r.Selector) + if err != nil { + return err + } + + // set deleted + r._deleted = true + + return nil +} + +// User returns the User associated with the Reset's UserID (user_id). +// +// Generated from foreign key 'reset_user_id_fkey'. +func (r *Reset) User(db XODB) (*User, error) { + return UserByID(db, r.UserID) +} + +// ResetBySelector retrieves a row from '"public"."reset"' as a Reset. +// +// Generated from index 'reset_pkey'. +func ResetBySelector(db XODB, selector string) (*Reset, error) { + var err error + + // sql query + const sqlstr = `SELECT ` + + `"user_id", "selector", "verifier", "expires_at" ` + + `FROM "public"."reset" ` + + `WHERE "selector" = $1` + + // run query + XOLog(sqlstr, selector) + r := Reset{ + _exists: true, + } + + err = db.QueryRow(sqlstr, selector).Scan(&r.UserID, &r.Selector, &r.Verifier, &r.ExpiresAt) + if err != nil { + return nil, err + } + + return &r, nil +} + +// ResetByUserID retrieves a row from '"public"."reset"' as a Reset. +// +// Generated from index 'reset_user_id_idx'. +func ResetByUserID(db XODB, userID int64) (*Reset, error) { + var err error + + // sql query + const sqlstr = `SELECT ` + + `"user_id", "selector", "verifier", "expires_at" ` + + `FROM "public"."reset" ` + + `WHERE "user_id" = $1` + + // run query + XOLog(sqlstr, userID) + r := Reset{ + _exists: true, + } + + err = db.QueryRow(sqlstr, userID).Scan(&r.UserID, &r.Selector, &r.Verifier, &r.ExpiresAt) + if err != nil { + return nil, err + } + + return &r, nil +}