parent
4b780361bf
commit
c6851fee50
48
database.go
48
database.go
|
@ -8,6 +8,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-sql-driver/mysql"
|
"github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/mattn/go-sqlite3"
|
||||||
|
|
||||||
"github.com/guregu/null"
|
"github.com/guregu/null"
|
||||||
"github.com/guregu/null/zero"
|
"github.com/guregu/null/zero"
|
||||||
uuid "github.com/nu7hatch/gouuid"
|
uuid "github.com/nu7hatch/gouuid"
|
||||||
|
@ -130,6 +132,22 @@ func (db *datastore) upsert(indexedCols ...string) string {
|
||||||
return "ON DUPLICATE KEY UPDATE"
|
return "ON DUPLICATE KEY UPDATE"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *datastore) isDuplicateKeyErr(err error) bool {
|
||||||
|
if db.driverName == driverSQLite {
|
||||||
|
if err, ok := err.(sqlite3.Error); ok {
|
||||||
|
return err.Code == sqlite3.ErrConstraint
|
||||||
|
}
|
||||||
|
} else if db.driverName == driverMySQL {
|
||||||
|
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
||||||
|
return mysqlErr.Number == mySQLErrDuplicateKey
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Error("isDuplicateKeyErr: failed check for unrecognized driver '%s'", db.driverName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (db *datastore) CreateUser(u *User, collectionTitle string) error {
|
func (db *datastore) CreateUser(u *User, collectionTitle string) error {
|
||||||
// New users get a `users` and `collections` row.
|
// New users get a `users` and `collections` row.
|
||||||
t, err := db.Begin()
|
t, err := db.Begin()
|
||||||
|
@ -146,11 +164,9 @@ func (db *datastore) CreateUser(u *User, collectionTitle string) error {
|
||||||
res, err := t.Exec("INSERT INTO users (username, password, email) VALUES (?, ?, ?)", u.Username, u.HashedPass, u.Email)
|
res, err := t.Exec("INSERT INTO users (username, password, email) VALUES (?, ?, ?)", u.Username, u.HashedPass, u.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Rollback()
|
t.Rollback()
|
||||||
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
if db.isDuplicateKeyErr(err) {
|
||||||
if mysqlErr.Number == mySQLErrDuplicateKey {
|
|
||||||
return impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
return impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
log.Error("Rolling back users INSERT: %v\n", err)
|
log.Error("Rolling back users INSERT: %v\n", err)
|
||||||
return err
|
return err
|
||||||
|
@ -169,11 +185,9 @@ func (db *datastore) CreateUser(u *User, collectionTitle string) error {
|
||||||
res, err = t.Exec("INSERT INTO collections (alias, title, description, privacy, owner_id, view_count) VALUES (?, ?, ?, ?, ?, ?)", u.Username, collectionTitle, "", CollUnlisted, u.ID, 0)
|
res, err = t.Exec("INSERT INTO collections (alias, title, description, privacy, owner_id, view_count) VALUES (?, ?, ?, ?, ?, ?)", u.Username, collectionTitle, "", CollUnlisted, u.ID, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Rollback()
|
t.Rollback()
|
||||||
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
if db.isDuplicateKeyErr(err) {
|
||||||
if mysqlErr.Number == mySQLErrDuplicateKey {
|
|
||||||
return impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
return impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
log.Error("Rolling back collections INSERT: %v\n", err)
|
log.Error("Rolling back collections INSERT: %v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -241,11 +255,9 @@ func (db *datastore) CreateCollection(alias, title string, userID int64) (*Colle
|
||||||
// All good, so create new collection
|
// All good, so create new collection
|
||||||
res, err := db.Exec("INSERT INTO collections (alias, title, description, privacy, owner_id, view_count) VALUES (?, ?, ?, ?, ?, ?)", alias, title, "", CollUnlisted, userID, 0)
|
res, err := db.Exec("INSERT INTO collections (alias, title, description, privacy, owner_id, view_count) VALUES (?, ?, ?, ?, ?, ?)", alias, title, "", CollUnlisted, userID, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
if db.isDuplicateKeyErr(err) {
|
||||||
if mysqlErr.Number == mySQLErrDuplicateKey {
|
|
||||||
return nil, impart.HTTPError{http.StatusConflict, "Collection already exists."}
|
return nil, impart.HTTPError{http.StatusConflict, "Collection already exists."}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
log.Error("Couldn't add to collections: %v\n", err)
|
log.Error("Couldn't add to collections: %v\n", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -614,8 +626,7 @@ func (db *datastore) CreatePost(userID, collID int64, post *SubmittedPost) (*Pos
|
||||||
defer stmt.Close()
|
defer stmt.Close()
|
||||||
_, err = stmt.Exec(friendlyID, slug, post.Title, post.Content, appearance, post.Language, post.IsRTL, 0, ownerID, ownerCollID, created, 0)
|
_, err = stmt.Exec(friendlyID, slug, post.Title, post.Content, appearance, post.Language, post.IsRTL, 0, ownerID, ownerCollID, created, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
if db.isDuplicateKeyErr(err) {
|
||||||
if mysqlErr.Number == mySQLErrDuplicateKey {
|
|
||||||
// Duplicate entry error; try a new slug
|
// Duplicate entry error; try a new slug
|
||||||
// TODO: make this a little more robust
|
// TODO: make this a little more robust
|
||||||
slug = sql.NullString{id.GenSafeUniqueSlug(slug.String), true}
|
slug = sql.NullString{id.GenSafeUniqueSlug(slug.String), true}
|
||||||
|
@ -626,9 +637,6 @@ func (db *datastore) CreatePost(userID, collID int64, post *SubmittedPost) (*Pos
|
||||||
} else {
|
} else {
|
||||||
return nil, handleFailedPostInsert(err)
|
return nil, handleFailedPostInsert(err)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return nil, handleFailedPostInsert(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: return Created field in proper format
|
// TODO: return Created field in proper format
|
||||||
|
@ -1198,8 +1206,7 @@ func (db *datastore) CanCollect(cpr *ClaimPostRequest, userID int64) bool {
|
||||||
func (db *datastore) AttemptClaim(p *ClaimPostRequest, query string, params []interface{}, slugIdx int) (sql.Result, error) {
|
func (db *datastore) AttemptClaim(p *ClaimPostRequest, query string, params []interface{}, slugIdx int) (sql.Result, error) {
|
||||||
qRes, err := db.Exec(query, params...)
|
qRes, err := db.Exec(query, params...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
if db.isDuplicateKeyErr(err) && slugIdx > -1 {
|
||||||
if mysqlErr.Number == mySQLErrDuplicateKey && slugIdx > -1 {
|
|
||||||
s := id.GenSafeUniqueSlug(p.Slug)
|
s := id.GenSafeUniqueSlug(p.Slug)
|
||||||
if s == p.Slug {
|
if s == p.Slug {
|
||||||
// Sanity check to prevent infinite recursion
|
// Sanity check to prevent infinite recursion
|
||||||
|
@ -1209,7 +1216,6 @@ func (db *datastore) AttemptClaim(p *ClaimPostRequest, query string, params []in
|
||||||
params[slugIdx] = p.Slug
|
params[slugIdx] = p.Slug
|
||||||
return db.AttemptClaim(p, query, params, slugIdx)
|
return db.AttemptClaim(p, query, params, slugIdx)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return qRes, fmt.Errorf("attemptClaim: %s", err)
|
return qRes, fmt.Errorf("attemptClaim: %s", err)
|
||||||
}
|
}
|
||||||
return qRes, nil
|
return qRes, nil
|
||||||
|
@ -1779,11 +1785,9 @@ func (db *datastore) ChangeSettings(app *app, u *User, s *userSettings) error {
|
||||||
_, err = t.Exec("UPDATE users SET username = ? WHERE id = ?", newUsername, u.ID)
|
_, err = t.Exec("UPDATE users SET username = ? WHERE id = ?", newUsername, u.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Rollback()
|
t.Rollback()
|
||||||
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
if db.isDuplicateKeyErr(err) {
|
||||||
if mysqlErr.Number == mySQLErrDuplicateKey {
|
|
||||||
return impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
return impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
log.Error("Unable to update users table: %v", err)
|
log.Error("Unable to update users table: %v", err)
|
||||||
return ErrInternalGeneral
|
return ErrInternalGeneral
|
||||||
}
|
}
|
||||||
|
@ -1791,11 +1795,9 @@ func (db *datastore) ChangeSettings(app *app, u *User, s *userSettings) error {
|
||||||
_, err = t.Exec("UPDATE collections SET alias = ? WHERE alias = ? AND owner_id = ?", newUsername, u.Username, u.ID)
|
_, err = t.Exec("UPDATE collections SET alias = ? WHERE alias = ? AND owner_id = ?", newUsername, u.Username, u.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Rollback()
|
t.Rollback()
|
||||||
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
if db.isDuplicateKeyErr(err) {
|
||||||
if mysqlErr.Number == mySQLErrDuplicateKey {
|
|
||||||
return impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
return impart.HTTPError{http.StatusConflict, "Username is already taken."}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
log.Error("Unable to update collection: %v", err)
|
log.Error("Unable to update collection: %v", err)
|
||||||
return ErrInternalGeneral
|
return ErrInternalGeneral
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue