راهاندازی مدل مجوزها
در ادامه، به پکیج internal/data میرویم و یک PermissionModel برای مدیریت تعاملات با جداول جدیدمان اضافه میکنیم. فعلاً تنها چیزی که میخواهیم در این مدل بگنجانیم، متد GetAllForUser() است که تمام کدهای مجوز را برای یک کاربر خاص برمیگرداند. ایده این است که بتوانیم از این در handlerها و middlewareهایمان به این صورت استفاده کنیم:
// Return a slice of the permission codes for the user with ID = 1. This would return // something like []string{"movies:read", "movies:write"}. app.models.Permissions.GetAllForUser(1)
در پشت صحنه، دستور SQL که برای دریافت کدهای مجوز یک کاربر خاص نیاز داریم به این صورت است:
SELECT permissions.code FROM permissions INNER JOIN users_permissions ON users_permissions.permission_id = permissions.id INNER JOIN users ON users_permissions.user_id = users.id WHERE users.id = $1
در این کوئری از عبارت INNER JOIN استفاده میکنیم تا جدول permissions را به جدول users_permissions متصل کنیم و سپس دوباره از آن استفاده میکنیم تا آن را به جدول users متصل کنیم. سپس از عبارت WHERE برای فیلتر کردن نتیجه استفاده میکنیم و فقط ردیفهایی را که مربوط به یک user ID خاص هستند باقی میگذاریم.
بیایید با راهاندازی PermissionModel جدید پیش برویم. ابتدا یک فایل جدید internal/data/permissions.go ایجاد کنید:
$ touch internal/data/permissions.go
و سپس کد زیر را اضافه کنید:
package data import ( "context" "database/sql" "time" ) // Define a Permissions slice, which we will use to hold the permission codes (such as // "movies:read" and "movies:write") for a single user. type Permissions []string // Add a helper method to check whether the Permissions slice contains a specific // permission code. func (p Permissions) Include(code string) bool { return slices.Contains(p, code) } // Define the PermissionModel type. type PermissionModel struct { DB *sql.DB } // The GetAllForUser() method returns all permission codes for a specific user in a // Permissions slice. The code in this method should feel very familiar --- it uses the // standard pattern that we've already seen before for retrieving multiple data rows in // an SQL query. func (m PermissionModel) GetAllForUser(userID int64) (Permissions, error) { query := ` SELECT permissions.code FROM permissions INNER JOIN users_permissions ON users_permissions.permission_id = permissions.id INNER JOIN users ON users_permissions.user_id = users.id WHERE users.id = $1` ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() rows, err := m.DB.QueryContext(ctx, query, userID) if err != nil { return nil, err } defer rows.Close() var permissions Permissions for rows.Next() { var permission string err := rows.Scan(&permission) if err != nil { return nil, err } permissions = append(permissions, permission) } if err = rows.Err(); err != nil { return nil, err } return permissions, nil }
سپس آخرین کاری که باید انجام دهیم اضافه کردن PermissionModel به ساختار Model والد است تا برای handlerها و middlewareهایمان در دسترس باشد. به این صورت:
package data ... type Models struct { Movies MovieModel Permissions PermissionModel // Add a new Permissions field. Tokens TokenModel Users UserModel } func NewModels(db *sql.DB) Models { return Models{ Movies: MovieModel{DB: db}, Permissions: PermissionModel{DB: db}, // Initialize a new PermissionModel instance. Tokens: TokenModel{DB: db}, Users: UserModel{DB: db}, } }