<commit_before>package user

import (
	"errors"
	"time"

	"code.google.com/p/go.crypto/bcrypt"
)

type User struct {
	Id       int64     "The user's auto-incremented ID"
	Handle   string    "The user's name"
	Email    string    "The user's email"
	Password string    `schema:"-"` //Do not allow this to be set by users
	Created  time.Time "The creation timestamp of the user's account"

	//Values below here should not be stored in the database
	PlaintextPassword string "Plaintext password. Not stored in the database; used for logging in."
}

func (u *User) GetId() int64 {
	return u.Id
}

func (u *User) Guest() bool {
	if u.Id == 0 {
		return true
	}

	return false
}

func (u *User) Register() (err error) {
	//Make sure they sent us a bcrypt-able password
	err = u.SetPassword(u.PlaintextPassword)
	if err != nil {
		//Fail here to avoid modifying the DB
		return
	}

	//We will now try to store this new user to the database.
	err = u.createInDb()

	return
}

func (u *User) createInDb() (err error) {
	//Wrap in a transaction
	tx, err := db.Begin()

	CreateUserStmt, err := tx.Prepare(queries.UserCreate)
	defer CreateUserStmt.Close()
	if err != nil {
		_ = tx.Rollback()
		return errors.New("Error: We had a database problem.")
	}

	//Note: because pq handles LastInsertId oddly (or not at all?), instead of 
	//calling .Exec() then .LastInsertId, we prepare a statement that ends in 
	//`RETURNING id` and we .QueryRow().Select() the result  
	err = CreateUserStmt.QueryRow(u.Handle, u.Email, u.Password).Scan(&u.Id)
	if err != nil {
		_ = tx.Rollback()
		return errors.New("Error: your username or email address was already found in the database. Please choose differently.")
	}

	//Declare transactional victory
	tx.Commit()

	return
}

//SetPassword takes a plaintext password and hashes it with bcrypt and sets the
//password field to the hash.
func (u *User) SetPassword(password string) (err error) {
	if len(password) < 1 {
		err = errors.New("Error: no password was provided.")
		return
	}

	hpass, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)

	//Regardless of success or failure, we now get rid of the PlaintextPassword value
	u.PlaintextPassword = ""

	if err != nil {
		return
	}
	u.Password = string(h<PASSWORD>)

	return
}

//If a login checks out, return a new user object
func (login *User) Login() (user *User, err error) {
	user, err = FindOneByHandle(login.Handle)
	//If a valid user couldn't be found, the user shall become logged out
	if err != nil {
		user = new(User)
		err = errors.New("The username or password was invalid")
		return
	}

	//If the user account's password validates, update u with the new user object
	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(login.PlaintextPassword))

	//Regardless of success or failure, we now get rid of the PlaintextPassword value
	login.PlaintextPassword = ""

	if err != nil {
		user = new(User)
		err = errors.New("The username or password was invalid")
		return
	}

	return
}

func FindOneByHandle(handle string) (user *User, err error) {
	//Initialize empty user
	user = new(User)

	//Find one or zero existent users
	FindUserStmt, err := db.Prepare(queries.UserFindByHandle)
	if err != nil {
		return
	}
	defer FindUserStmt.Close()

	//Read any found values into the user object
	err = FindUserStmt.QueryRow(handle).Scan(&user.Id, &user.Handle, &user.Email, &user.Password, &user.Created)
	if err != nil {
		user = new(User)
	}

	//If there are no records, the error will be non-nil
	//You may want to obscure this error message elsewhere, 
	//E.g., to hide whether a login failure was due to a non-existent
	//user or a bad password for a real user.  
	return
}

