Feat: session db methods and try at tx
This commit is contained in:
		| @@ -12,7 +12,6 @@ import ( | |||||||
| 	"html/template" | 	"html/template" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func abortWithError(w http.ResponseWriter, msg string) { | func abortWithError(w http.ResponseWriter, msg string) { | ||||||
| @@ -142,11 +141,12 @@ func makeCookie(username string, remote string) (*http.Cookie, error) { | |||||||
| 	// Create a new random session token | 	// Create a new random session token | ||||||
| 	// sessionToken := xid.New().String() | 	// sessionToken := xid.New().String() | ||||||
| 	sessionToken := "sessionprefix_" + username | 	sessionToken := "sessionprefix_" + username | ||||||
| 	expiresAt := time.Now().Add(time.Duration(cfg.SessionLifetime) * time.Second) | 	// expiresAt := time.Now().Add(time.Duration(cfg.SessionLifetime) * time.Second) | ||||||
| 	// Set the token in the session map, along with the session information | 	// Set the token in the session map, along with the session information | ||||||
| 	session := &models.Session{ | 	session := &models.Session{ | ||||||
| 		Username:    username, | 		Username:    username, | ||||||
| 		Expiry:   expiresAt, | 		CookieToken: sessionToken, | ||||||
|  | 		Lifetime:    uint32(cfg.SessionLifetime / 60), | ||||||
| 	} | 	} | ||||||
| 	cookieName := "session_token" | 	cookieName := "session_token" | ||||||
| 	// hmac to protect cookies | 	// hmac to protect cookies | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ type AllRepos interface { | |||||||
|  |  | ||||||
| type RepoProvider struct { | type RepoProvider struct { | ||||||
| 	DB  *sqlx.DB | 	DB  *sqlx.DB | ||||||
|  | 	Ext sqlx.Ext | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewRepoProvider(pathToDB string) *RepoProvider { | func NewRepoProvider(pathToDB string) *RepoProvider { | ||||||
|   | |||||||
| @@ -1,9 +1,61 @@ | |||||||
| package repos | package repos | ||||||
|  |  | ||||||
| import "gralias/models" | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"gralias/models" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/jmoiron/sqlx" | ||||||
|  | ) | ||||||
|  |  | ||||||
| type SessionsRepo interface { | type SessionsRepo interface { | ||||||
| 	SessionByToken(token string) (*models.Session, error) | 	SessionByToken(ctx context.Context, token string) (*models.Session, error) | ||||||
| 	SessionCreate(req *models.Session) error | 	SessionCreate(ctx context.Context, session *models.Session) error | ||||||
| 	SessionUpdateLifetime(minutes uint32) error | 	SessionUpdate(ctx context.Context, session *models.Session) error | ||||||
|  | 	SessionDelete(ctx context.Context, token string) error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *RepoProvider) SessionByToken(ctx context.Context, token string) (*models.Session, error) { | ||||||
|  | 	session := &models.Session{} | ||||||
|  | 	// The lifetime in the DB is in seconds, but in the model it is in minutes. | ||||||
|  | 	err := p.DB.GetContext(ctx, session, `SELECT id, updated_at, lifetime / 60 as lifetime, cookie_token, username FROM sessions WHERE cookie_token = ?`, token) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return session, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *RepoProvider) SessionCreate(ctx context.Context, session *models.Session) error { | ||||||
|  | 	p.Ext = p.DB | ||||||
|  | 	tx, ok := ctx.Value("sqltx").(*sqlx.Tx) | ||||||
|  | 	if ok && tx != nil { | ||||||
|  | 		// how to know if it is a final exec in chain? | ||||||
|  | 		// or is it better to commit outside? | ||||||
|  | 		tocommit, ok := ctx.Value("tocommit").(bool) | ||||||
|  | 		if ok && tocommit { | ||||||
|  | 			defer func() { | ||||||
|  | 				if err := tx.Commit(); err != nil { | ||||||
|  | 					// log | ||||||
|  | 					// return err | ||||||
|  | 				} | ||||||
|  | 			}() | ||||||
|  | 		} | ||||||
|  | 		p.Ext = tx | ||||||
|  | 	} | ||||||
|  | 	// The lifetime in the model is in minutes, but in the DB it is in seconds. | ||||||
|  | 	_, err := p.Ext.Exec(`INSERT INTO sessions (updated_at, lifetime, cookie_token, username) VALUES (?, ?, ?, ?)`, | ||||||
|  | 		time.Now(), session.Lifetime*60, session.CookieToken, session.Username) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *RepoProvider) SessionUpdate(ctx context.Context, session *models.Session) error { | ||||||
|  | 	// The lifetime in the model is in minutes, but in the DB it is in seconds. | ||||||
|  | 	_, err := p.DB.ExecContext(ctx, `UPDATE sessions SET updated_at = ?, lifetime = ? WHERE cookie_token = ?`, | ||||||
|  | 		time.Now(), session.Lifetime*60, session.CookieToken) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *RepoProvider) SessionDelete(ctx context.Context, token string) error { | ||||||
|  | 	_, err := p.DB.ExecContext(ctx, `DELETE FROM sessions WHERE cookie_token = ?`, token) | ||||||
|  | 	return err | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								todos.md
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								todos.md
									
									
									
									
									
								
							| @@ -1,4 +1,5 @@ | |||||||
| ### feats | ### feats | ||||||
|  | - implement the db methods for sessions in repos/session.go; + | ||||||
| - auto close room if nothing is going on there (hmm) for ~1h; + | - auto close room if nothing is going on there (hmm) for ~1h; + | ||||||
| - words database (file) load and form random 25 words; + | - words database (file) load and form random 25 words; + | ||||||
| - invite link; + | - invite link; + | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Grail Finder
					Grail Finder