Let's Go احراز هویت کاربر › ایجاد مدل کاربران
قبلی · فهرست · بعدی
فصل ۱۰.۲.

ایجاد یک مدل کاربر

حالا که مسیرها راه‌اندازی شده‌اند، باید یک جدول پایگاه داده جدید users و یک مدل پایگاه داده برای دسترسی به آن ایجاد کنیم.

با اتصال به MySQL از پنجره ترمینال خود به عنوان کاربر root شروع کنید و دستور SQL زیر را برای راه‌اندازی جدول users اجرا کنید:

USE snippetbox;

CREATE TABLE users (
    id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    hashed_password CHAR(60) NOT NULL,
    created DATETIME NOT NULL
);

ALTER TABLE users ADD CONSTRAINT users_uc_email UNIQUE (email);

چند نکته در مورد این جدول وجود دارد که ارزش اشاره دارد:

ساخت مدل در Go

سپس بیایید یک مدل راه‌اندازی کنیم تا بتوانیم به راحتی با جدول جدید users کار کنیم. همان الگویی را دنبال می‌کنیم که قبلاً در کتاب برای مدل‌سازی دسترسی به جدول snippets استفاده کردیم، بنابراین امیدوارم این باید آشنا و ساده به نظر برسد.

ابتدا، فایل internal/models/errors.go که قبلاً ایجاد کردید را باز کنید و چند نوع خطای جدید تعریف کنید:

File: internal/models/errors.go
package models

import (
    "errors"
)

var (
    ErrNoRecord = errors.New("models: no matching record found")

    // Add a new ErrInvalidCredentials error. We'll use this later if a user
    // tries to login with an incorrect email address or password.
    ErrInvalidCredentials = errors.New("models: invalid credentials")

    // Add a new ErrDuplicateEmail error. We'll use this later if a user
    // tries to signup with an email address that's already in use.
    ErrDuplicateEmail = errors.New("models: duplicate email")
)

سپس یک فایل جدید در internal/models/users.go ایجاد کنید:

$ touch internal/models/users.go

…و یک struct جدید User (برای نگه‌داری داده‌های یک کاربر خاص) و یک struct UserModel (با چند متد placeholder برای تعامل با پایگاه داده ما) تعریف کنید. به این صورت:

File: internal/models/users.go
package models

import (
    "database/sql"
    "time"
)

// Define a new User struct. Notice how the field names and types align
// with the columns in the database "users" table?
type User struct {
    ID             int
    Name           string
    Email          string
    HashedPassword []byte
    Created        time.Time
}

// Define a new UserModel struct which wraps a database connection pool.
type UserModel struct {
    DB *sql.DB
}

// We'll use the Insert method to add a new record to the "users" table.
func (m *UserModel) Insert(name, email, password string) error {
    return nil
}

// We'll use the Authenticate method to verify whether a user exists with
// the provided email address and password. This will return the relevant
// user ID if they do.
func (m *UserModel) Authenticate(email, password string) (int, error) {
    return 0, nil
}

// We'll use the Exists method to check if a user exists with a specific ID.
func (m *UserModel) Exists(id int) (bool, error) {
    return false, nil
}

مرحله نهایی اضافه کردن یک فیلد جدید به struct application ما است تا بتوانیم این مدل را در دسترس handlerهای خود قرار دهیم. فایل main.go را به این صورت به‌روزرسانی کنید:

File: cmd/web/main.go
package main

...

// Add a new users field to the application struct.
type application struct {
    logger        *slog.Logger
    snippets       *models.SnippetModel
    users          *models.UserModel
    templateCache  map[string]*template.Template
    formDecoder    *form.Decoder
    sessionManager *scs.SessionManager
}

func main() {
    
    ...

    // Initialize a models.UserModel instance and add it to the application
    // dependencies.
    app := &application{
        logger:         logger,
        snippets:       &models.SnippetModel{DB: db},
        users:          &models.UserModel{DB: db},
        templateCache:  templateCache,
        formDecoder:    formDecoder,
        sessionManager: sessionManager,
    }

    tlsConfig := &tls.Config{
        CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256},
    }

    srv := &http.Server{
        Addr:         *addr,
        Handler:      app.routes(),
        ErrorLog:     slog.NewLogLogger(logger.Handler(), slog.LevelError),
        TLSConfig:    tlsConfig,
        IdleTimeout:  time.Minute,
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
    }

    logger.Info("starting server", "addr", srv.Addr)

    err = srv.ListenAndServeTLS("./tls/cert.pem", "./tls/key.pem")
    logger.Error(err.Error())
    os.Exit(1)
}

...

اطمینان حاصل کنید که همه فایل‌ها ذخیره شده‌اند، سپس برنامه را اجرا کنید. در این مرحله باید متوجه شوید که بدون هیچ مشکلی کامپایل می‌شود.