//If a user with this id exists, return a *User object. Otherwise, nil.
func FindOneUserById(id int64) (user *User, err error) {
	//Initialize empty user
	user = new(User)

	//Find one or zero existent users
	FindUserStmt, err := db.Prepare(queries.UserFindById)
	if err != nil {
		return
	}
	defer FindUserStmt.Close()

	//Read any found values into the user object
	err = FindUserStmt.QueryRow(id).Scan(&user.Id, &user.Handle, &user.Email, &user.Password, &user.Created)<commit_msg>Fixed idle db leaks by defer Close()'ing connections before returning due to error.<commit_after>package user

import (
	"errors"
	"time"

	"code.google.com/p/go.crypto/bcrypt"
)

type User struct {
	Id       int64     "The user's auto-incremented ID"
	Handle   string    "The user's name"
	Email    string    "The user's email"
	Password string    `schema:"-"` //Do not allow this to be set by users
	Created  time.Time "The creation timestamp of the user's account"

	//Values below here should not be stored in the database
	PlaintextPassword string "<PASSWORD>. Not stored in the database; used for logging in."
}

func (u *User) GetId() int64 {
	return u.Id
}

func (u *User) Guest() bool {
	if u.Id == 0 {
		return true
	}

	return false
}

func (u *User) Register() (err error) {
	//Make sure they sent us a bcrypt-able password
	err = u.SetPassword(u.PlaintextPassword)
	if err != nil {
		//Fail here to avoid modifying the DB
		return
	}

	//We will now try to store this new user to the database.
	err = u.createInDb()

	return
}

func (u *User) createInDb() (err error) {
	//Wrap in a transaction
	tx, err := db.Begin()

	CreateUserStmt, err := tx.Prepare(queries.UserCreate)
	defer CreateUserStmt.Close()
	if err != nil {
		_ = tx.Rollback()
		return errors.New("Error: We had a database problem.")
	}

	//Note: because pq handles LastInsertId oddly (or not at all?), instead of 
	//calling .Exec() then .LastInsertId, we prepare a statement that ends in 
	//`RETURNING id` and we .QueryRow().Select() the result  
	err = CreateUserStmt.QueryRow(u.Handle, u.Email, u.Password).Scan(&u.Id)
	if err != nil {
		_ = tx.Rollback()
		return errors.New("Error: your username or email address was already found in the database. Please choose differently.")
	}

	//Declare transactional victory
	tx.Commit()

	return
}

//SetPassword takes a plaintext password and hashes it with bcrypt and sets the
//password field to the hash.
func (u *User) SetPassword(password string) (err error) {
	if len(password) < 1 {
		err = errors.New("Error: no password was provided.")
		return
	}

	hpass, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)

	//Regardless of success or failure, we now get rid of the PlaintextPassword value
	u.PlaintextPassword = ""

	if err != nil {
		return
	}
	u.Password = string(hpass)

	return
}

//If a login checks out, return a new user object
func (login *User) Login() (user *User, err error) {
	user, err = FindOneByHandle(login.Handle)
	//If a valid user couldn't be found, the user shall become logged out
	if err != nil {
		user = new(User)
		err = errors.New("The username or password was invalid")
		return
	}

	//If the user account's password validates, update u with the new user object
	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(login.PlaintextPassword))

	//Regardless of success or failure, we now get rid of the PlaintextPassword value
	login.PlaintextPassword = ""

	if err != nil {
		user = new(User)
		err = errors.New("The username or password was invalid")
		return
	}

	return
}

func FindOneByHandle(handle string) (user *User, err error) {
	//Initialize empty user
	user = new(User)

	//Find one or zero existent users
	FindUserStmt, err := db.Prepare(queries.UserFindByHandle)
	defer FindUserStmt.Close()
	if err != nil {
		return
	}

	//Read any found values into the user object
	err = FindUserStmt.QueryRow(handle).Scan(&user.Id, &user.Handle, &user.Email, &user.Password, &user.Created)
	if err != nil {
		user = new(User)
	}

	//If there are no records, the error will be non-nil
	//You may want to obscure this error message elsewhere, 
	//E.g., to hide whether a login failure was due to a non-existent
	//user or a bad password for a real user.  
	return
}

//If a user with this id exists, return a *User object. Otherwise, nil.
func FindOneUserById(id int64) (user *User, err error) {
	//Initialize empty user
	user = new(User)

	//Find one or zero existent users
	FindUserStmt, err := db.Prepare(queries.UserFindById)
	defer FindUserStmt.Close()
	if err != nil {
		return
	}

	//Read any found values into the user object
	err = FindUserStmt.QueryRow(id).Scan(&user.Id, &user.Handle, &user.Email, &user.Password, &user.Created)
{'fraction_non_alphanumeric': 0.11050380228136882, 'fraction_numerical': 0.0019011406844106464, 'mean_word_length': 3.591925804691762, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2569836', 'n_tokens_mistral': 2806, 'n_tokens_neox': 2696, 'n_words': 1030}