Add public feed, admin area, self-registration, visibility & hashtags
Some checks failed
Deploy to NAS / deploy (push) Failing after 26s
Some checks failed
Deploy to NAS / deploy (push) Failing after 26s
- Public feed (/) with infinite scroll via Intersection Observer - Self-registration (/register) - Admin area (/admin/entries, /admin/users) with user management - journal_entries: visibility (public/private) + hashtags fields - users: is_admin flag - DB schema updated (recreate DB to apply) - CI: run go test via docker run (golang:1.25-alpine) — fixes 'go not found' Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ const sessionDuration = 24 * time.Hour
|
||||
|
||||
var ErrInvalidCredentials = errors.New("invalid username or password")
|
||||
var ErrSessionNotFound = errors.New("session not found or expired")
|
||||
var ErrUsernameTaken = errors.New("username already taken")
|
||||
|
||||
type Store struct {
|
||||
pool *pgxpool.Pool
|
||||
@@ -128,6 +129,40 @@ func (s *Store) Logout(ctx context.Context, sessionID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Register creates a new user account. Returns ErrUsernameTaken if the username is already in use.
|
||||
func (s *Store) Register(ctx context.Context, username, password string) error {
|
||||
hash, err := HashPassword(password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("hash password: %w", err)
|
||||
}
|
||||
_, err = s.pool.Exec(ctx,
|
||||
`INSERT INTO users (username, password_hash) VALUES ($1, $2)`,
|
||||
username, hash,
|
||||
)
|
||||
if err != nil && strings.Contains(err.Error(), "unique") {
|
||||
return ErrUsernameTaken
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// GetUserBySession returns the full user (including is_admin) for a session.
|
||||
func (s *Store) GetUserBySession(ctx context.Context, sessionID string) (domain.User, error) {
|
||||
var u domain.User
|
||||
err := s.pool.QueryRow(ctx,
|
||||
`SELECT u.user_id, u.username, u.is_admin, u.created_at
|
||||
FROM sessions s JOIN users u ON s.user_id = u.user_id
|
||||
WHERE s.session_id = $1 AND s.expires_at > NOW()`,
|
||||
sessionID,
|
||||
).Scan(&u.UserID, &u.Username, &u.IsAdmin, &u.CreatedAt)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return domain.User{}, ErrSessionNotFound
|
||||
}
|
||||
return domain.User{}, err
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func newSessionID() (string, error) {
|
||||
b := make([]byte, 32)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user