├── .circleci └── config.yml ├── .coveralls.yml ├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── LICENSE ├── README.md ├── SECURITY.md ├── collections ├── permission.go └── role.go ├── docs ├── _config.yml └── index.md ├── go.mod ├── go.sum ├── helpers ├── array.go ├── debug.go ├── pagination.go └── string.go ├── models ├── permission.go ├── pivot │ ├── userPermissions.go │ └── userRoles.go └── role.go ├── options ├── permission.go └── role.go ├── permify.go ├── permify_test.go ├── repositories ├── base.go ├── mocks │ ├── permissionRepository.go │ ├── roleRepository.go │ └── userRepository.go ├── permissionRepository.go ├── permissionRepository_test.go ├── repository_test.go ├── roleRepository.go ├── roleRepository_test.go ├── scopes │ └── pagination.go ├── userRepository.go └── userRepository_test.go └── utils └── pagination.go /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Use the latest 2.1 version of CircleCI pipeline process engine. 2 | # See: https://circleci.com/docs/2.0/configuration-reference 3 | version: 2.1 4 | 5 | # Define a job to be invoked later in a workflow. 6 | # See: https://circleci.com/docs/2.0/configuration-reference/#jobs 7 | jobs: 8 | say-hello: 9 | # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. 10 | # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor 11 | docker: 12 | - image: cimg/base:stable 13 | # Add steps to the job 14 | # See: https://circleci.com/docs/2.0/configuration-reference/#steps 15 | steps: 16 | - checkout 17 | - run: 18 | name: "Say hello" 19 | command: "echo Hello, World!" 20 | 21 | # Invoke jobs via workflows 22 | # See: https://circleci.com/docs/2.0/configuration-reference/#workflows 23 | workflows: 24 | say-hello-workflow: 25 | jobs: 26 | - say-hello 27 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: IHCGVLPxLfY9lCYCNvVR7GWJ1LbB6eXlm -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: EgeAytin, tolgaOzen 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Versions** 14 | 15 | Permify-gorm version: 16 | 17 | Go version: 18 | 19 | Gorm version: 20 | 21 | Database driver name: 22 | 23 | Database version: 24 | 25 | **To Reproduce** 26 | Steps to reproduce the behavior: 27 | 28 | Here is a sample of my code and/or tests that demonstrate the issue in my app: 29 | 30 | **Example Application** 31 | Here is a link to my Github repo containing a Go application which shows my problem: 32 | 33 | **Expected behavior** 34 | A clear and concise description of what you expected to happen. 35 | 36 | **Additional context** 37 | Add any other context about the problem here. 38 | 39 | **Environment (please complete the following information, because it helps us investigate better):** 40 | - OS: [e.g. macOS] 41 | - Version [e.g. 22] 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | *.idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Tolga Özen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | Permify logo
4 |

5 | 6 | [![Go Reference](https://pkg.go.dev/badge/github.com/Permify/go-role.svg)](https://pkg.go.dev/github.com/Permify/go-role) 7 | [![Go Report Card](https://goreportcard.com/badge/github.com/Permify/go-role)](https://goreportcard.com/report/github.com/Permify/go-role) 8 | ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/Permify/go-role) 9 | ![GitHub](https://img.shields.io/github/license/Permify/go-role) 10 | [![Twitter Follow](https://img.shields.io/twitter/follow/GetPermify?style=social)](https://twitter.com/GetPermify) 11 | 12 | ## Associate users with roles and permissions 13 | 14 | This package allows you to manage user permissions and roles in your database. 15 | 16 | ## 👇 Setup 17 | 18 | Install 19 | 20 | ```shell 21 | go get github.com/Permify/go-role 22 | ``` 23 | 24 | Run All Tests 25 | 26 | ```shell 27 | go test ./... 28 | ``` 29 | 30 | Get the database driver for gorm that you will be using 31 | 32 | ```shell 33 | # mysql 34 | go get gorm.io/driver/mysql 35 | # or postgres 36 | go get gorm.io/driver/postgres 37 | # or sqlite 38 | go get gorm.io/driver/sqlite 39 | # or sqlserver 40 | go get gorm.io/driver/sqlserver 41 | # or clickhouse 42 | go get gorm.io/driver/clickhouse 43 | ``` 44 | 45 | Import permify. 46 | 47 | ```go 48 | import permify `github.com/Permify/go-role` 49 | ``` 50 | 51 | Initialize the new Permify. 52 | 53 | ```go 54 | // initialize the database. (you can use all gorm's supported databases) 55 | db, _ := gorm.Open(mysql.Open("user:password@tcp(host:3306)/db?charset=utf8&parseTime=True&loc=Local"), &gorm.Config{}) 56 | 57 | // New initializer for Permify 58 | // If migration is true, it generate all tables in the database if they don't exist. 59 | permify, _ := permify.New(permify.Options{ 60 | Migrate: true, 61 | DB: db, 62 | }) 63 | ``` 64 | 65 | ## 🚲 Basic Usage 66 | 67 | This package allows users to be associated with permissions and roles. Each role is associated with multiple permissions. 68 | 69 | ```go 70 | // CreateRole create new role. 71 | // Name parameter is converted to guard name. example: senior $#% associate -> senior-associate. 72 | // If a role with the same name has been created before, it will not create it again. (FirstOrCreate) 73 | // First parameter is role name, second parameter is role description. 74 | err := permify.CreateRole("admin", "role description") 75 | 76 | // CreatePermission create new permission. 77 | // Name parameter is converted to guard name. example: create $#% contact -> create-contact. 78 | // If a permission with the same name has been created before, it will not create it again. (FirstOrCreate) 79 | err := permify.CreatePermission("edit user details", "") 80 | ``` 81 | 82 | Permissions can be added to a role using AddPermissionsToRole method in different ways: 83 | 84 | ```go 85 | // first parameter is role id 86 | err := permify.AddPermissionsToRole(1, "edit user details") 87 | // or 88 | err := permify.AddPermissionsToRole("admin", []string{"edit user details", "create contact"}) 89 | // or 90 | err := permify.AddPermissionsToRole("admin", []uint{1, 3}) 91 | ``` 92 | 93 | With using these methods you can remove and overwrite permissions: 94 | 95 | ```go 96 | // overwrites the permissions of the role according to the permission names or ids. 97 | err := permify.ReplacePermissionsToRole("admin", []string{"edit user details", "create contact"}) 98 | 99 | // remove permissions from role according to the permission names or ids. 100 | err := permify.RemovePermissionsFromRole("admin", []string{"edit user details"}) 101 | ``` 102 | 103 | Basic fetch queries: 104 | 105 | ```go 106 | // Fetch all the roles. (with pagination option). 107 | // If withPermissions is true, it will preload the permissions to the role. 108 | // If pagination is nil, it returns without paging. 109 | roles, totalCount, err := permify.GetAllRoles(options.RoleOption{ 110 | WithPermissions: true, 111 | Pagination: &utils.Pagination{ 112 | Page: 1, 113 | Limit: 1, 114 | }, 115 | }) 116 | 117 | // without paging. 118 | roles, totalCount, err := permify.GetAllRoles(options.RoleOption{ 119 | WithPermissions: false, 120 | }) 121 | 122 | // The data returned is a collection of roles. 123 | // Collections provides a fluent convenient wrapper for working with arrays of data. 124 | fmt.Println(roles.IDs()) 125 | fmt.Println(roles.Names()) 126 | fmt.Println(roles.Permissions().Names()) 127 | 128 | // Fetch all permissions of the user that come with direct and roles. 129 | permissions, _ := permify.GetAllPermissionsOfUser(1) 130 | 131 | // Fetch all direct permissions of the user. (with pagination option) 132 | permissions, totalCount, err := permify.GetDirectPermissionsOfUser(1, options.PermissionOption{ 133 | Pagination: &utils.Pagination{ 134 | Page: 1, 135 | Limit: 10, 136 | }, 137 | }) 138 | ``` 139 | 140 | Controls 141 | 142 | ```go 143 | // does the role or any of the roles have given permission? 144 | can, err := permify.RoleHasPermission("admin", "edit user details") 145 | 146 | // does the role or roles have any of the given permissions? 147 | can, err := permify.RoleHasAnyPermissions([]string{"admin", "manager"}, []string{"edit user details", "create contact"}) 148 | 149 | // does the role or roles have all the given permissions? 150 | can, err := permify.RoleHasAllPermissions("admin", []string{"edit user details", "create contact"}) 151 | 152 | // does the user have the given permission? (including the permissions of the roles) 153 | can, err := permify.UserHasPermission(1, "edit user details") 154 | 155 | // does the user have the given permission? (not including the permissions of the roles) 156 | can, err := permify.UserHasDirectPermission(1, "edit user details") 157 | 158 | // does the user have any of the given permissions? (including the permissions of the roles) 159 | can, err := permify.UserHasAnyPermissions(1, []uint{1, 2}) 160 | 161 | // does the user have all the given roles? 162 | can, err := permify.UserHasAllRoles(1, []string{"admin", "manager"}) 163 | 164 | // does the user have any of the given roles? 165 | can, err := permify.UserHasAnyRoles(1, []string{"admin", "manager"}) 166 | ``` 167 | 168 | 169 | ## 🚘 Using permissions via roles 170 | 171 | ### Adding Role 172 | 173 | Add roles to user according to the role names or ids: 174 | 175 | ```go 176 | // add one role to user 177 | err := permify.AddRolesToUser(1, "admin") 178 | 179 | // you can also add multiple roles at once 180 | err := permify.AddRolesToUser(1, []string{"admin", "manager"}) 181 | // or 182 | err := permify.AddRolesToUser(1, []uint{1,2}) 183 | ``` 184 | 185 | Replace the roles of the user according to the role names or ids: 186 | 187 | ```go 188 | // remove all user roles and add admin role 189 | err := permify.ReplaceRolesToUser(1, "admin") 190 | 191 | // you can also replace multiple roles at once 192 | err := permify.ReplaceRolesToUser(1, []string{"admin", "manager"}) 193 | // or 194 | err := permify.RemoveRolesFromUser(1, []uint{1,2}) 195 | ``` 196 | 197 | Remove the roles of the user according to the role names or ids: 198 | 199 | ```go 200 | // remove one role to user 201 | err := permify.RemoveRolesFromUser(1, "admin") 202 | 203 | // you can also remove multiple roles at once 204 | err := permify.RemoveRolesFromUser(1, []string{"admin", "manager"}) 205 | // or 206 | err := permify.RemoveRolesFromUser(1, []uint{1,2}) 207 | ``` 208 | 209 | Control Roles 210 | 211 | ```go 212 | // does the user have the given role? 213 | can, err := permify.UserHasRole(1, "admin") 214 | 215 | // does the user have all the given roles? 216 | can, err := permify.UserHasAllRoles(1, []string{"admin", "manager"}) 217 | 218 | // does the user have any of the given roles? 219 | can, err := permify.UserHasAnyRoles(1, []string{"admin", "manager"}) 220 | ``` 221 | 222 | Get User's Roles 223 | 224 | ```go 225 | roles, totalCount, err := permify.GetRolesOfUser(1, options.RoleOption{ 226 | WithPermissions: true, // preload role's permissions 227 | Pagination: &utils.Pagination{ 228 | Page: 1, 229 | Limit: 1, 230 | }, 231 | }) 232 | 233 | // the data returned is a collection of roles. 234 | // Collections provides a fluent convenient wrapper for working with arrays of data. 235 | fmt.Println(roles.IDs()) 236 | fmt.Println(roles.Names()) 237 | fmt.Println(roles.Len()) 238 | fmt.Println(roles.Permissions().Names()) 239 | ``` 240 | 241 | Add Permissions to Roles 242 | 243 | ```go 244 | // add one permission to role 245 | // first parameter can be role name or id, second parameter can be permission name(s) or id(s). 246 | err := permify.AddPermissionsToRole("admin", "edit contact details") 247 | 248 | // you can also add multiple permissions at once 249 | err := permify.AddPermissionsToRole("admin", []string{"edit contact details", "delete user"}) 250 | // or 251 | err := permify.AddPermissionsToRole("admin", []uint{1, 2}) 252 | ``` 253 | 254 | Remove Permissions from Roles 255 | 256 | ```go 257 | // remove one permission to role 258 | err := permify.RemovePermissionsFromRole("admin", "edit contact details") 259 | 260 | // you can also add multiple permissions at once 261 | err := permify.RemovePermissionsFromRole("admin", []string{"edit contact details", "delete user"}) 262 | // or 263 | err := permify.RemovePermissionsFromRole("admin", []uint{1, 2}) 264 | ``` 265 | 266 | Control Role's Permissions 267 | 268 | ```go 269 | // does the role or any of the roles have given permission? 270 | can, err := permify.RoleHasPermission([]string{"admin", "manager"}, "edit contact details") 271 | 272 | // does the role or roles have all the given permissions? 273 | can, err := permify.RoleHasAllPermissions("admin", []string{"edit contact details", "delete contact"}) 274 | 275 | // does the role or roles have any of the given permissions? 276 | can, err := permify.RoleHasAnyPermissions(1, []string{"edit contact details", "delete contact"}) 277 | ``` 278 | 279 | Get Role's Permissions 280 | 281 | ```go 282 | permissions, totalCount, err := permify.GetPermissionsOfRoles([]string{"admin", "manager"}, options.PermissionOption{ 283 | Pagination: &utils.Pagination{ 284 | Page: 1, 285 | Limit: 1, 286 | }, 287 | }) 288 | 289 | // the data returned is a collection of permissions. 290 | // Collections provides a fluent convenient wrapper for working with arrays of data. 291 | fmt.Println(permissions.IDs()) 292 | fmt.Println(permissions.Names()) 293 | fmt.Println(permissions.Len()) 294 | ``` 295 | 296 | ## 🚤 Direct Permissions 297 | 298 | ### Adding Direct Permissions 299 | 300 | Add direct permission or permissions to user according to the permission names or ids. 301 | 302 | ```go 303 | // add one permission to user 304 | err := permify.AddPermissionsToUser(1, "edit contact details") 305 | 306 | // you can also add multiple permissions at once 307 | err := permify.AddPermissionsToUser(1, []string{"edit contact details", "create contact"}) 308 | // or 309 | err := permify.AddPermissionsToUser(1, []uint{1,2}) 310 | ``` 311 | 312 | Remove the roles of the user according to the role names or ids: 313 | 314 | ```go 315 | // remove one role to user 316 | err := permify.RemovePermissionsFromUser(1, "edit contact details") 317 | 318 | // you can also remove multiple permissions at once 319 | err := permify.RemovePermissionsFromUser(1, []string{"edit contact details", "create contact"}) 320 | // or 321 | err := permify.RemovePermissionsFromUser(1, []uint{1,2}) 322 | ``` 323 | 324 | Control Permissions 325 | 326 | ```go 327 | // ALL PERMISSIONS 328 | 329 | // does the user have the given permission? (including the permissions of the roles) 330 | can, err := permify.UserHasPermission(1, "edit contact details") 331 | 332 | // does the user have all the given permissions? (including the permissions of the roles) 333 | can, err := permify.UserHasAllPermissions(1, []string{"edit contact details", "delete contact"}) 334 | 335 | // does the user have any of the given permissions? (including the permissions of the roles). 336 | can, err := permify.UserHasAnyPermissions(1, []string{"edit contact details", "delete contact"}) 337 | 338 | // DIRECT PERMISSIONS 339 | 340 | // does the user have the given permission? (not including the permissions of the roles) 341 | can, err := permify.UserHasDirectPermission(1, "edit contact details") 342 | 343 | // does the user have all the given permissions? (not including the permissions of the roles) 344 | can, err := permify.UserHasAllDirectPermissions(1, []string{"edit contact details", "delete contact"}) 345 | 346 | // does the user have any of the given permissions? (not including the permissions of the roles) 347 | can, err := permify.UserHasAnyDirectPermissions(1, []string{"edit contact details", "delete contact"}) 348 | ``` 349 | 350 | Get User's All Permissions 351 | 352 | ```go 353 | permissions, err := permify.GetAllPermissionsOfUser(1) 354 | 355 | // the data returned is a collection of permissions. 356 | // Collections provides a fluent convenient wrapper for working with arrays of data. 357 | fmt.Println(permissions.IDs()) 358 | fmt.Println(permissions.Names()) 359 | fmt.Println(permissions.Len()) 360 | ``` 361 | 362 | Get User's Direct Permissions 363 | 364 | ```go 365 | permissions, totalCount, err := permify.GetDirectPermissionsOfUser(1, options.PermissionOption{ 366 | Pagination: &utils.Pagination{ 367 | Page: 1, 368 | Limit: 10, 369 | }, 370 | }) 371 | 372 | // the data returned is a collection of permissions. 373 | // Collections provides a fluent convenient wrapper for working with arrays of data. 374 | fmt.Println(permissions.IDs()) 375 | fmt.Println(permissions.Names()) 376 | fmt.Println(permissions.Len()) 377 | ``` 378 | 379 | ## 🚀 Using your user model 380 | 381 | You can create the relationships between the user and the role and permissions in this manner. In this way: 382 | 383 | - You can manage user preloads 384 | - You can create foreign key between users and pivot tables (user_roles, user_permissions). 385 | 386 | ```go 387 | import ( 388 | "gorm.io/gorm" 389 | models `github.com/Permify/go-role/models` 390 | ) 391 | 392 | type User struct { 393 | gorm.Model 394 | Name string 395 | 396 | // permify 397 | Roles []models.Role `gorm:"many2many:user_roles;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` 398 | Permissions []models.Permission `gorm:"many2many:user_permissions;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` 399 | } 400 | ``` 401 | 402 | ## ⁉️ Error Handling 403 | 404 | ### ErrRecordNotFound 405 | 406 | You can use error handling in the same way as gorm. for example: 407 | 408 | ```go 409 | // check if returns RecordNotFound error 410 | permission, err := permify.GetPermission(1) 411 | if errors.Is(err, gorm.ErrRecordNotFound) { 412 | // record not found 413 | } 414 | ``` 415 | 416 | ### Errors 417 | 418 | [Errors List](https://github.com/go-gorm/gorm/blob/master/errors.go) 419 | 420 | 421 | Stargazers 422 | ----------- 423 | 424 | [![Stargazers repo roster for @Permify/go-role](https://reporoster.com/stars/Permify/go-role)](https://github.com/Permify/go-role/stargazers) 425 | 426 | 427 | ## Community & Support 428 | Join our [Discord channel](https://discord.gg/MJbUjwskdH) for issues, feature requests, feedbacks or anything else. We love to talk about authorization and access control :heart: 429 | 430 |

431 | 432 | permify | Discord 433 | 434 | 435 | permify | Twitter 436 | 437 | 438 | permify | Linkedin 439 | 440 |

441 | 442 | 443 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | If you discover any security related issues, please email tolga@permify.co or ege@permify.co instead of using the issue tracker. 4 | -------------------------------------------------------------------------------- /collections/permission.go: -------------------------------------------------------------------------------- 1 | package collections 2 | 3 | import ( 4 | "github.com/Permify/go-role/models" 5 | ) 6 | 7 | // Permission provides methods for you to manage array data more easily. 8 | type Permission []models.Permission 9 | 10 | // Origin convert the collection to permission array. 11 | // @return []models.Permission 12 | func (u Permission) Origin() []models.Permission { 13 | return []models.Permission(u) 14 | } 15 | 16 | // Len returns the number of elements of the array. 17 | // @return int64 18 | func (u Permission) Len() (length int64) { 19 | return int64(len(u)) 20 | } 21 | 22 | // IDs returns an array of the permission array's ids. 23 | // @return []uint 24 | func (u Permission) IDs() (IDs []uint) { 25 | for _, permission := range u { 26 | IDs = append(IDs, permission.ID) 27 | } 28 | return IDs 29 | } 30 | 31 | // Names returns an array of the permission array's names. 32 | // @return []string 33 | func (u Permission) Names() (names []string) { 34 | for _, permission := range u { 35 | names = append(names, permission.Name) 36 | } 37 | return names 38 | } 39 | 40 | // GuardNames returns an array of the permission array's guard names. 41 | // @return []string 42 | func (u Permission) GuardNames() (guards []string) { 43 | for _, permission := range u { 44 | guards = append(guards, permission.GuardName) 45 | } 46 | return guards 47 | } 48 | -------------------------------------------------------------------------------- /collections/role.go: -------------------------------------------------------------------------------- 1 | package collections 2 | 3 | import ( 4 | "github.com/Permify/go-role/helpers" 5 | "github.com/Permify/go-role/models" 6 | ) 7 | 8 | // Role provides methods for you to manage array data more easily. 9 | type Role []models.Role 10 | 11 | // Origin convert the collection to role array. 12 | // @return []models.Role 13 | func (u Role) Origin() []models.Role { 14 | return []models.Role(u) 15 | } 16 | 17 | // Len returns the number of elements of the array. 18 | // @return int64 19 | func (u Role) Len() (length int64) { 20 | return int64(len(u)) 21 | } 22 | 23 | // IDs returns an array of the role array's ids. 24 | // @return []uint 25 | func (u Role) IDs() (IDs []uint) { 26 | for _, role := range u { 27 | IDs = append(IDs, role.ID) 28 | } 29 | return IDs 30 | } 31 | 32 | // Names returns an array of the role array's names. 33 | // @return []string 34 | func (u Role) Names() (names []string) { 35 | for _, role := range u { 36 | names = append(names, role.Name) 37 | } 38 | return names 39 | } 40 | 41 | // GuardNames returns an array of the permission array's guard names. 42 | // @return []string 43 | func (u Role) GuardNames() (guards []string) { 44 | for _, role := range u { 45 | guards = append(guards, role.GuardName) 46 | } 47 | return guards 48 | } 49 | 50 | // Permissions returns uniquely the permissions of the roles in the role collection. 51 | // @return Permission 52 | func (u Role) Permissions() (permissions Permission) { 53 | var IDs []uint 54 | for _, a := range u { 55 | if len(a.Permissions) > 0 { 56 | for _, prm := range a.Permissions { 57 | if !helpers.InArray(prm.ID, IDs) { 58 | permissions = append(permissions, prm) 59 | } 60 | IDs = append(IDs, prm.ID) 61 | } 62 | } 63 | } 64 | return 65 | } 66 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-midnight -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | 2 | ![permify-gorm](https://user-images.githubusercontent.com/39353278/157410086-42e02752-d5a9-4c64-bdc3-d3a203a247d7.png) 3 | 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/Permify/permify-gorm)](https://goreportcard.com/report/github.com/Permify/permify-gorm) 5 | ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/Permify/permify-gorm) 6 | ![GitHub](https://img.shields.io/github/license/Permify/permify-gorm) 7 | 8 | ## Role Based Access Control (RBAC) for your go application 9 | 10 | This package allows you to manage user permissions and roles in your database. 11 | 12 | 13 | ## 👇 Setup 14 | 15 | Install 16 | 17 | ```shell 18 | go get github.com/Permify/permify-gorm 19 | ``` 20 | 21 | Run All Tests 22 | 23 | ```shell 24 | go test ./... 25 | ``` 26 | 27 | Get the database driver for gorm that you will be using 28 | 29 | ```shell 30 | # mysql 31 | go get gorm.io/driver/mysql 32 | # or postgres 33 | go get gorm.io/driver/postgres 34 | # or sqlite 35 | go get gorm.io/driver/sqlite 36 | # or sqlserver 37 | go get gorm.io/driver/sqlserver 38 | # or clickhouse 39 | go get gorm.io/driver/clickhouse 40 | ``` 41 | 42 | Import permify. 43 | 44 | ```go 45 | import permify `github.com/Permify/permify-gorm` 46 | ``` 47 | 48 | Initialize the new Permify. 49 | 50 | ```go 51 | // initialize the database. (you can use all gorm's supported databases) 52 | db, _ := gorm.Open(mysql.Open("user:password@tcp(host:3306)/db?charset=utf8&parseTime=True&loc=Local"), &gorm.Config{}) 53 | 54 | // New initializer for Permify 55 | // If migration is true, it generate all tables in the database if they don't exist. 56 | permify, _ := permify.New(permify.Options{ 57 | Migrate: true, 58 | DB: db, 59 | }) 60 | ``` 61 | 62 | ## 🚲 Basic Usage 63 | 64 | This package allows users to be associated with permissions and roles. Each role is associated with multiple permissions. 65 | 66 | ```go 67 | // CreateRole create new role. 68 | // Name parameter is converted to guard name. example: senior $#% associate -> senior-associate. 69 | // If a role with the same name has been created before, it will not create it again. (FirstOrCreate) 70 | // First parameter is role name, second parameter is role description. 71 | err := permify.CreateRole("admin", "role description") 72 | 73 | // CreatePermission create new permission. 74 | // Name parameter is converted to guard name. example: create $#% contact -> create-contact. 75 | // If a permission with the same name has been created before, it will not create it again. (FirstOrCreate) 76 | err := permify.CreatePermission("edit user details", "") 77 | ``` 78 | 79 | Permissions can be added to a role using AddPermissionsToRole method in different ways: 80 | 81 | ```go 82 | // first parameter is role id 83 | err := permify.AddPermissionsToRole(1, "edit user details") 84 | // or 85 | err := permify.AddPermissionsToRole("admin", []string{"edit user details", "create contact"}) 86 | // or 87 | err := permify.AddPermissionsToRole("admin", []uint{1, 3}) 88 | ``` 89 | 90 | With using these methods you can remove and overwrite permissions: 91 | 92 | ```go 93 | // overwrites the permissions of the role according to the permission names or ids. 94 | err := permify.ReplacePermissionsToRole("admin", []string{"edit user details", "create contact"}) 95 | 96 | // remove permissions from role according to the permission names or ids. 97 | err := permify.RemovePermissionsFromRole("admin", []string{"edit user details"}) 98 | ``` 99 | 100 | Basic fetch queries: 101 | 102 | ```go 103 | // Fetch all the roles. (with pagination option). 104 | // If withPermissions is true, it will preload the permissions to the role. 105 | // If pagination is nil, it returns without paging. 106 | roles, totalCount, err := permify.GetAllRoles(options.RoleOption{ 107 | WithPermissions: true, 108 | Pagination: &utils.Pagination{ 109 | Page: 1, 110 | Limit: 1, 111 | }, 112 | }) 113 | 114 | // without paging. 115 | roles, totalCount, err := permify.GetAllRoles(options.RoleOption{ 116 | WithPermissions: false, 117 | }) 118 | 119 | // The data returned is a collection of roles. 120 | // Collections provides a fluent convenient wrapper for working with arrays of data. 121 | fmt.Println(roles.IDs()) 122 | fmt.Println(roles.Names()) 123 | fmt.Println(roles.Permissions().Names()) 124 | 125 | // Fetch all permissions of the user that come with direct and roles. 126 | permissions, _ := permify.GetAllPermissionsOfUser(1) 127 | 128 | // Fetch all direct permissions of the user. (with pagination option) 129 | permissions, totalCount, err := permify.GetDirectPermissionsOfUser(1, options.PermissionOption{ 130 | Pagination: &utils.Pagination{ 131 | Page: 1, 132 | Limit: 10, 133 | }, 134 | }) 135 | ``` 136 | 137 | Controls 138 | 139 | ```go 140 | // does the role or any of the roles have given permission? 141 | can, err := permify.RoleHasPermission("admin", "edit user details") 142 | 143 | // does the role or roles have any of the given permissions? 144 | can, err := permify.RoleHasAnyPermissions([]string{"admin", "manager"}, []string{"edit user details", "create contact"}) 145 | 146 | // does the role or roles have all the given permissions? 147 | can, err := permify.RoleHasAllPermissions("admin", []string{"edit user details", "create contact"}) 148 | 149 | // does the user have the given permission? (including the permissions of the roles) 150 | can, err := permify.UserHasPermission(1, "edit user details") 151 | 152 | // does the user have the given permission? (not including the permissions of the roles) 153 | can, err := permify.UserHasDirectPermission(1, "edit user details") 154 | 155 | // does the user have any of the given permissions? (including the permissions of the roles) 156 | can, err := permify.UserHasAnyPermissions(1, []uint{1, 2}) 157 | 158 | // does the user have all the given roles? 159 | can, err := permify.UserHasAllRoles(1, []string{"admin", "manager"}) 160 | 161 | // does the user have any of the given roles? 162 | can, err := permify.UserHasAnyRoles(1, []string{"admin", "manager"}) 163 | ``` 164 | 165 | 166 | ## 🚘 Using permissions via roles 167 | 168 | ### Adding Role 169 | 170 | Add roles to user according to the role names or ids: 171 | 172 | ```go 173 | // add one role to user 174 | err := permify.AddRolesToUser(1, "admin") 175 | 176 | // you can also add multiple roles at once 177 | err := permify.AddRolesToUser(1, []string{"admin", "manager"}) 178 | // or 179 | err := permify.AddRolesToUser(1, []uint{1,2}) 180 | ``` 181 | 182 | Replace the roles of the user according to the role names or ids: 183 | 184 | ```go 185 | // remove all user roles and add admin role 186 | err := permify.ReplaceRolesToUser(1, "admin") 187 | 188 | // you can also replace multiple roles at once 189 | err := permify.ReplaceRolesToUser(1, []string{"admin", "manager"}) 190 | // or 191 | err := permify.RemoveRolesFromUser(1, []uint{1,2}) 192 | ``` 193 | 194 | Remove the roles of the user according to the role names or ids: 195 | 196 | ```go 197 | // remove one role to user 198 | err := permify.RemoveRolesFromUser(1, "admin") 199 | 200 | // you can also remove multiple roles at once 201 | err := permify.RemoveRolesFromUser(1, []string{"admin", "manager"}) 202 | // or 203 | err := permify.RemoveRolesFromUser(1, []uint{1,2}) 204 | ``` 205 | 206 | Control Roles 207 | 208 | ```go 209 | // does the user have the given role? 210 | can, err := permify.UserHasRole(1, "admin") 211 | 212 | // does the user have all the given roles? 213 | can, err := permify.UserHasAllRoles(1, []string{"admin", "manager"}) 214 | 215 | // does the user have any of the given roles? 216 | can, err := permify.UserHasAnyRoles(1, []string{"admin", "manager"}) 217 | ``` 218 | 219 | Get User's Roles 220 | 221 | ```go 222 | roles, totalCount, err := permify.GetRolesOfUser(1, options.RoleOption{ 223 | WithPermissions: true, // preload role's permissions 224 | Pagination: &utils.Pagination{ 225 | Page: 1, 226 | Limit: 1, 227 | }, 228 | }) 229 | 230 | // the data returned is a collection of roles. 231 | // Collections provides a fluent convenient wrapper for working with arrays of data. 232 | fmt.Println(roles.IDs()) 233 | fmt.Println(roles.Names()) 234 | fmt.Println(roles.Len()) 235 | fmt.Println(roles.Permissions().Names()) 236 | ``` 237 | 238 | Add Permissions to Roles 239 | 240 | ```go 241 | // add one permission to role 242 | // first parameter can be role name or id, second parameter can be permission name(s) or id(s). 243 | err := permify.AddPermissionsToRole("admin", "edit contact details") 244 | 245 | // you can also add multiple permissions at once 246 | err := permify.AddPermissionsToRole("admin", []string{"edit contact details", "delete user"}) 247 | // or 248 | err := permify.AddPermissionsToRole("admin", []uint{1, 2}) 249 | ``` 250 | 251 | Remove Permissions from Roles 252 | 253 | ```go 254 | // remove one permission to role 255 | err := permify.RemovePermissionsFromRole("admin", "edit contact details") 256 | 257 | // you can also add multiple permissions at once 258 | err := permify.RemovePermissionsFromRole("admin", []string{"edit contact details", "delete user"}) 259 | // or 260 | err := permify.RemovePermissionsFromRole("admin", []uint{1, 2}) 261 | ``` 262 | 263 | Control Role's Permissions 264 | 265 | ```go 266 | // does the role or any of the roles have given permission? 267 | can, err := permify.RoleHasPermission([]string{"admin", "manager"}, "edit contact details") 268 | 269 | // does the role or roles have all the given permissions? 270 | can, err := permify.RoleHasAllPermissions("admin", []string{"edit contact details", "delete contact"}) 271 | 272 | // does the role or roles have any of the given permissions? 273 | can, err := permify.RoleHasAnyPermissions(1, []string{"edit contact details", "delete contact"}) 274 | ``` 275 | 276 | Get Role's Permissions 277 | 278 | ```go 279 | permissions, totalCount, err := permify.GetPermissionsOfRoles([]string{"admin", "manager"}, options.PermissionOption{ 280 | Pagination: &utils.Pagination{ 281 | Page: 1, 282 | Limit: 1, 283 | }, 284 | }) 285 | 286 | // the data returned is a collection of permissions. 287 | // Collections provides a fluent convenient wrapper for working with arrays of data. 288 | fmt.Println(permissions.IDs()) 289 | fmt.Println(permissions.Names()) 290 | fmt.Println(permissions.Len()) 291 | ``` 292 | 293 | ## 🚤 Direct Permissions 294 | 295 | ### Adding Direct Permissions 296 | 297 | Add direct permission or permissions to user according to the permission names or ids. 298 | 299 | ```go 300 | // add one permission to user 301 | err := permify.AddPermissionsToUser(1, "edit contact details") 302 | 303 | // you can also add multiple permissions at once 304 | err := permify.AddPermissionsToUser(1, []string{"edit contact details", "create contact"}) 305 | // or 306 | err := permify.AddPermissionsToUser(1, []uint{1,2}) 307 | ``` 308 | 309 | Remove the roles of the user according to the role names or ids: 310 | 311 | ```go 312 | // remove one role to user 313 | err := permify.RemovePermissionsFromUser(1, "edit contact details") 314 | 315 | // you can also remove multiple permissions at once 316 | err := permify.RemovePermissionsFromUser(1, []string{"edit contact details", "create contact"}) 317 | // or 318 | err := permify.RemovePermissionsFromUser(1, []uint{1,2}) 319 | ``` 320 | 321 | Control Permissions 322 | 323 | ```go 324 | // ALL PERMISSIONS 325 | 326 | // does the user have the given permission? (including the permissions of the roles) 327 | can, err := permify.UserHasPermission(1, "edit contact details") 328 | 329 | // does the user have all the given permissions? (including the permissions of the roles) 330 | can, err := permify.UserHasAllPermissions(1, []string{"edit contact details", "delete contact"}) 331 | 332 | // does the user have any of the given permissions? (including the permissions of the roles). 333 | can, err := permify.UserHasAnyPermissions(1, []string{"edit contact details", "delete contact"}) 334 | 335 | // DIRECT PERMISSIONS 336 | 337 | // does the user have the given permission? (not including the permissions of the roles) 338 | can, err := permify.UserHasDirectPermission(1, "edit contact details") 339 | 340 | // does the user have all the given permissions? (not including the permissions of the roles) 341 | can, err := permify.UserHasAllDirectPermissions(1, []string{"edit contact details", "delete contact"}) 342 | 343 | // does the user have any of the given permissions? (not including the permissions of the roles) 344 | can, err := permify.UserHasAnyDirectPermissions(1, []string{"edit contact details", "delete contact"}) 345 | ``` 346 | 347 | Get User's All Permissions 348 | 349 | ```go 350 | permissions, err := permify.GetAllPermissionsOfUser(1) 351 | 352 | // the data returned is a collection of permissions. 353 | // Collections provides a fluent convenient wrapper for working with arrays of data. 354 | fmt.Println(permissions.IDs()) 355 | fmt.Println(permissions.Names()) 356 | fmt.Println(permissions.Len()) 357 | ``` 358 | 359 | Get User's Direct Permissions 360 | 361 | ```go 362 | permissions, totalCount, err := permify.GetDirectPermissionsOfUser(1, options.PermissionOption{ 363 | Pagination: &utils.Pagination{ 364 | Page: 1, 365 | Limit: 10, 366 | }, 367 | }) 368 | 369 | // the data returned is a collection of permissions. 370 | // Collections provides a fluent convenient wrapper for working with arrays of data. 371 | fmt.Println(permissions.IDs()) 372 | fmt.Println(permissions.Names()) 373 | fmt.Println(permissions.Len()) 374 | ``` 375 | 376 | ## 🚀 Using your user model 377 | 378 | You can create the relationships between the user and the role and permissions in this manner. In this way: 379 | 380 | - You can manage user preloads 381 | - You can create foreign key between users and pivot tables (user_roles, user_permissions). 382 | 383 | ```go 384 | import ( 385 | "gorm.io/gorm" 386 | models `github.com/Permify/permify-gorm/models` 387 | ) 388 | 389 | type User struct { 390 | gorm.Model 391 | Name string 392 | 393 | // permify 394 | Roles []models.Role `gorm:"many2many:user_roles;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` 395 | Permissions []models.Permission `gorm:"many2many:user_permissions;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` 396 | } 397 | ``` 398 | 399 | ## ⁉️ Error Handling 400 | 401 | ### ErrRecordNotFound 402 | 403 | You can use error handling in the same way as gorm. for example: 404 | 405 | ```go 406 | // check if returns RecordNotFound error 407 | permission, err := permify.GetPermission(1) 408 | if errors.Is(err, gorm.ErrRecordNotFound) { 409 | // record not found 410 | } 411 | ``` 412 | 413 | ### Errors 414 | 415 | [Errors List](https://github.com/go-gorm/gorm/blob/master/errors.go) 416 | 417 | 418 | ## Need More, Check Out our API 419 | 420 | Permify API is an authorization API which you can add complex rbac and abac solutions. 421 | 422 | [](https://www.permify.co/get-started) 423 | 424 | 425 |

:heart: Let's get connected:

426 | 427 |

428 | 429 | guilyx | Twitter 430 | 431 | 432 | guilyx's LinkdeIN 433 | 434 |

435 | 436 | 437 | [comment]: <> (![permify-gorm-draw-sql](https://user-images.githubusercontent.com/39353278/157461050-0a146e7c-9ba7-4956-90a9-4720190a2c82.png)) 438 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Permify/go-role 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/DATA-DOG/go-sqlmock v1.5.0 7 | github.com/davecgh/go-spew v1.1.1 8 | github.com/gosimple/slug v1.12.0 9 | github.com/onsi/ginkgo v1.16.5 10 | github.com/onsi/gomega v1.18.1 11 | github.com/stretchr/testify v1.7.0 12 | gorm.io/driver/postgres v1.3.1 13 | gorm.io/gorm v1.23.2 14 | ) 15 | 16 | require ( 17 | github.com/fsnotify/fsnotify v1.4.9 // indirect 18 | github.com/gosimple/unidecode v1.0.1 // indirect 19 | github.com/jackc/chunkreader/v2 v2.0.1 // indirect 20 | github.com/jackc/pgconn v1.10.1 // indirect 21 | github.com/jackc/pgio v1.0.0 // indirect 22 | github.com/jackc/pgpassfile v1.0.0 // indirect 23 | github.com/jackc/pgproto3/v2 v2.2.0 // indirect 24 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect 25 | github.com/jackc/pgtype v1.9.1 // indirect 26 | github.com/jackc/pgx/v4 v4.14.1 // indirect 27 | github.com/jinzhu/inflection v1.0.0 // indirect 28 | github.com/jinzhu/now v1.1.4 // indirect 29 | github.com/nxadm/tail v1.4.8 // indirect 30 | github.com/pmezard/go-difflib v1.0.0 // indirect 31 | github.com/stretchr/objx v0.2.0 // indirect 32 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect 33 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect 34 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect 35 | golang.org/x/text v0.3.7 // indirect 36 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect 37 | gopkg.in/yaml.v2 v2.4.0 // indirect 38 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 39 | ) 40 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= 3 | github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= 4 | github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= 5 | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 6 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 7 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 8 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 9 | github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= 10 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 11 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 12 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 13 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 14 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 16 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 18 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 19 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 20 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 21 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 22 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 23 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 24 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= 25 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 26 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 27 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 28 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 29 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 30 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 31 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 32 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 33 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 34 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 35 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 36 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 37 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 38 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 39 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 40 | github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 41 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 42 | github.com/gosimple/slug v1.12.0 h1:xzuhj7G7cGtd34NXnW/yF0l+AGNfWqwgh/IXgFy7dnc= 43 | github.com/gosimple/slug v1.12.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= 44 | github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= 45 | github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= 46 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 47 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 48 | github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= 49 | github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= 50 | github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 51 | github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= 52 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 53 | github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= 54 | github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= 55 | github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= 56 | github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= 57 | github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= 58 | github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 59 | github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8= 60 | github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 61 | github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= 62 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= 63 | github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= 64 | github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= 65 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= 66 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 67 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 68 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 69 | github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= 70 | github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= 71 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= 72 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= 73 | github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 74 | github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 75 | github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 76 | github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 77 | github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= 78 | github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 79 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= 80 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= 81 | github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= 82 | github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= 83 | github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= 84 | github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= 85 | github.com/jackc/pgtype v1.9.1 h1:MJc2s0MFS8C3ok1wQTdQxWuXQcB6+HwAm5x1CzW7mf0= 86 | github.com/jackc/pgtype v1.9.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= 87 | github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= 88 | github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= 89 | github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= 90 | github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= 91 | github.com/jackc/pgx/v4 v4.14.1 h1:71oo1KAGI6mXhLiTMn6iDFcp3e7+zon/capWjl2OEFU= 92 | github.com/jackc/pgx/v4 v4.14.1/go.mod h1:RgDuE4Z34o7XE92RpLsvFiOEfrAUT0Xt2KxvX73W06M= 93 | github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 94 | github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 95 | github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 96 | github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 97 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 98 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 99 | github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= 100 | github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 101 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 102 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 103 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 104 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 105 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 106 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 107 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 108 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 109 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 110 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 111 | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 112 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 113 | github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= 114 | github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 115 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 116 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 117 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 118 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 119 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 120 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 121 | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= 122 | github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 123 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 124 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 125 | github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= 126 | github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= 127 | github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= 128 | github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ= 129 | github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= 130 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 131 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 132 | github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= 133 | github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= 134 | github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= 135 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 136 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 137 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 138 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 139 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 140 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= 141 | github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 142 | github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= 143 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 144 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 145 | github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= 146 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 147 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 148 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 149 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 150 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 151 | github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= 152 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 153 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 154 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 155 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 156 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 157 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 158 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 159 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 160 | github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= 161 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 162 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 163 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 164 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 165 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 166 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 167 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 168 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 169 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 170 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 171 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 172 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 173 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 174 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 175 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 176 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 177 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 178 | golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 179 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 180 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 181 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= 182 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 183 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 184 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 185 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 186 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 187 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 188 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 189 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 190 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 191 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 192 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 193 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 194 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 195 | golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= 196 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= 197 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 198 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 199 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 200 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 201 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 202 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 203 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 204 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 205 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 206 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 207 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 208 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 209 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 210 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 211 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 212 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 213 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 214 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 215 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 216 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 217 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 218 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 219 | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 220 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 221 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 222 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= 223 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 224 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 225 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 226 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 227 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 228 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 229 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 230 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 231 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 232 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 233 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 234 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 235 | golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 236 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 237 | golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 238 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 239 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 240 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 241 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 242 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 243 | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 244 | golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 245 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 246 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 247 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 248 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 249 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 250 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 251 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 252 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 253 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 254 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 255 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 256 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 257 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 258 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 259 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 260 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 261 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 262 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 263 | gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= 264 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 265 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 266 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 267 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 268 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 269 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 270 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 271 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 272 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 273 | gorm.io/driver/postgres v1.3.1 h1:Pyv+gg1Gq1IgsLYytj/S2k7ebII3CzEdpqQkPOdH24g= 274 | gorm.io/driver/postgres v1.3.1/go.mod h1:WwvWOuR9unCLpGWCL6Y3JOeBWvbKi6JLhayiVclSZZU= 275 | gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= 276 | gorm.io/gorm v1.23.2 h1:xmq9QRMWL8HTJyhAUBXy8FqIIQCYESeKfJL4DoGKiWQ= 277 | gorm.io/gorm v1.23.2/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= 278 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 279 | -------------------------------------------------------------------------------- /helpers/array.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // InArray is the value in the first parameter an element of the array in the second parameter? 8 | // @param interface{} 9 | // @param interface{} 10 | // return bool 11 | func InArray(val interface{}, array interface{}) (exists bool) { 12 | exists = false 13 | switch reflect.TypeOf(array).Kind() { 14 | case reflect.Slice: 15 | s := reflect.ValueOf(array) 16 | for i := 0; i < s.Len(); i++ { 17 | if reflect.DeepEqual(val, s.Index(i).Interface()) == true { 18 | exists = true 19 | return 20 | } 21 | } 22 | } 23 | return 24 | } 25 | 26 | // JoinUintArrays concatenates the given uint arrays and makes them a single array. 27 | // @param ...[]uint 28 | // return []uint 29 | func JoinUintArrays(array ...[]uint) (j []uint) { 30 | for _, a := range array { 31 | for _, b := range a { 32 | j = append(j, b) 33 | } 34 | } 35 | return 36 | } 37 | 38 | // RemoveDuplicateValues make singular of repeating values in an array. 39 | // @param []uint 40 | // return []uint 41 | func RemoveDuplicateValues(intSlice []uint) []uint { 42 | keys := make(map[uint]bool) 43 | list := []uint{} 44 | for _, entry := range intSlice { 45 | if _, value := keys[entry]; !value { 46 | keys[entry] = true 47 | list = append(list, entry) 48 | } 49 | } 50 | return list 51 | } 52 | -------------------------------------------------------------------------------- /helpers/debug.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/davecgh/go-spew/spew" 7 | ) 8 | 9 | // Pre exit running project. 10 | // @param interface{} 11 | // @param ...interface{} 12 | func Pre(x interface{}, y ...interface{}) { 13 | spew.Dump(x) 14 | os.Exit(1) 15 | } 16 | -------------------------------------------------------------------------------- /helpers/pagination.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | // NextPageCal calculate next page according to the page number and total page count. 8 | // @param int 9 | // @param int 10 | // return int 11 | func NextPageCal(page int, totalPage int) int { 12 | if page == totalPage { 13 | return page 14 | } 15 | return page + 1 16 | } 17 | 18 | // PrevPageCal calculate previous page according to page number. 19 | // @param int 20 | // return int 21 | func PrevPageCal(page int) int { 22 | if page > 1 { 23 | return page - 1 24 | } 25 | return page 26 | } 27 | 28 | // TotalPage calculate total page according to records count and limit. 29 | // @param int64 30 | // @param int 31 | // return int 32 | func TotalPage(count int64, limit int) int { 33 | return int(math.Ceil(float64(count) / float64(limit))) 34 | } 35 | 36 | // OffsetCal calculate offset according to page and limit. 37 | // @param int 38 | // @param int 39 | // return int 40 | func OffsetCal(page int, limit int) int { 41 | return (page - 1) * limit 42 | } 43 | -------------------------------------------------------------------------------- /helpers/string.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/gosimple/slug" 7 | ) 8 | 9 | // Guard edits the given string. 10 | // example: 'create $#% contact' -> 'create-contact'. 11 | // @param string 12 | // @param string 13 | // return bool 14 | func Guard(b string) string { 15 | return slug.Make(b) 16 | } 17 | 18 | // GuardArray edits the given string array. 19 | // example: 'create $#% contact' -> 'create-contact'. 20 | // @param []string 21 | // return []string 22 | func GuardArray(b []string) (guardArray []string) { 23 | for _, c := range b { 24 | guardArray = append(guardArray, slug.Make(c)) 25 | } 26 | return 27 | } 28 | 29 | // IsInt is the given value an integer? 30 | // @param interface{} 31 | // return bool 32 | func IsInt(value interface{}) bool { 33 | if reflect.TypeOf(value).Kind() == reflect.Int { 34 | return true 35 | } 36 | return false 37 | } 38 | 39 | // IsUInt is the given value an unsigned integer? 40 | // @param interface{} 41 | // return bool 42 | func IsUInt(value interface{}) bool { 43 | if reflect.TypeOf(value).Kind() == reflect.Uint { 44 | return true 45 | } 46 | return false 47 | } 48 | 49 | // IsUIntArray is the given value an unsigned integer array? 50 | // @param interface{} 51 | // return bool 52 | func IsUIntArray(value interface{}) bool { 53 | t := reflect.TypeOf(value) 54 | if !IsArray(value) { 55 | return false 56 | } 57 | if t.Elem().Kind() == reflect.Uint { 58 | return true 59 | } 60 | return false 61 | } 62 | 63 | // IsString is the given value an string? 64 | // @param interface{} 65 | // return bool 66 | func IsString(value interface{}) bool { 67 | if reflect.TypeOf(value).Kind() == reflect.String { 68 | return true 69 | } 70 | return false 71 | } 72 | 73 | // IsStringArray is the given value an string array? 74 | // @param interface{} 75 | // return bool 76 | func IsStringArray(value interface{}) bool { 77 | t := reflect.TypeOf(value) 78 | if !IsArray(value) { 79 | return false 80 | } 81 | if t.Elem().Kind() == reflect.String { 82 | return true 83 | } 84 | return false 85 | } 86 | 87 | // IsArray is the given value an array? 88 | // @param interface{} 89 | // return bool 90 | func IsArray(value interface{}) bool { 91 | t := reflect.TypeOf(value) 92 | if t.Kind() != reflect.Slice && t.Kind() != reflect.Array { 93 | return false 94 | } 95 | return true 96 | } 97 | -------------------------------------------------------------------------------- /models/permission.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // Permission represents the database model of permissions 8 | type Permission struct { 9 | ID uint `gorm:"primary_key" json:"id"` 10 | Name string `gorm:"size:255;not null" json:"name"` 11 | GuardName string `gorm:"size:255;not null;index" json:"guard_name"` 12 | Description string `gorm:"size:255" json:"description"` 13 | 14 | // Time 15 | CreatedAt time.Time `json:"created_at"` 16 | UpdatedAt time.Time `json:"updated_at"` 17 | } 18 | 19 | // TableName sets the table name 20 | func (Permission) TableName() string { 21 | return "permissions" 22 | } 23 | -------------------------------------------------------------------------------- /models/pivot/userPermissions.go: -------------------------------------------------------------------------------- 1 | package pivot 2 | 3 | // UserPermissions represents the database model of user permissions relationships 4 | type UserPermissions struct { 5 | UserID uint `gorm:"primary_key" json:"user_id"` 6 | PermissionID uint `gorm:"primary_key" json:"permission_id"` 7 | } 8 | 9 | // TableName sets the table name 10 | func (UserPermissions) TableName() string { 11 | return "user_permissions" 12 | } 13 | -------------------------------------------------------------------------------- /models/pivot/userRoles.go: -------------------------------------------------------------------------------- 1 | package pivot 2 | 3 | // UserRoles represents the database model of user roles relationships 4 | type UserRoles struct { 5 | UserID uint `gorm:"primary_key" json:"user_id"` 6 | RoleID uint `gorm:"primary_key" json:"role_id"` 7 | } 8 | 9 | // TableName sets the table name 10 | func (UserRoles) TableName() string { 11 | return "user_roles" 12 | } 13 | -------------------------------------------------------------------------------- /models/role.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // Role represents the database model of roles 8 | type Role struct { 9 | ID uint `gorm:"primary_key" json:"id"` 10 | Name string `gorm:"size:255;not null" json:"name"` 11 | GuardName string `gorm:"size:255;not null;index" json:"guard_name"` 12 | Description string `gorm:"size:255;" json:"description"` 13 | 14 | // Many to Many 15 | Permissions []Permission `gorm:"many2many:role_permissions;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"permissions"` 16 | 17 | // Time 18 | CreatedAt time.Time `json:"created_at"` 19 | UpdatedAt time.Time `json:"updated_at"` 20 | } 21 | 22 | // TableName sets the table name 23 | func (Role) TableName() string { 24 | return "roles" 25 | } 26 | -------------------------------------------------------------------------------- /options/permission.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/Permify/go-role/utils" 5 | ) 6 | 7 | // PermissionOption represents options when fetching permissions. 8 | type PermissionOption struct { 9 | Pagination *utils.Pagination 10 | } 11 | -------------------------------------------------------------------------------- /options/role.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/Permify/go-role/utils" 5 | ) 6 | 7 | // RoleOption represents options when fetching roles. 8 | type RoleOption struct { 9 | WithPermissions bool 10 | Pagination *utils.Pagination 11 | } 12 | -------------------------------------------------------------------------------- /permify.go: -------------------------------------------------------------------------------- 1 | package permify_gorm 2 | 3 | import ( 4 | "errors" 5 | 6 | "gorm.io/gorm" 7 | 8 | "github.com/Permify/go-role/collections" 9 | "github.com/Permify/go-role/helpers" 10 | "github.com/Permify/go-role/models" 11 | "github.com/Permify/go-role/options" 12 | "github.com/Permify/go-role/repositories" 13 | "github.com/Permify/go-role/repositories/scopes" 14 | ) 15 | 16 | var errUnsupportedValueType = errors.New("err unsupported value type") 17 | 18 | // Options has the options for initiating the Permify 19 | type Options struct { 20 | Migrate bool 21 | DB *gorm.DB 22 | } 23 | 24 | // New initializer for Permify 25 | // If migration is true, it generate all tables in the database if they don't exist. 26 | func New(opts Options) (p *Permify, err error) { 27 | roleRepository := &repositories.RoleRepository{Database: opts.DB} 28 | permissionRepository := &repositories.PermissionRepository{Database: opts.DB} 29 | userRepository := &repositories.UserRepository{Database: opts.DB} 30 | 31 | if opts.Migrate { 32 | err = repositories.Migrates(roleRepository, permissionRepository) 33 | if err != nil { 34 | return nil, err 35 | } 36 | } 37 | 38 | p = &Permify{ 39 | RoleRepository: roleRepository, 40 | PermissionRepository: permissionRepository, 41 | UserRepository: userRepository, 42 | } 43 | 44 | return 45 | } 46 | 47 | // Permify is main struct of this package. 48 | type Permify struct { 49 | RoleRepository repositories.IRoleRepository 50 | PermissionRepository repositories.IPermissionRepository 51 | UserRepository repositories.IUserRepository 52 | } 53 | 54 | // ROLE 55 | 56 | // GetRole fetch role according to the role name or id. 57 | // If withPermissions is true, it will preload the permissions to the role. 58 | // First parameter is can be role name or id, second parameter is boolean. 59 | // If the given variable is an array, the first element of the given array is returned. 60 | // @param interface{} 61 | // @param bool 62 | // @return models.Role, error 63 | func (s *Permify) GetRole(r interface{}, withPermissions bool) (role models.Role, err error) { 64 | if helpers.IsArray(r) { 65 | var roles []models.Role 66 | roles, err = s.GetRoles(r, withPermissions) 67 | if err != nil { 68 | return models.Role{}, err 69 | } 70 | if len(roles) > 0 { 71 | role = roles[0] 72 | } 73 | return 74 | } 75 | 76 | if helpers.IsString(r) { 77 | if withPermissions { 78 | return s.RoleRepository.GetRoleByGuardNameWithPermissions(helpers.Guard(r.(string))) 79 | } 80 | return s.RoleRepository.GetRoleByGuardName(helpers.Guard(r.(string))) 81 | } 82 | 83 | if helpers.IsInt(r) { 84 | if withPermissions { 85 | return s.RoleRepository.GetRoleByIDWithPermissions(uint(r.(int))) 86 | } 87 | return s.RoleRepository.GetRoleByID(uint(r.(int))) 88 | } 89 | 90 | if helpers.IsUInt(r) { 91 | if withPermissions { 92 | return s.RoleRepository.GetRoleByIDWithPermissions(r.(uint)) 93 | } 94 | return s.RoleRepository.GetRoleByID(r.(uint)) 95 | } 96 | 97 | return models.Role{}, errUnsupportedValueType 98 | } 99 | 100 | // GetRoles fetch roles according to the role names or ids. 101 | // First parameter is can be role name(s) or id(s), second parameter is boolean. 102 | // If withPermissions is true, it will preload the permissions to the roles. 103 | // @param interface{} 104 | // @param bool 105 | // @return collections.Role, error 106 | func (s *Permify) GetRoles(r interface{}, withPermissions bool) (roles collections.Role, err error) { 107 | if !helpers.IsArray(r) { 108 | var role models.Role 109 | role, err = s.GetRole(r, withPermissions) 110 | if err != nil { 111 | return collections.Role{}, err 112 | } 113 | roles = collections.Role{role} 114 | return 115 | } 116 | 117 | if helpers.IsStringArray(r) { 118 | if withPermissions { 119 | return s.RoleRepository.GetRolesByGuardNamesWithPermissions(helpers.GuardArray(r.([]string))) 120 | } 121 | return s.RoleRepository.GetRolesByGuardNames(helpers.GuardArray(r.([]string))) 122 | } 123 | 124 | if helpers.IsUIntArray(r) { 125 | if withPermissions { 126 | return s.RoleRepository.GetRolesWithPermissions(r.([]uint)) 127 | } 128 | return s.RoleRepository.GetRoles(r.([]uint)) 129 | } 130 | 131 | return collections.Role{}, errUnsupportedValueType 132 | } 133 | 134 | // GetAllRoles fetch all the roles. (with pagination option). 135 | // If withPermissions is true, it will preload the permissions to the role. 136 | // First parameter is role option. 137 | // @param options.RoleOption 138 | // @return collections.Role, int64, error 139 | func (s *Permify) GetAllRoles(option options.RoleOption) (roles collections.Role, totalCount int64, err error) { 140 | var roleIDs []uint 141 | if option.Pagination == nil { 142 | roleIDs, totalCount, err = s.RoleRepository.GetRoleIDs(nil) 143 | } else { 144 | roleIDs, totalCount, err = s.RoleRepository.GetRoleIDs(&scopes.GormPagination{Pagination: option.Pagination.Get()}) 145 | } 146 | 147 | roles, err = s.GetRoles(roleIDs, option.WithPermissions) 148 | return 149 | } 150 | 151 | // GetRolesOfUser fetch all the roles of the user. (with pagination option). 152 | // If withPermissions is true, it will preload the permissions to the role. 153 | // First parameter is user id, second parameter is role option. 154 | // @param uint 155 | // @param options.RoleOption 156 | // @return collections.Role, int64, error 157 | func (s *Permify) GetRolesOfUser(userID uint, option options.RoleOption) (roles collections.Role, totalCount int64, err error) { 158 | var roleIDs []uint 159 | if option.Pagination == nil { 160 | roleIDs, totalCount, err = s.RoleRepository.GetRoleIDsOfUser(userID, nil) 161 | } else { 162 | roleIDs, totalCount, err = s.RoleRepository.GetRoleIDsOfUser(userID, &scopes.GormPagination{Pagination: option.Pagination.Get()}) 163 | } 164 | 165 | roles, err = s.GetRoles(roleIDs, option.WithPermissions) 166 | return 167 | } 168 | 169 | // CreateRole create new role. 170 | // Name parameter is converted to guard name. example: senior $#% associate -> senior-associate. 171 | // If a role with the same name has been created before, it will not create it again. (FirstOrCreate) 172 | // First parameter is role name, second parameter is role description. 173 | // @param string 174 | // @param string 175 | // @return error 176 | func (s *Permify) CreateRole(name string, description string) (err error) { 177 | return s.RoleRepository.FirstOrCreate(&models.Role{ 178 | Name: name, 179 | GuardName: helpers.Guard(name), 180 | Description: description, 181 | }) 182 | } 183 | 184 | // DeleteRole delete role. 185 | // If the role is in use, its relations from the pivot tables are deleted. 186 | // First parameter can be role name or id. 187 | // @param interface{} 188 | // @return error 189 | func (s *Permify) DeleteRole(r interface{}) (err error) { 190 | var role models.Role 191 | role, err = s.GetRole(r, false) 192 | if err != nil { 193 | return err 194 | } 195 | return s.RoleRepository.Delete(&role) 196 | } 197 | 198 | // AddPermissionsToRole add permission to role. 199 | // First parameter can be role name or id, second parameter can be permission name(s) or id(s). 200 | // If the first parameter is an array, the first element of the first parameter is used. 201 | // @param interface{} 202 | // @param interface{} 203 | // @return error 204 | func (s *Permify) AddPermissionsToRole(r interface{}, p interface{}) (err error) { 205 | var role models.Role 206 | role, err = s.GetRole(r, false) 207 | if err != nil { 208 | return err 209 | } 210 | 211 | var permissions collections.Permission 212 | permissions, err = s.GetPermissions(p) 213 | if err != nil { 214 | return err 215 | } 216 | 217 | if permissions.Len() > 0 { 218 | err = s.RoleRepository.AddPermissions(&role, permissions) 219 | } 220 | 221 | return 222 | } 223 | 224 | // ReplacePermissionsToRole overwrites the permissions of the role according to the permission names or ids. 225 | // First parameter can be role name or id, second parameter can be permission name(s) or id(s). 226 | // If the first parameter is an array, the first element of the first parameter is used. 227 | // @param interface{} 228 | // @param interface{} 229 | // @return error 230 | func (s *Permify) ReplacePermissionsToRole(r interface{}, p interface{}) (err error) { 231 | var role models.Role 232 | role, err = s.GetRole(r, false) 233 | if err != nil { 234 | return err 235 | } 236 | 237 | var permissions collections.Permission 238 | permissions, err = s.GetPermissions(p) 239 | if err != nil { 240 | return err 241 | } 242 | 243 | if permissions.Len() > 0 { 244 | return s.RoleRepository.ReplacePermissions(&role, permissions) 245 | } 246 | 247 | return s.RoleRepository.ClearPermissions(&role) 248 | } 249 | 250 | // RemovePermissionsFromRole remove permissions from role according to the permission names or ids. 251 | // First parameter can be role name or id, second parameter can be permission name(s) or id(s). 252 | // If the first parameter is an array, the first element of the first parameter is used. 253 | // @param interface{} 254 | // @param interface{} 255 | // @return error 256 | func (s *Permify) RemovePermissionsFromRole(r interface{}, p interface{}) (err error) { 257 | var role models.Role 258 | role, err = s.GetRole(r, false) 259 | if err != nil { 260 | return err 261 | } 262 | 263 | var permissions collections.Permission 264 | permissions, err = s.GetPermissions(p) 265 | if err != nil { 266 | return err 267 | } 268 | 269 | if permissions.Len() > 0 { 270 | err = s.RoleRepository.RemovePermissions(&role, permissions) 271 | } 272 | 273 | return 274 | } 275 | 276 | // PERMISSION 277 | 278 | // GetPermission fetch permission according to the permission name or id. 279 | // First parameter can be permission name or id. 280 | // If the first parameter is an array, the first element of the given array is returned. 281 | // @param interface{} 282 | // @return error 283 | func (s *Permify) GetPermission(p interface{}) (permission models.Permission, err error) { 284 | if helpers.IsArray(p) { 285 | var permissions []models.Permission 286 | permissions, err = s.GetPermissions(p) 287 | if err != nil { 288 | return models.Permission{}, err 289 | } 290 | if len(permissions) > 0 { 291 | permission = permissions[0] 292 | } 293 | return 294 | } 295 | 296 | if helpers.IsString(p) { 297 | return s.PermissionRepository.GetPermissionByGuardName(helpers.Guard(p.(string))) 298 | } 299 | 300 | if helpers.IsInt(p) { 301 | return s.PermissionRepository.GetPermissionByID(uint(p.(int))) 302 | } 303 | 304 | if helpers.IsUInt(p) { 305 | return s.PermissionRepository.GetPermissionByID(p.(uint)) 306 | } 307 | 308 | return models.Permission{}, errUnsupportedValueType 309 | } 310 | 311 | // GetPermissions fetch permissions according to the permission names or ids. 312 | // First parameter is can be permission name(s) or id(s). 313 | // @param interface{} 314 | // @return collections.Permission, error 315 | func (s *Permify) GetPermissions(p interface{}) (permissions collections.Permission, err error) { 316 | if !helpers.IsArray(p) { 317 | var permission models.Permission 318 | permission, err = s.GetPermission(p) 319 | if err != nil { 320 | return collections.Permission{}, err 321 | } 322 | permissions = collections.Permission{permission} 323 | return 324 | } 325 | 326 | if helpers.IsStringArray(p) { 327 | return s.PermissionRepository.GetPermissionsByGuardNames(helpers.GuardArray(p.([]string))) 328 | } 329 | 330 | if helpers.IsUIntArray(p) { 331 | return s.PermissionRepository.GetPermissions(p.([]uint)) 332 | } 333 | 334 | return collections.Permission{}, errUnsupportedValueType 335 | } 336 | 337 | // GetAllPermissions fetch all the permissions. (with pagination option). 338 | // First parameter is permission option. 339 | // @param options.PermissionOption 340 | // @return collections.Permission, int64, error 341 | func (s *Permify) GetAllPermissions(option options.PermissionOption) (permissions collections.Permission, totalCount int64, err error) { 342 | var permissionIDs []uint 343 | if option.Pagination == nil { 344 | permissionIDs, totalCount, err = s.PermissionRepository.GetPermissionIDs(nil) 345 | } else { 346 | permissionIDs, totalCount, err = s.PermissionRepository.GetPermissionIDs(&scopes.GormPagination{Pagination: option.Pagination.Get()}) 347 | } 348 | permissions, err = s.GetPermissions(permissionIDs) 349 | return 350 | } 351 | 352 | // GetDirectPermissionsOfUser fetch all direct permissions of the user. (with pagination option) 353 | // First parameter is user id, second parameter is permission option. 354 | // @param uint 355 | // @param options.PermissionOption 356 | // @return collections.Permission, int64, error 357 | func (s *Permify) GetDirectPermissionsOfUser(userID uint, option options.PermissionOption) (permissions collections.Permission, totalCount int64, err error) { 358 | var permissionIDs []uint 359 | if option.Pagination == nil { 360 | permissionIDs, totalCount, err = s.PermissionRepository.GetDirectPermissionIDsOfUserByID(userID, nil) 361 | } else { 362 | permissionIDs, totalCount, err = s.PermissionRepository.GetDirectPermissionIDsOfUserByID(userID, &scopes.GormPagination{Pagination: option.Pagination.Get()}) 363 | } 364 | permissions, err = s.GetPermissions(permissionIDs) 365 | return 366 | } 367 | 368 | // GetPermissionsOfRoles fetch all permissions of the roles. (with pagination option) 369 | // First parameter can be role name(s) or id(s), second parameter is permission option. 370 | // @param interface{} 371 | // @param options.PermissionOption 372 | // @return collections.Permission, int64, error 373 | func (s *Permify) GetPermissionsOfRoles(r interface{}, option options.PermissionOption) (permissions collections.Permission, totalCount int64, err error) { 374 | var roles collections.Role 375 | roles, err = s.GetRoles(r, false) 376 | if err != nil { 377 | return collections.Permission{}, 0, err 378 | } 379 | 380 | var permissionIDs []uint 381 | if option.Pagination == nil { 382 | permissionIDs, totalCount, err = s.PermissionRepository.GetPermissionIDsOfRolesByIDs(roles.IDs(), nil) 383 | } else { 384 | permissionIDs, totalCount, err = s.PermissionRepository.GetPermissionIDsOfRolesByIDs(roles.IDs(), &scopes.GormPagination{Pagination: option.Pagination.Get()}) 385 | } 386 | 387 | permissions, err = s.GetPermissions(permissionIDs) 388 | return 389 | } 390 | 391 | // GetAllPermissionsOfUser fetch all permissions of the user that come with direct and roles. 392 | // First parameter is user id. 393 | // @param uint 394 | // @return collections.Permission, error 395 | func (s *Permify) GetAllPermissionsOfUser(userID uint) (permissions collections.Permission, err error) { 396 | var userRoleIDs []uint 397 | userRoleIDs, _, err = s.RoleRepository.GetRoleIDsOfUser(userID, nil) 398 | if err != nil { 399 | return collections.Permission{}, err 400 | } 401 | 402 | var rolePermissionIDs []uint 403 | rolePermissionIDs, _, err = s.PermissionRepository.GetPermissionIDsOfRolesByIDs(userRoleIDs, nil) 404 | if err != nil { 405 | return collections.Permission{}, err 406 | } 407 | 408 | var userDirectPermissionIDs []uint 409 | userDirectPermissionIDs, _, err = s.PermissionRepository.GetDirectPermissionIDsOfUserByID(userID, nil) 410 | if err != nil { 411 | return collections.Permission{}, err 412 | } 413 | 414 | return s.GetPermissions(helpers.RemoveDuplicateValues(helpers.JoinUintArrays(rolePermissionIDs, userDirectPermissionIDs))) 415 | } 416 | 417 | // CreatePermission create new permission. 418 | // Name parameter is converted to guard name. example: create $#% contact -> create-contact. 419 | // If a permission with the same name has been created before, it will not create it again. (FirstOrCreate) 420 | // @param string 421 | // @param string 422 | // @return error 423 | func (s *Permify) CreatePermission(name string, description string) (err error) { 424 | return s.PermissionRepository.FirstOrCreate(&models.Permission{ 425 | Name: name, 426 | GuardName: helpers.Guard(name), 427 | Description: description, 428 | }) 429 | } 430 | 431 | // DeletePermission delete permission. 432 | // If the permission is in use, its relations from the pivot tables are deleted. 433 | // First parameter can be permission name or id. 434 | // If the first parameter is an array, the first element of the given array is used. 435 | // @param interface{} 436 | // @return error 437 | func (s *Permify) DeletePermission(p interface{}) (err error) { 438 | var permission models.Permission 439 | permission, err = s.GetPermission(p) 440 | if err != nil { 441 | return err 442 | } 443 | return s.PermissionRepository.Delete(&permission) 444 | } 445 | 446 | // USER 447 | 448 | // AddPermissionsToUser add direct permission or permissions to user according to the permission names or ids. 449 | // First parameter is the user id, second parameter is can be permission name(s) or id(s). 450 | // @param uint 451 | // @param interface{} 452 | // @return error 453 | func (s *Permify) AddPermissionsToUser(userID uint, p interface{}) (err error) { 454 | var permissions collections.Permission 455 | permissions, err = s.GetPermissions(p) 456 | if err != nil { 457 | return err 458 | } 459 | 460 | if permissions.Len() > 0 { 461 | err = s.UserRepository.AddPermissions(userID, permissions) 462 | } 463 | 464 | return 465 | } 466 | 467 | // ReplacePermissionsToUser overwrites the direct permissions of the user according to the permission names or ids. 468 | // First parameter is the user id, second parameter is can be permission name(s) or id(s). 469 | // @param uint 470 | // @param interface{} 471 | // @return error 472 | func (s *Permify) ReplacePermissionsToUser(userID uint, p interface{}) (err error) { 473 | var permissions collections.Permission 474 | permissions, err = s.GetPermissions(p) 475 | if err != nil { 476 | return err 477 | } 478 | 479 | if permissions.Len() > 0 { 480 | return s.UserRepository.ReplacePermissions(userID, permissions) 481 | } 482 | 483 | return s.UserRepository.ClearPermissions(userID) 484 | } 485 | 486 | // RemovePermissionsFromUser remove direct permissions from user according to the permission names or ids. 487 | // First parameter is the user id, second parameter is can be permission name(s) or id(s). 488 | // @param uint 489 | // @param interface{} 490 | // @return error 491 | func (s *Permify) RemovePermissionsFromUser(userID uint, p interface{}) (err error) { 492 | var permissions collections.Permission 493 | permissions, err = s.GetPermissions(p) 494 | if err != nil { 495 | return err 496 | } 497 | 498 | if permissions.Len() > 0 { 499 | err = s.UserRepository.RemovePermissions(userID, permissions) 500 | } 501 | 502 | return 503 | } 504 | 505 | // AddRolesToUser add role or roles to user according to the role names or ids. 506 | // First parameter is the user id, second parameter is can be role name(s) or id(s). 507 | // @param uint 508 | // @param interface{} 509 | // @return error 510 | func (s *Permify) AddRolesToUser(userID uint, r interface{}) (err error) { 511 | var roles collections.Role 512 | roles, err = s.GetRoles(r, false) 513 | if err != nil { 514 | return err 515 | } 516 | 517 | if roles.Len() > 0 { 518 | err = s.UserRepository.AddRoles(userID, roles) 519 | } 520 | 521 | return 522 | } 523 | 524 | // ReplaceRolesToUser overwrites the roles of the user according to the role names or ids. 525 | // First parameter is the user id, second parameter is can be role name(s) or id(s). 526 | // @param uint 527 | // @param interface{} 528 | // @return error 529 | func (s *Permify) ReplaceRolesToUser(userID uint, r interface{}) (err error) { 530 | var roles collections.Role 531 | roles, err = s.GetRoles(r, false) 532 | if err != nil { 533 | return err 534 | } 535 | 536 | if roles.Len() > 0 { 537 | return s.UserRepository.ReplaceRoles(userID, roles) 538 | } 539 | 540 | return s.UserRepository.ClearRoles(userID) 541 | } 542 | 543 | // RemoveRolesFromUser remove roles from user according to the role names or ids. 544 | // First parameter is the user id, second parameter is can be role name(s) or id(s). 545 | // @param uint 546 | // @param interface{} 547 | // @return error 548 | func (s *Permify) RemoveRolesFromUser(userID uint, r interface{}) (err error) { 549 | var roles collections.Role 550 | roles, err = s.GetRoles(r, false) 551 | if err != nil { 552 | return err 553 | } 554 | 555 | if roles.Len() > 0 { 556 | err = s.UserRepository.RemoveRoles(userID, roles) 557 | } 558 | 559 | return 560 | } 561 | 562 | // CONTROLS 563 | 564 | // ROLE 565 | 566 | // RoleHasPermission does the role or any of the roles have given permission? 567 | // First parameter is can be role name(s) or id(s), second parameter is can be permission name or id. 568 | // If the second parameter is an array, the first element of the given array is used. 569 | // @param interface{} 570 | // @param interface{} 571 | // @return error 572 | func (s *Permify) RoleHasPermission(r interface{}, p interface{}) (b bool, err error) { 573 | var roles collections.Role 574 | roles, err = s.GetRoles(r, false) 575 | if err != nil { 576 | return false, err 577 | } 578 | 579 | var permission models.Permission 580 | permission, err = s.GetPermission(p) 581 | if err != nil { 582 | return false, err 583 | } 584 | 585 | return s.RoleRepository.HasPermission(roles, permission) 586 | } 587 | 588 | // RoleHasAllPermissions does the role or roles have all the given permissions? 589 | // First parameter is can be role name(s) or id(s), second parameter is can be permission name(s) or id(s). 590 | // @param interface{} 591 | // @param interface{} 592 | // @return error 593 | func (s *Permify) RoleHasAllPermissions(r interface{}, p interface{}) (b bool, err error) { 594 | var roles collections.Role 595 | roles, err = s.GetRoles(r, false) 596 | if err != nil { 597 | return false, err 598 | } 599 | 600 | var permissions collections.Permission 601 | permissions, err = s.GetPermissions(p) 602 | if err != nil { 603 | return false, err 604 | } 605 | 606 | return s.RoleRepository.HasAllPermissions(roles, permissions) 607 | } 608 | 609 | // RoleHasAnyPermissions does the role or roles have any of the given permissions? 610 | // First parameter is can be role name(s) or id(s), second parameter is can be permission name(s) or id(s). 611 | // @param interface{} 612 | // @param interface{} 613 | // @return error 614 | func (s *Permify) RoleHasAnyPermissions(r interface{}, p interface{}) (b bool, err error) { 615 | var roles collections.Role 616 | roles, err = s.GetRoles(r, false) 617 | if err != nil { 618 | return false, err 619 | } 620 | 621 | var permissions collections.Permission 622 | permissions, err = s.GetPermissions(p) 623 | if err != nil { 624 | return false, err 625 | } 626 | 627 | return s.RoleRepository.HasAnyPermissions(roles, permissions) 628 | } 629 | 630 | // USER 631 | 632 | // UserHasRole does the user have the given role? 633 | // First parameter is the user id, second parameter is can be role name or id. 634 | // If the second parameter is an array, the first element of the given array is used. 635 | // @param uint 636 | // @param interface{} 637 | // @return bool, error 638 | func (s *Permify) UserHasRole(userID uint, r interface{}) (b bool, err error) { 639 | var role models.Role 640 | role, err = s.GetRole(r, false) 641 | if err != nil { 642 | return false, err 643 | } 644 | return s.UserRepository.HasRole(userID, role) 645 | } 646 | 647 | // UserHasAllRoles does the user have all the given roles? 648 | // First parameter is the user id, second parameter is can be role name(s) or id(s). 649 | // @param uint 650 | // @param interface{} 651 | // @return bool, error 652 | func (s *Permify) UserHasAllRoles(userID uint, r interface{}) (b bool, err error) { 653 | var roles collections.Role 654 | roles, err = s.GetRoles(r, false) 655 | if err != nil { 656 | return false, err 657 | } 658 | return s.UserRepository.HasAllRoles(userID, roles) 659 | } 660 | 661 | // UserHasAnyRoles does the user have any of the given roles? 662 | // First parameter is the user id, second parameter is can be role name(s) or id(s). 663 | // @param uint 664 | // @param interface{} 665 | // @return bool, error 666 | func (s *Permify) UserHasAnyRoles(userID uint, r interface{}) (b bool, err error) { 667 | var roles collections.Role 668 | roles, err = s.GetRoles(r, false) 669 | if err != nil { 670 | return false, err 671 | } 672 | return s.UserRepository.HasAnyRoles(userID, roles) 673 | } 674 | 675 | // UserHasDirectPermission does the user have the given permission? (not including the permissions of the roles) 676 | // First parameter is the user id, second parameter is can be permission name or id. 677 | // If the second parameter is an array, the first element of the given array is used. 678 | // @param uint 679 | // @param interface{} 680 | // @return bool, error 681 | func (s *Permify) UserHasDirectPermission(userID uint, p interface{}) (b bool, err error) { 682 | var permission models.Permission 683 | permission, err = s.GetPermission(p) 684 | if err != nil { 685 | return false, err 686 | } 687 | return s.UserRepository.HasDirectPermission(userID, permission) 688 | } 689 | 690 | // UserHasAllDirectPermissions does the user have all the given permissions? (not including the permissions of the roles) 691 | // First parameter is the user id, second parameter is can be permission name(s) or id(s). 692 | // @param uint 693 | // @param interface{} 694 | // @return bool, error 695 | func (s *Permify) UserHasAllDirectPermissions(userID uint, p interface{}) (b bool, err error) { 696 | var permissions collections.Permission 697 | permissions, err = s.GetPermissions(p) 698 | if err != nil { 699 | return false, err 700 | } 701 | return s.UserRepository.HasAllDirectPermissions(userID, permissions) 702 | } 703 | 704 | // UserHasAnyDirectPermissions does the user have any of the given permissions? (not including the permissions of the roles) 705 | // First parameter is the user id, second parameter is can be permission name(s) or id(s). 706 | // @param uint 707 | // @param interface{} 708 | // @return bool, error 709 | func (s *Permify) UserHasAnyDirectPermissions(userID uint, p interface{}) (b bool, err error) { 710 | var permissions collections.Permission 711 | permissions, err = s.GetPermissions(p) 712 | if err != nil { 713 | return false, err 714 | } 715 | return s.UserRepository.HasAnyDirectPermissions(userID, permissions) 716 | } 717 | 718 | // UserHasPermission does the user have the given permission? (including the permissions of the roles) 719 | // First parameter is the user id, second parameter is can be permission name or id. 720 | // If the second parameter is an array, the first element of the given array is used. 721 | // @param uint 722 | // @param interface{} 723 | // @return bool, error 724 | func (s *Permify) UserHasPermission(userID uint, p interface{}) (b bool, err error) { 725 | var permission models.Permission 726 | permission, err = s.GetPermission(p) 727 | if err != nil { 728 | return false, err 729 | } 730 | 731 | var directPermissionIDs []uint 732 | directPermissionIDs, _, err = s.PermissionRepository.GetDirectPermissionIDsOfUserByID(userID, nil) 733 | if err != nil { 734 | return false, err 735 | } 736 | 737 | if helpers.InArray(permission.ID, directPermissionIDs) { 738 | return true, err 739 | } 740 | 741 | var roleIDs []uint 742 | roleIDs, _, err = s.RoleRepository.GetRoleIDsOfUser(userID, nil) 743 | if err != nil { 744 | return false, err 745 | } 746 | 747 | var permissionIDs []uint 748 | permissionIDs, _, err = s.PermissionRepository.GetPermissionIDsOfRolesByIDs(roleIDs, nil) 749 | if err != nil { 750 | return false, err 751 | } 752 | 753 | if helpers.InArray(permission.ID, permissionIDs) { 754 | return true, err 755 | } 756 | 757 | return false, err 758 | } 759 | 760 | // UserHasAllPermissions does the user have all the given permissions? (including the permissions of the roles). 761 | // First parameter is the user id, second parameter is can be permission name(s) or id(s). 762 | // @param uint 763 | // @param interface{} 764 | // @return bool, error 765 | func (s *Permify) UserHasAllPermissions(userID uint, p interface{}) (b bool, err error) { 766 | var permissions collections.Permission 767 | permissions, err = s.GetPermissions(p) 768 | if err != nil { 769 | return false, err 770 | } 771 | 772 | var userPermissionIDs []uint 773 | userPermissionIDs, _, err = s.PermissionRepository.GetDirectPermissionIDsOfUserByID(userID, nil) 774 | if err != nil { 775 | return false, err 776 | } 777 | 778 | var roleIDs []uint 779 | roleIDs, _, err = s.RoleRepository.GetRoleIDsOfUser(userID, nil) 780 | if err != nil { 781 | return false, err 782 | } 783 | 784 | var rolePermissionIDs []uint 785 | rolePermissionIDs, _, err = s.PermissionRepository.GetPermissionIDsOfRolesByIDs(roleIDs, nil) 786 | if err != nil { 787 | return false, err 788 | } 789 | 790 | allPermissionIDsOfUser := helpers.RemoveDuplicateValues(helpers.JoinUintArrays(userPermissionIDs, rolePermissionIDs)) 791 | 792 | for _, permissionID := range permissions.IDs() { 793 | if !helpers.InArray(permissionID, allPermissionIDsOfUser) { 794 | return false, err 795 | } 796 | } 797 | 798 | return true, err 799 | } 800 | 801 | // UserHasAnyPermissions does the user have any of the given permissions? (including the permissions of the roles). 802 | // First parameter is the user id, second parameter is can be permission name(s) or id(s). 803 | // @param uint 804 | // @param interface{} 805 | // @return bool, error 806 | func (s *Permify) UserHasAnyPermissions(userID uint, p interface{}) (b bool, err error) { 807 | var permissions collections.Permission 808 | permissions, err = s.GetPermissions(p) 809 | if err != nil { 810 | return false, err 811 | } 812 | 813 | var directPermissionIDs []uint 814 | directPermissionIDs, _, err = s.PermissionRepository.GetDirectPermissionIDsOfUserByID(userID, nil) 815 | if err != nil { 816 | return false, err 817 | } 818 | 819 | for _, permissionID := range permissions.IDs() { 820 | if helpers.InArray(permissionID, directPermissionIDs) { 821 | return true, err 822 | } 823 | } 824 | 825 | var roleIDs []uint 826 | roleIDs, _, err = s.RoleRepository.GetRoleIDsOfUser(userID, nil) 827 | if err != nil { 828 | return false, err 829 | } 830 | 831 | var permissionIDs []uint 832 | permissionIDs, _, err = s.PermissionRepository.GetPermissionIDsOfRolesByIDs(roleIDs, nil) 833 | if err != nil { 834 | return false, err 835 | } 836 | 837 | for _, permissionID := range permissions.IDs() { 838 | if helpers.InArray(permissionID, permissionIDs) { 839 | return true, err 840 | } 841 | } 842 | 843 | return false, err 844 | } 845 | -------------------------------------------------------------------------------- /repositories/base.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | // Seedable gives models the ability to seed. 4 | type Seedable interface { 5 | Seed() error 6 | } 7 | 8 | // Seeds seed to seedable models. 9 | func Seeds(repos ...Seedable) (err error) { 10 | for _, r := range repos { 11 | err = r.Seed() 12 | } 13 | return 14 | } 15 | 16 | // Migratable gives models the ability to migrate. 17 | type Migratable interface { 18 | Migrate() error 19 | } 20 | 21 | // Migrates migrate to migratable models. 22 | func Migrates(repos ...Migratable) (err error) { 23 | for _, r := range repos { 24 | err = r.Migrate() 25 | } 26 | return 27 | } 28 | -------------------------------------------------------------------------------- /repositories/mocks/permissionRepository.go: -------------------------------------------------------------------------------- 1 | package mocks 2 | 3 | import ( 4 | "github.com/stretchr/testify/mock" 5 | 6 | "github.com/Permify/go-role/collections" 7 | "github.com/Permify/go-role/models" 8 | "github.com/Permify/go-role/repositories/scopes" 9 | ) 10 | 11 | // PermissionRepository is an autogenerated mock type for the PermissionRepository type 12 | type PermissionRepository struct { 13 | mock.Mock 14 | } 15 | 16 | // Migrate provides a mock function. 17 | func (_m *PermissionRepository) Migrate() (err error) { 18 | ret := _m.Called() 19 | 20 | var r0 error 21 | if rf, ok := ret.Get(0).(func() error); ok { 22 | r0 = rf() 23 | } else { 24 | r0 = ret.Error(0) 25 | } 26 | 27 | return r0 28 | } 29 | 30 | // GetPermissionByID provides a mock function with given fields: ID 31 | func (_m *PermissionRepository) GetPermissionByID(ID uint) (permission models.Permission, err error) { 32 | ret := _m.Called(ID) 33 | 34 | var r0 models.Permission 35 | if rf, ok := ret.Get(0).(func(uint) models.Permission); ok { 36 | r0 = rf(ID) 37 | } else { 38 | r0 = ret.Get(0).(models.Permission) 39 | } 40 | 41 | var r1 error 42 | if rf, ok := ret.Get(1).(func(uint) error); ok { 43 | r1 = rf(ID) 44 | } else { 45 | r1 = ret.Error(1) 46 | } 47 | 48 | return r0, r1 49 | } 50 | 51 | // GetPermissionByGuardName provides a mock function with given fields: guardName 52 | func (_m *PermissionRepository) GetPermissionByGuardName(guardName string) (permission models.Permission, err error) { 53 | ret := _m.Called(guardName) 54 | 55 | var r0 models.Permission 56 | if rf, ok := ret.Get(0).(func(string) models.Permission); ok { 57 | r0 = rf(guardName) 58 | } else { 59 | r0 = ret.Get(0).(models.Permission) 60 | } 61 | 62 | var r1 error 63 | if rf, ok := ret.Get(1).(func(string) error); ok { 64 | r1 = rf(guardName) 65 | } else { 66 | r1 = ret.Error(1) 67 | } 68 | 69 | return r0, r1 70 | } 71 | 72 | // GetPermissions provides a mock function with given fields: IDs 73 | func (_m *PermissionRepository) GetPermissions(IDs []uint) (permissions collections.Permission, err error) { 74 | ret := _m.Called(IDs) 75 | 76 | var r0 collections.Permission 77 | if rf, ok := ret.Get(0).(func([]uint) collections.Permission); ok { 78 | r0 = rf(IDs) 79 | } else { 80 | r0 = ret.Get(0).(collections.Permission) 81 | } 82 | 83 | var r1 error 84 | if rf, ok := ret.Get(1).(func([]uint) error); ok { 85 | r1 = rf(IDs) 86 | } else { 87 | r1 = ret.Error(1) 88 | } 89 | 90 | return r0, r1 91 | } 92 | 93 | // GetPermissionsByGuardNames provides a mock function with given fields: guardNames 94 | func (_m *PermissionRepository) GetPermissionsByGuardNames(guardNames []string) (permissions collections.Permission, err error) { 95 | ret := _m.Called(guardNames) 96 | 97 | var r0 collections.Permission 98 | if rf, ok := ret.Get(0).(func([]string) collections.Permission); ok { 99 | r0 = rf(guardNames) 100 | } else { 101 | r0 = ret.Get(0).(collections.Permission) 102 | } 103 | 104 | var r1 error 105 | if rf, ok := ret.Get(1).(func([]string) error); ok { 106 | r1 = rf(guardNames) 107 | } else { 108 | r1 = ret.Error(1) 109 | } 110 | 111 | return r0, r1 112 | } 113 | 114 | // GetPermissionIDs provides a mock function with given fields: pagination 115 | func (_m *PermissionRepository) GetPermissionIDs(pagination scopes.GormPager) (permissionIDs []uint, totalCount int64, err error) { 116 | ret := _m.Called(pagination) 117 | 118 | var r0 []uint 119 | if rf, ok := ret.Get(0).(func(scopes.GormPager) []uint); ok { 120 | r0 = rf(pagination) 121 | } else { 122 | r0 = ret.Get(0).([]uint) 123 | } 124 | 125 | var r1 int64 126 | if rf, ok := ret.Get(1).(func(scopes.GormPager) int64); ok { 127 | r1 = rf(pagination) 128 | } else { 129 | r1 = ret.Get(1).(int64) 130 | } 131 | 132 | var r2 error 133 | if rf, ok := ret.Get(2).(func(scopes.GormPager) error); ok { 134 | r2 = rf(pagination) 135 | } else { 136 | r2 = ret.Error(2) 137 | } 138 | 139 | return r0, r1, r2 140 | } 141 | 142 | // GetDirectPermissionIDsOfUserByID provides a mock function with given fields: userID, pagination 143 | func (_m *PermissionRepository) GetDirectPermissionIDsOfUserByID(userID uint, pagination scopes.GormPager) (permissionIDs []uint, totalCount int64, err error) { 144 | ret := _m.Called(userID, pagination) 145 | 146 | var r0 []uint 147 | if rf, ok := ret.Get(0).(func(uint, scopes.GormPager) []uint); ok { 148 | r0 = rf(userID, pagination) 149 | } else { 150 | r0 = ret.Get(0).([]uint) 151 | } 152 | 153 | var r1 int64 154 | if rf, ok := ret.Get(1).(func(uint, scopes.GormPager) int64); ok { 155 | r1 = rf(userID, pagination) 156 | } else { 157 | r1 = ret.Get(1).(int64) 158 | } 159 | 160 | var r2 error 161 | if rf, ok := ret.Get(2).(func(uint, scopes.GormPager) error); ok { 162 | r2 = rf(userID, pagination) 163 | } else { 164 | r2 = ret.Error(2) 165 | } 166 | 167 | return r0, r1, r2 168 | } 169 | 170 | // GetPermissionIDsOfRolesByIDs provides a mock function with given fields: roleIDs, pagination 171 | func (_m *PermissionRepository) GetPermissionIDsOfRolesByIDs(roleIDs []uint, pagination scopes.GormPager) (permissionIDs []uint, totalCount int64, err error) { 172 | ret := _m.Called(roleIDs, pagination) 173 | 174 | var r0 []uint 175 | if rf, ok := ret.Get(0).(func([]uint, scopes.GormPager) []uint); ok { 176 | r0 = rf(roleIDs, pagination) 177 | } else { 178 | r0 = ret.Get(0).([]uint) 179 | } 180 | 181 | var r1 int64 182 | if rf, ok := ret.Get(1).(func([]uint, scopes.GormPager) int64); ok { 183 | r1 = rf(roleIDs, pagination) 184 | } else { 185 | r1 = ret.Get(1).(int64) 186 | } 187 | 188 | var r2 error 189 | if rf, ok := ret.Get(2).(func([]uint, scopes.GormPager) error); ok { 190 | r2 = rf(roleIDs, pagination) 191 | } else { 192 | r2 = ret.Error(2) 193 | } 194 | 195 | return r0, r1, r2 196 | } 197 | 198 | // FirstOrCreate provides a mock function with given fields: permission 199 | func (_m *PermissionRepository) FirstOrCreate(permission *models.Permission) error { 200 | ret := _m.Called(permission) 201 | 202 | var r0 error 203 | if rf, ok := ret.Get(0).(func(*models.Permission) error); ok { 204 | r0 = rf(permission) 205 | } else { 206 | r0 = ret.Error(0) 207 | } 208 | 209 | return r0 210 | } 211 | 212 | // Updates provides a mock function with given fields: permission, updates 213 | func (_m *PermissionRepository) Updates(permission *models.Permission, updates map[string]interface{}) (err error) { 214 | ret := _m.Called(permission, updates) 215 | 216 | var r0 error 217 | if rf, ok := ret.Get(0).(func(*models.Permission, map[string]interface{}) error); ok { 218 | r0 = rf(permission, updates) 219 | } else { 220 | r0 = ret.Error(0) 221 | } 222 | 223 | return r0 224 | } 225 | 226 | // Delete provides a mock function with given fields: permission 227 | func (_m *PermissionRepository) Delete(permission *models.Permission) (err error) { 228 | ret := _m.Called(permission) 229 | 230 | var r0 error 231 | if rf, ok := ret.Get(0).(func(*models.Permission) error); ok { 232 | r0 = rf(permission) 233 | } else { 234 | r0 = ret.Error(0) 235 | } 236 | 237 | return r0 238 | } 239 | -------------------------------------------------------------------------------- /repositories/mocks/roleRepository.go: -------------------------------------------------------------------------------- 1 | package mocks 2 | 3 | import ( 4 | "github.com/stretchr/testify/mock" 5 | 6 | "github.com/Permify/go-role/collections" 7 | "github.com/Permify/go-role/models" 8 | "github.com/Permify/go-role/repositories/scopes" 9 | ) 10 | 11 | // RoleRepository is an autogenerated mock type for the RoleRepository type 12 | type RoleRepository struct { 13 | mock.Mock 14 | } 15 | 16 | // Migrate provides a mock function. 17 | func (_m *RoleRepository) Migrate() (err error) { 18 | ret := _m.Called() 19 | 20 | var r0 error 21 | if rf, ok := ret.Get(0).(func() error); ok { 22 | r0 = rf() 23 | } else { 24 | r0 = ret.Error(0) 25 | } 26 | 27 | return r0 28 | } 29 | 30 | // GetRoleByID provides a mock function with given fields: ID 31 | func (_m *RoleRepository) GetRoleByID(ID uint) (role models.Role, err error) { 32 | ret := _m.Called(ID) 33 | 34 | var r0 models.Role 35 | if rf, ok := ret.Get(0).(func(uint) models.Role); ok { 36 | r0 = rf(ID) 37 | } else { 38 | r0 = ret.Get(0).(models.Role) 39 | } 40 | 41 | var r1 error 42 | if rf, ok := ret.Get(1).(func(uint) error); ok { 43 | r1 = rf(ID) 44 | } else { 45 | r1 = ret.Error(1) 46 | } 47 | 48 | return r0, r1 49 | } 50 | 51 | // GetRoleByIDWithPermissions provides a mock function with given fields: ID 52 | func (_m *RoleRepository) GetRoleByIDWithPermissions(ID uint) (role models.Role, err error) { 53 | ret := _m.Called(ID) 54 | 55 | var r0 models.Role 56 | if rf, ok := ret.Get(0).(func(uint) models.Role); ok { 57 | r0 = rf(ID) 58 | } else { 59 | r0 = ret.Get(0).(models.Role) 60 | } 61 | 62 | var r1 error 63 | if rf, ok := ret.Get(1).(func(uint) error); ok { 64 | r1 = rf(ID) 65 | } else { 66 | r1 = ret.Error(1) 67 | } 68 | 69 | return r0, r1 70 | } 71 | 72 | // GetRoleByGuardName provides a mock function with given fields: guardName 73 | func (_m *RoleRepository) GetRoleByGuardName(guardName string) (role models.Role, err error) { 74 | ret := _m.Called(guardName) 75 | 76 | var r0 models.Role 77 | if rf, ok := ret.Get(0).(func(string) models.Role); ok { 78 | r0 = rf(guardName) 79 | } else { 80 | r0 = ret.Get(0).(models.Role) 81 | } 82 | 83 | var r1 error 84 | if rf, ok := ret.Get(1).(func(string) error); ok { 85 | r1 = rf(guardName) 86 | } else { 87 | r1 = ret.Error(1) 88 | } 89 | 90 | return r0, r1 91 | } 92 | 93 | // GetRoleByGuardNameWithPermissions provides a mock function with given fields: guardName 94 | func (_m *RoleRepository) GetRoleByGuardNameWithPermissions(guardName string) (role models.Role, err error) { 95 | ret := _m.Called(guardName) 96 | 97 | var r0 models.Role 98 | if rf, ok := ret.Get(0).(func(string) models.Role); ok { 99 | r0 = rf(guardName) 100 | } else { 101 | r0 = ret.Get(0).(models.Role) 102 | } 103 | 104 | var r1 error 105 | if rf, ok := ret.Get(1).(func(string) error); ok { 106 | r1 = rf(guardName) 107 | } else { 108 | r1 = ret.Error(1) 109 | } 110 | 111 | return r0, r1 112 | } 113 | 114 | // GetRoles provides a mock function with given fields: IDs 115 | func (_m *RoleRepository) GetRoles(IDs []uint) (roles collections.Role, err error) { 116 | ret := _m.Called(IDs) 117 | 118 | var r0 collections.Role 119 | if rf, ok := ret.Get(0).(func([]uint) collections.Role); ok { 120 | r0 = rf(IDs) 121 | } else { 122 | r0 = ret.Get(0).(collections.Role) 123 | } 124 | 125 | var r1 error 126 | if rf, ok := ret.Get(1).(func([]uint) error); ok { 127 | r1 = rf(IDs) 128 | } else { 129 | r1 = ret.Error(1) 130 | } 131 | 132 | return r0, r1 133 | } 134 | 135 | // GetRolesWithPermissions provides a mock function with given fields: IDs 136 | func (_m *RoleRepository) GetRolesWithPermissions(IDs []uint) (roles collections.Role, err error) { 137 | ret := _m.Called(IDs) 138 | 139 | var r0 collections.Role 140 | if rf, ok := ret.Get(0).(func([]uint) collections.Role); ok { 141 | r0 = rf(IDs) 142 | } else { 143 | r0 = ret.Get(0).(collections.Role) 144 | } 145 | 146 | var r1 error 147 | if rf, ok := ret.Get(1).(func([]uint) error); ok { 148 | r1 = rf(IDs) 149 | } else { 150 | r1 = ret.Error(1) 151 | } 152 | 153 | return r0, r1 154 | } 155 | 156 | // GetRolesByGuardNames provides a mock function with given fields: guardNames 157 | func (_m *RoleRepository) GetRolesByGuardNames(guardNames []string) (roles collections.Role, err error) { 158 | ret := _m.Called(guardNames) 159 | 160 | var r0 collections.Role 161 | if rf, ok := ret.Get(0).(func([]string) collections.Role); ok { 162 | r0 = rf(guardNames) 163 | } else { 164 | r0 = ret.Get(0).(collections.Role) 165 | } 166 | 167 | var r1 error 168 | if rf, ok := ret.Get(1).(func([]string) error); ok { 169 | r1 = rf(guardNames) 170 | } else { 171 | r1 = ret.Error(1) 172 | } 173 | 174 | return r0, r1 175 | } 176 | 177 | // GetRolesByGuardNamesWithPermissions provides a mock function with given fields: guardNames 178 | func (_m *RoleRepository) GetRolesByGuardNamesWithPermissions(guardNames []string) (roles collections.Role, err error) { 179 | ret := _m.Called(guardNames) 180 | 181 | var r0 collections.Role 182 | if rf, ok := ret.Get(0).(func([]string) collections.Role); ok { 183 | r0 = rf(guardNames) 184 | } else { 185 | r0 = ret.Get(0).(collections.Role) 186 | } 187 | 188 | var r1 error 189 | if rf, ok := ret.Get(1).(func([]string) error); ok { 190 | r1 = rf(guardNames) 191 | } else { 192 | r1 = ret.Error(1) 193 | } 194 | 195 | return r0, r1 196 | } 197 | 198 | // GetRoleIDs provides a mock function with given fields: pagination 199 | func (_m *RoleRepository) GetRoleIDs(pagination scopes.GormPager) (roleIDs []uint, totalCount int64, err error) { 200 | ret := _m.Called(pagination) 201 | 202 | var r0 []uint 203 | if rf, ok := ret.Get(0).(func(scopes.GormPager) []uint); ok { 204 | r0 = rf(pagination) 205 | } else { 206 | r0 = ret.Get(0).([]uint) 207 | } 208 | 209 | var r1 int64 210 | if rf, ok := ret.Get(1).(func(scopes.GormPager) int64); ok { 211 | r1 = rf(pagination) 212 | } else { 213 | r1 = ret.Get(1).(int64) 214 | } 215 | 216 | var r2 error 217 | if rf, ok := ret.Get(2).(func(scopes.GormPager) error); ok { 218 | r2 = rf(pagination) 219 | } else { 220 | r2 = ret.Error(2) 221 | } 222 | 223 | return r0, r1, r2 224 | } 225 | 226 | // GetRoleIDsOfUser provides a mock function with given fields: userID, pagination 227 | func (_m *RoleRepository) GetRoleIDsOfUser(userID uint, pagination scopes.GormPager) (roleIDs []uint, totalCount int64, err error) { 228 | ret := _m.Called(userID, pagination) 229 | 230 | var r0 []uint 231 | if rf, ok := ret.Get(0).(func(uint, scopes.GormPager) []uint); ok { 232 | r0 = rf(userID, pagination) 233 | } else { 234 | r0 = ret.Get(0).([]uint) 235 | } 236 | 237 | var r1 int64 238 | if rf, ok := ret.Get(1).(func(uint, scopes.GormPager) int64); ok { 239 | r1 = rf(userID, pagination) 240 | } else { 241 | r1 = ret.Get(1).(int64) 242 | } 243 | 244 | var r2 error 245 | if rf, ok := ret.Get(2).(func(uint, scopes.GormPager) error); ok { 246 | r2 = rf(userID, pagination) 247 | } else { 248 | r2 = ret.Error(2) 249 | } 250 | 251 | return r0, r1, r2 252 | } 253 | 254 | // GetRoleIDsOfPermission provides a mock function with given fields: userID, pagination 255 | func (_m *RoleRepository) GetRoleIDsOfPermission(permissionID uint, pagination scopes.GormPager) (roleIDs []uint, totalCount int64, err error) { 256 | ret := _m.Called(permissionID, pagination) 257 | 258 | var r0 []uint 259 | if rf, ok := ret.Get(0).(func(uint, scopes.GormPager) []uint); ok { 260 | r0 = rf(permissionID, pagination) 261 | } else { 262 | r0 = ret.Get(0).([]uint) 263 | } 264 | 265 | var r1 int64 266 | if rf, ok := ret.Get(1).(func(uint, scopes.GormPager) int64); ok { 267 | r1 = rf(permissionID, pagination) 268 | } else { 269 | r1 = ret.Get(1).(int64) 270 | } 271 | 272 | var r2 error 273 | if rf, ok := ret.Get(2).(func(uint, scopes.GormPager) error); ok { 274 | r2 = rf(permissionID, pagination) 275 | } else { 276 | r2 = ret.Error(2) 277 | } 278 | 279 | return r0, r1, r2 280 | } 281 | 282 | // FirstOrCreate provides a mock function with given fields: permission 283 | func (_m *RoleRepository) FirstOrCreate(role *models.Role) error { 284 | ret := _m.Called(role) 285 | 286 | var r0 error 287 | if rf, ok := ret.Get(0).(func(*models.Role) error); ok { 288 | r0 = rf(role) 289 | } else { 290 | r0 = ret.Error(0) 291 | } 292 | 293 | return r0 294 | } 295 | 296 | // Updates provides a mock function with given fields: permission, updates 297 | func (_m *RoleRepository) Updates(role *models.Role, updates map[string]interface{}) (err error) { 298 | ret := _m.Called(role, updates) 299 | 300 | var r0 error 301 | if rf, ok := ret.Get(0).(func(*models.Role, map[string]interface{}) error); ok { 302 | r0 = rf(role, updates) 303 | } else { 304 | r0 = ret.Error(0) 305 | } 306 | 307 | return r0 308 | } 309 | 310 | // Delete provides a mock function with given fields: permission 311 | func (_m *RoleRepository) Delete(role *models.Role) (err error) { 312 | ret := _m.Called(role) 313 | 314 | var r0 error 315 | if rf, ok := ret.Get(0).(func(*models.Role) error); ok { 316 | r0 = rf(role) 317 | } else { 318 | r0 = ret.Error(0) 319 | } 320 | 321 | return r0 322 | } 323 | 324 | // AddPermissions provides a mock function with given fields: role, permissions 325 | func (_m *RoleRepository) AddPermissions(role *models.Role, permissions collections.Permission) error { 326 | ret := _m.Called(role, permissions) 327 | 328 | var r0 error 329 | if rf, ok := ret.Get(0).(func(*models.Role, collections.Permission) error); ok { 330 | r0 = rf(role, permissions) 331 | } else { 332 | r0 = ret.Error(0) 333 | } 334 | 335 | return r0 336 | } 337 | 338 | // ReplacePermissions provides a mock function with given fields: role, permissions 339 | func (_m *RoleRepository) ReplacePermissions(role *models.Role, permissions collections.Permission) error { 340 | ret := _m.Called(role, permissions) 341 | 342 | var r0 error 343 | if rf, ok := ret.Get(0).(func(*models.Role, collections.Permission) error); ok { 344 | r0 = rf(role, permissions) 345 | } else { 346 | r0 = ret.Error(0) 347 | } 348 | 349 | return r0 350 | } 351 | 352 | // RemovePermissions provides a mock function with given fields: role, permissions 353 | func (_m *RoleRepository) RemovePermissions(role *models.Role, permissions collections.Permission) error { 354 | ret := _m.Called(role, permissions) 355 | 356 | var r0 error 357 | if rf, ok := ret.Get(0).(func(*models.Role, collections.Permission) error); ok { 358 | r0 = rf(role, permissions) 359 | } else { 360 | r0 = ret.Error(0) 361 | } 362 | 363 | return r0 364 | } 365 | 366 | // ClearPermissions provides a mock function with given fields: role 367 | func (_m *RoleRepository) ClearPermissions(role *models.Role) error { 368 | ret := _m.Called(role) 369 | 370 | var r0 error 371 | if rf, ok := ret.Get(0).(func(*models.Role) error); ok { 372 | r0 = rf(role) 373 | } else { 374 | r0 = ret.Error(0) 375 | } 376 | 377 | return r0 378 | } 379 | 380 | // HasPermission provides a mock function with given fields: role, permissions 381 | func (_m *RoleRepository) HasPermission(roles collections.Role, permission models.Permission) (b bool, err error) { 382 | ret := _m.Called(roles, permission) 383 | 384 | var r0 bool 385 | if rf, ok := ret.Get(0).(func(collections.Role, models.Permission) bool); ok { 386 | r0 = rf(roles, permission) 387 | } else { 388 | r0 = ret.Get(0).(bool) 389 | } 390 | 391 | var r1 error 392 | if rf, ok := ret.Get(1).(func(collections.Role, models.Permission) error); ok { 393 | r1 = rf(roles, permission) 394 | } else { 395 | r1 = ret.Error(1) 396 | } 397 | 398 | return r0, r1 399 | } 400 | 401 | // HasAllPermissions provides a mock function with given fields: roles, permissions 402 | func (_m *RoleRepository) HasAllPermissions(roles collections.Role, permissions collections.Permission) (b bool, err error) { 403 | ret := _m.Called(roles, permissions) 404 | 405 | var r0 bool 406 | if rf, ok := ret.Get(0).(func(collections.Role, collections.Permission) bool); ok { 407 | r0 = rf(roles, permissions) 408 | } else { 409 | r0 = ret.Get(0).(bool) 410 | } 411 | 412 | var r1 error 413 | if rf, ok := ret.Get(1).(func(collections.Role, collections.Permission) error); ok { 414 | r1 = rf(roles, permissions) 415 | } else { 416 | r1 = ret.Error(1) 417 | } 418 | 419 | return r0, r1 420 | } 421 | 422 | // HasAnyPermissions provides a mock function with given fields: roles, permissions 423 | func (_m *RoleRepository) HasAnyPermissions(roles collections.Role, permissions collections.Permission) (b bool, err error) { 424 | ret := _m.Called(roles, permissions) 425 | 426 | var r0 bool 427 | if rf, ok := ret.Get(0).(func(collections.Role, collections.Permission) bool); ok { 428 | r0 = rf(roles, permissions) 429 | } else { 430 | r0 = ret.Get(0).(bool) 431 | } 432 | 433 | var r1 error 434 | if rf, ok := ret.Get(1).(func(collections.Role, collections.Permission) error); ok { 435 | r1 = rf(roles, permissions) 436 | } else { 437 | r1 = ret.Error(1) 438 | } 439 | 440 | return r0, r1 441 | } 442 | -------------------------------------------------------------------------------- /repositories/mocks/userRepository.go: -------------------------------------------------------------------------------- 1 | package mocks 2 | 3 | import ( 4 | "github.com/stretchr/testify/mock" 5 | 6 | "github.com/Permify/go-role/collections" 7 | "github.com/Permify/go-role/models" 8 | ) 9 | 10 | // UserRepository is an autogenerated mock type for the UserRepository type 11 | type UserRepository struct { 12 | mock.Mock 13 | } 14 | 15 | // AddPermissions provides a mock function with given fields: userID, permissions 16 | func (_m *UserRepository) AddPermissions(userID uint, permissions collections.Permission) error { 17 | ret := _m.Called(userID, permissions) 18 | 19 | var r0 error 20 | if rf, ok := ret.Get(0).(func(uint, collections.Permission) error); ok { 21 | r0 = rf(userID, permissions) 22 | } else { 23 | r0 = ret.Error(0) 24 | } 25 | 26 | return r0 27 | } 28 | 29 | // ReplacePermissions provides a mock function with given fields: userID, permissions 30 | func (_m *UserRepository) ReplacePermissions(userID uint, permissions collections.Permission) error { 31 | ret := _m.Called(userID, permissions) 32 | 33 | var r0 error 34 | if rf, ok := ret.Get(0).(func(uint, collections.Permission) error); ok { 35 | r0 = rf(userID, permissions) 36 | } else { 37 | r0 = ret.Error(0) 38 | } 39 | 40 | return r0 41 | } 42 | 43 | // RemovePermissions provides a mock function with given fields: userID, permissions 44 | func (_m *UserRepository) RemovePermissions(userID uint, permissions collections.Permission) error { 45 | ret := _m.Called(userID, permissions) 46 | 47 | var r0 error 48 | if rf, ok := ret.Get(0).(func(uint, collections.Permission) error); ok { 49 | r0 = rf(userID, permissions) 50 | } else { 51 | r0 = ret.Error(0) 52 | } 53 | 54 | return r0 55 | } 56 | 57 | // ClearPermissions provides a mock function with given fields: userID 58 | func (_m *UserRepository) ClearPermissions(userID uint) (err error) { 59 | ret := _m.Called(userID) 60 | 61 | var r0 error 62 | if rf, ok := ret.Get(0).(func(uint) error); ok { 63 | r0 = rf(userID) 64 | } else { 65 | r0 = ret.Error(0) 66 | } 67 | 68 | return r0 69 | } 70 | 71 | // AddRoles provides a mock function with given fields: userID, roles 72 | func (_m *UserRepository) AddRoles(userID uint, roles collections.Role) error { 73 | ret := _m.Called(userID, roles) 74 | 75 | var r0 error 76 | if rf, ok := ret.Get(0).(func(uint, collections.Role) error); ok { 77 | r0 = rf(userID, roles) 78 | } else { 79 | r0 = ret.Error(0) 80 | } 81 | 82 | return r0 83 | } 84 | 85 | // ReplaceRoles provides a mock function with given fields: userID, roles 86 | func (_m *UserRepository) ReplaceRoles(userID uint, roles collections.Role) error { 87 | ret := _m.Called(userID, roles) 88 | 89 | var r0 error 90 | if rf, ok := ret.Get(0).(func(uint, collections.Role) error); ok { 91 | r0 = rf(userID, roles) 92 | } else { 93 | r0 = ret.Error(0) 94 | } 95 | 96 | return r0 97 | } 98 | 99 | // RemoveRoles provides a mock function with given fields: userID, roles 100 | func (_m *UserRepository) RemoveRoles(userID uint, roles collections.Role) error { 101 | ret := _m.Called(userID, roles) 102 | 103 | var r0 error 104 | if rf, ok := ret.Get(0).(func(uint, collections.Role) error); ok { 105 | r0 = rf(userID, roles) 106 | } else { 107 | r0 = ret.Error(0) 108 | } 109 | 110 | return r0 111 | } 112 | 113 | // ClearRoles provides a mock function with given fields: userID 114 | func (_m *UserRepository) ClearRoles(userID uint) (err error) { 115 | ret := _m.Called(userID) 116 | 117 | var r0 error 118 | if rf, ok := ret.Get(0).(func(uint) error); ok { 119 | r0 = rf(userID) 120 | } else { 121 | r0 = ret.Error(0) 122 | } 123 | 124 | return r0 125 | } 126 | 127 | // HasRole provides a mock function with given fields: userID, role 128 | func (_m *UserRepository) HasRole(userID uint, role models.Role) (b bool, err error) { 129 | ret := _m.Called(userID, role) 130 | 131 | var r0 bool 132 | if rf, ok := ret.Get(0).(func(uint, models.Role) bool); ok { 133 | r0 = rf(userID, role) 134 | } else { 135 | r0 = ret.Get(0).(bool) 136 | } 137 | 138 | var r1 error 139 | if rf, ok := ret.Get(1).(func(uint, models.Role) error); ok { 140 | r1 = rf(userID, role) 141 | } else { 142 | r1 = ret.Error(1) 143 | } 144 | 145 | return r0, r1 146 | } 147 | 148 | // HasAllRoles provides a mock function with given fields: userID, roles 149 | func (_m *UserRepository) HasAllRoles(userID uint, roles collections.Role) (b bool, err error) { 150 | ret := _m.Called(userID, roles) 151 | 152 | var r0 bool 153 | if rf, ok := ret.Get(0).(func(uint, collections.Role) bool); ok { 154 | r0 = rf(userID, roles) 155 | } else { 156 | r0 = ret.Get(0).(bool) 157 | } 158 | 159 | var r1 error 160 | if rf, ok := ret.Get(1).(func(uint, collections.Role) error); ok { 161 | r1 = rf(userID, roles) 162 | } else { 163 | r1 = ret.Error(1) 164 | } 165 | 166 | return r0, r1 167 | } 168 | 169 | // HasAnyRoles provides a mock function with given fields: userID, roles 170 | func (_m *UserRepository) HasAnyRoles(userID uint, roles collections.Role) (b bool, err error) { 171 | ret := _m.Called(userID, roles) 172 | 173 | var r0 bool 174 | if rf, ok := ret.Get(0).(func(uint, collections.Role) bool); ok { 175 | r0 = rf(userID, roles) 176 | } else { 177 | r0 = ret.Get(0).(bool) 178 | } 179 | 180 | var r1 error 181 | if rf, ok := ret.Get(1).(func(uint, collections.Role) error); ok { 182 | r1 = rf(userID, roles) 183 | } else { 184 | r1 = ret.Error(1) 185 | } 186 | 187 | return r0, r1 188 | } 189 | 190 | // HasDirectPermission provides a mock function with given fields: userID, permission 191 | func (_m *UserRepository) HasDirectPermission(userID uint, permission models.Permission) (b bool, err error) { 192 | ret := _m.Called(userID, permission) 193 | 194 | var r0 bool 195 | if rf, ok := ret.Get(0).(func(uint, models.Permission) bool); ok { 196 | r0 = rf(userID, permission) 197 | } else { 198 | r0 = ret.Get(0).(bool) 199 | } 200 | 201 | var r1 error 202 | if rf, ok := ret.Get(1).(func(uint, models.Permission) error); ok { 203 | r1 = rf(userID, permission) 204 | } else { 205 | r1 = ret.Error(1) 206 | } 207 | 208 | return r0, r1 209 | } 210 | 211 | // HasAllDirectPermissions provides a mock function with given fields: userID, permissions 212 | func (_m *UserRepository) HasAllDirectPermissions(userID uint, permissions collections.Permission) (b bool, err error) { 213 | ret := _m.Called(userID, permissions) 214 | 215 | var r0 bool 216 | if rf, ok := ret.Get(0).(func(uint, collections.Permission) bool); ok { 217 | r0 = rf(userID, permissions) 218 | } else { 219 | r0 = ret.Get(0).(bool) 220 | } 221 | 222 | var r1 error 223 | if rf, ok := ret.Get(1).(func(uint, collections.Permission) error); ok { 224 | r1 = rf(userID, permissions) 225 | } else { 226 | r1 = ret.Error(1) 227 | } 228 | 229 | return r0, r1 230 | } 231 | 232 | // HasAnyDirectPermissions provides a mock function with given fields: userID, permissions 233 | func (_m *UserRepository) HasAnyDirectPermissions(userID uint, permissions collections.Permission) (b bool, err error) { 234 | ret := _m.Called(userID, permissions) 235 | 236 | var r0 bool 237 | if rf, ok := ret.Get(0).(func(uint, collections.Permission) bool); ok { 238 | r0 = rf(userID, permissions) 239 | } else { 240 | r0 = ret.Get(0).(bool) 241 | } 242 | 243 | var r1 error 244 | if rf, ok := ret.Get(1).(func(uint, collections.Permission) error); ok { 245 | r1 = rf(userID, permissions) 246 | } else { 247 | r1 = ret.Error(1) 248 | } 249 | 250 | return r0, r1 251 | } 252 | -------------------------------------------------------------------------------- /repositories/permissionRepository.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/Permify/go-role/collections" 7 | "github.com/Permify/go-role/models" 8 | "github.com/Permify/go-role/models/pivot" 9 | "github.com/Permify/go-role/repositories/scopes" 10 | ) 11 | 12 | // IPermissionRepository its data access layer abstraction of permission. 13 | type IPermissionRepository interface { 14 | Migratable 15 | 16 | // single fetch options 17 | 18 | GetPermissionByID(ID uint) (permission models.Permission, err error) 19 | GetPermissionByGuardName(guardName string) (permission models.Permission, err error) 20 | 21 | // Multiple fetch options 22 | 23 | GetPermissions(IDs []uint) (permissions collections.Permission, err error) 24 | GetPermissionsByGuardNames(guardNames []string) (permissions collections.Permission, err error) 25 | 26 | // ID fetch options 27 | 28 | GetPermissionIDs(pagination scopes.GormPager) (permissionIDs []uint, totalCount int64, err error) 29 | GetDirectPermissionIDsOfUserByID(userID uint, pagination scopes.GormPager) (permissionIDs []uint, totalCount int64, err error) 30 | GetPermissionIDsOfRolesByIDs(roleIDs []uint, pagination scopes.GormPager) (permissionIDs []uint, totalCount int64, err error) 31 | 32 | // FirstOrCreate & Updates & Delete 33 | 34 | FirstOrCreate(permission *models.Permission) (err error) 35 | Updates(permission *models.Permission, updates map[string]interface{}) (err error) 36 | Delete(permission *models.Permission) (err error) 37 | } 38 | 39 | // PermissionRepository its data access layer of permission. 40 | type PermissionRepository struct { 41 | Database *gorm.DB 42 | } 43 | 44 | // Migrate generate tables from the database. 45 | // @return error 46 | func (repository *PermissionRepository) Migrate() (err error) { 47 | err = repository.Database.AutoMigrate(models.Permission{}) 48 | err = repository.Database.AutoMigrate(pivot.UserPermissions{}) 49 | return 50 | } 51 | 52 | // GetPermissionByID get permission by id. 53 | // @param uint 54 | // @return models.Permission, error 55 | func (repository *PermissionRepository) GetPermissionByID(ID uint) (permission models.Permission, err error) { 56 | err = repository.Database.First(&permission, "permissions.id = ?", ID).Error 57 | return 58 | } 59 | 60 | // GetPermissionByGuardName get permission by guard name. 61 | // @param string 62 | // @return models.Permission, error 63 | func (repository *PermissionRepository) GetPermissionByGuardName(guardName string) (permission models.Permission, err error) { 64 | err = repository.Database.Where("permissions.guard_name = ?", guardName).First(&permission).Error 65 | return 66 | } 67 | 68 | // MULTIPLE FETCH OPTIONS 69 | 70 | // GetPermissions get permissions by ids. 71 | // @param []uint 72 | // @return collections.Role, error 73 | func (repository *PermissionRepository) GetPermissions(IDs []uint) (permissions collections.Permission, err error) { 74 | err = repository.Database.Where("permissions.id IN (?)", IDs).Find(&permissions).Error 75 | return 76 | } 77 | 78 | // GetPermissionsByGuardNames get permissions by guard names. 79 | // @param []string 80 | // @return collections.Permission, error 81 | func (repository *PermissionRepository) GetPermissionsByGuardNames(guardNames []string) (permissions collections.Permission, err error) { 82 | err = repository.Database.Where("permissions.guard_name IN (?)", guardNames).Find(&permissions).Error 83 | return 84 | } 85 | 86 | // ID FETCH OPTIONS 87 | 88 | // GetPermissionIDs get permission ids. (with pagination) 89 | // @param repositories_scopes.GormPager 90 | // @return []uint, int64, error 91 | func (repository *PermissionRepository) GetPermissionIDs(pagination scopes.GormPager) (permissionIDs []uint, totalCount int64, err error) { 92 | err = repository.Database.Model(&models.Permission{}).Count(&totalCount).Scopes(repository.paginate(pagination)).Pluck("permissions.id", &permissionIDs).Error 93 | return 94 | } 95 | 96 | // GetDirectPermissionIDsOfUserByID get direct permission ids of user. (with pagination) 97 | // @param uint 98 | // @param repositories_scopes.GormPager 99 | // @return []uint, int64, error 100 | func (repository *PermissionRepository) GetDirectPermissionIDsOfUserByID(userID uint, pagination scopes.GormPager) (permissionIDs []uint, totalCount int64, err error) { 101 | err = repository.Database.Table("user_permissions").Where("user_permissions.user_id = ?", userID).Count(&totalCount).Scopes(repository.paginate(pagination)).Pluck("user_permissions.permission_id", &permissionIDs).Error 102 | return 103 | } 104 | 105 | // GetPermissionIDsOfRolesByIDs get permission ids of roles. (with pagination) 106 | // @param []uint 107 | // @param repositories_scopes.GormPager 108 | // @return []uint, int64, error 109 | func (repository *PermissionRepository) GetPermissionIDsOfRolesByIDs(roleIDs []uint, pagination scopes.GormPager) (permissionIDs []uint, totalCount int64, err error) { 110 | err = repository.Database.Table("role_permissions").Distinct("role_permissions.permission_id").Where("role_permissions.role_id IN (?)", roleIDs).Count(&totalCount).Scopes(repository.paginate(pagination)).Pluck("role_permissions.permission_id", &permissionIDs).Error 111 | return 112 | } 113 | 114 | // FirstOrCreate & Updates & Delete 115 | 116 | // FirstOrCreate create new permission if name not exist. 117 | // @param *models.Permission 118 | // @return error 119 | func (repository *PermissionRepository) FirstOrCreate(permission *models.Permission) error { 120 | return repository.Database.Where(models.Role{GuardName: permission.GuardName}).FirstOrCreate(permission).Error 121 | } 122 | 123 | // Updates update permission. 124 | // @param *models.Permission 125 | // @param map[string]interface{} 126 | // @return error 127 | func (repository *PermissionRepository) Updates(permission *models.Permission, updates map[string]interface{}) (err error) { 128 | return repository.Database.Model(permission).Updates(updates).Error 129 | } 130 | 131 | // Delete delete permission. 132 | // @param *models.Permission 133 | // @return error 134 | func (repository *PermissionRepository) Delete(permission *models.Permission) (err error) { 135 | return repository.Database.Transaction(func(tx *gorm.DB) error { 136 | if err := tx.Where("user_permissions.permission_id = ?", permission.ID).Delete(&pivot.UserPermissions{}).Error; err != nil { 137 | tx.Rollback() 138 | return err 139 | } 140 | if err := tx.Delete(permission).Error; err != nil { 141 | tx.Rollback() 142 | return err 143 | } 144 | return nil 145 | }) 146 | } 147 | 148 | // paginate pagging if pagination option is true. 149 | // @param repositories_scopes.GormPager 150 | // @return func(db *gorm.DB) *gorm.DB 151 | func (repository *PermissionRepository) paginate(pagination scopes.GormPager) func(db *gorm.DB) *gorm.DB { 152 | return func(db *gorm.DB) *gorm.DB { 153 | if pagination != nil { 154 | db.Scopes(pagination.ToPaginate()) 155 | } 156 | 157 | return db 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /repositories/permissionRepository_test.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "database/sql" 5 | "regexp" 6 | 7 | "github.com/DATA-DOG/go-sqlmock" 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | "gorm.io/driver/postgres" 11 | "gorm.io/gorm" 12 | 13 | "github.com/Permify/go-role/models" 14 | ) 15 | 16 | var _ = Describe("Permission Repository", func() { 17 | var repository *PermissionRepository 18 | var mock sqlmock.Sqlmock 19 | 20 | BeforeEach(func() { 21 | var db *sql.DB 22 | var err error 23 | 24 | db, mock, err = sqlmock.New() 25 | Expect(err).ShouldNot(HaveOccurred()) 26 | 27 | var gormDb *gorm.DB 28 | dialector := postgres.New(postgres.Config{ 29 | DSN: "sqlmock_db_0", 30 | DriverName: "postgres", 31 | Conn: db, 32 | PreferSimpleProtocol: true, 33 | }) 34 | gormDb, err = gorm.Open(dialector, &gorm.Config{}) 35 | Expect(err).ShouldNot(HaveOccurred()) 36 | 37 | repository = &PermissionRepository{Database: gormDb} 38 | }) 39 | 40 | AfterEach(func() { 41 | err := mock.ExpectationsWereMet() 42 | Expect(err).ShouldNot(HaveOccurred()) 43 | }) 44 | 45 | Context("Get Permission By ID", func() { 46 | It("found", func() { 47 | permission := models.Permission{ 48 | ID: 1, 49 | Name: "create contact permission", 50 | GuardName: "create-contact-permission", 51 | } 52 | 53 | rows := sqlmock.NewRows([]string{"id", "name", "guard_name"}). 54 | AddRow(permission.ID, permission.Name, permission.GuardName) 55 | 56 | const sqlSelectOne = `SELECT * FROM "permissions" WHERE permissions.id = $1 ORDER BY "permissions"."id" LIMIT 1` 57 | 58 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 59 | WithArgs(permission.ID). 60 | WillReturnRows(rows) 61 | 62 | value, err := repository.GetPermissionByID(permission.ID) 63 | Expect(err).ShouldNot(HaveOccurred()) 64 | Expect(value).Should(Equal(permission)) 65 | }) 66 | 67 | It("not found", func() { 68 | // ignore sql match 69 | mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) 70 | _, err := repository.GetPermissionByID(1) 71 | Expect(err).Should(Equal(gorm.ErrRecordNotFound)) 72 | }) 73 | }) 74 | 75 | Context("Get Permission By Guard Name", func() { 76 | It("found", func() { 77 | permission := models.Permission{ 78 | ID: 1, 79 | Name: "create contact permission", 80 | GuardName: "create-contact-permission", 81 | } 82 | 83 | rows := sqlmock.NewRows([]string{"id", "name", "guard_name"}). 84 | AddRow(permission.ID, permission.Name, permission.GuardName) 85 | 86 | const sqlSelectOne = `SELECT * FROM "permissions" WHERE permissions.guard_name = $1 ORDER BY "permissions"."id" LIMIT 1` 87 | 88 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 89 | WithArgs(permission.GuardName). 90 | WillReturnRows(rows) 91 | 92 | value, err := repository.GetPermissionByGuardName(permission.GuardName) 93 | Expect(err).ShouldNot(HaveOccurred()) 94 | Expect(value).Should(Equal(permission)) 95 | }) 96 | 97 | It("not found", func() { 98 | mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) 99 | _, err := repository.GetPermissionByGuardName("create-contact-permission") 100 | Expect(err).Should(Equal(gorm.ErrRecordNotFound)) 101 | }) 102 | }) 103 | 104 | Context("Get Permissions", func() { 105 | It("found", func() { 106 | permissions := []models.Permission{ 107 | { 108 | ID: 1, 109 | Name: "create contact permission", 110 | GuardName: "create-contact-permission", 111 | }, 112 | } 113 | 114 | rows := sqlmock.NewRows([]string{"id", "name", "guard_name"}). 115 | AddRow(permissions[0].ID, permissions[0].Name, permissions[0].GuardName) 116 | 117 | const sqlSelectOne = `SELECT * FROM "permissions" WHERE permissions.id IN ($1)` 118 | 119 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 120 | WithArgs(permissions[0].ID). 121 | WillReturnRows(rows) 122 | 123 | value, err := repository.GetPermissions([]uint{permissions[0].ID}) 124 | Expect(err).ShouldNot(HaveOccurred()) 125 | Expect(value.Origin()).Should(Equal(permissions)) 126 | }) 127 | }) 128 | 129 | Context("Get Permissions By Guard Names", func() { 130 | It("found", func() { 131 | permissions := []models.Permission{ 132 | { 133 | ID: 1, 134 | Name: "create contact permission", 135 | GuardName: "create-contact-permission", 136 | }, 137 | } 138 | 139 | rows := sqlmock.NewRows([]string{"id", "name", "guard_name"}). 140 | AddRow(permissions[0].ID, permissions[0].Name, permissions[0].GuardName) 141 | 142 | const sqlSelectOne = `SELECT * FROM "permissions" WHERE permissions.guard_name IN ($1)` 143 | 144 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 145 | WithArgs(permissions[0].GuardName). 146 | WillReturnRows(rows) 147 | 148 | value, err := repository.GetPermissionsByGuardNames([]string{permissions[0].GuardName}) 149 | Expect(err).ShouldNot(HaveOccurred()) 150 | Expect(value.Origin()).Should(Equal(permissions)) 151 | }) 152 | }) 153 | }) 154 | -------------------------------------------------------------------------------- /repositories/repository_test.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestRepositories(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "postgres suite") 13 | } 14 | -------------------------------------------------------------------------------- /repositories/roleRepository.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/Permify/go-role/collections" 7 | "github.com/Permify/go-role/models" 8 | "github.com/Permify/go-role/models/pivot" 9 | "github.com/Permify/go-role/repositories/scopes" 10 | ) 11 | 12 | // IRoleRepository its data access layer abstraction of role. 13 | type IRoleRepository interface { 14 | Migratable 15 | 16 | // single fetch options 17 | 18 | GetRoleByID(ID uint) (role models.Role, err error) 19 | GetRoleByIDWithPermissions(ID uint) (role models.Role, err error) 20 | 21 | GetRoleByGuardName(guardName string) (role models.Role, err error) 22 | GetRoleByGuardNameWithPermissions(guardName string) (role models.Role, err error) 23 | 24 | // Multiple fetch options 25 | 26 | GetRoles(roleIDs []uint) (roles collections.Role, err error) 27 | GetRolesWithPermissions(roleIDs []uint) (roles collections.Role, err error) 28 | 29 | GetRolesByGuardNames(guardNames []string) (roles collections.Role, err error) 30 | GetRolesByGuardNamesWithPermissions(guardNames []string) (roles collections.Role, err error) 31 | 32 | // ID fetch options 33 | 34 | GetRoleIDs(pagination scopes.GormPager) (roleIDs []uint, totalCount int64, err error) 35 | GetRoleIDsOfUser(userID uint, pagination scopes.GormPager) (roleIDs []uint, totalCount int64, err error) 36 | GetRoleIDsOfPermission(permissionID uint, pagination scopes.GormPager) (roleIDs []uint, totalCount int64, err error) 37 | 38 | // FirstOrCreate & Updates & Delete 39 | 40 | FirstOrCreate(role *models.Role) (err error) 41 | Updates(role *models.Role, updates map[string]interface{}) (err error) 42 | Delete(role *models.Role) (err error) 43 | 44 | // Actions 45 | 46 | AddPermissions(role *models.Role, permissions collections.Permission) (err error) 47 | ReplacePermissions(role *models.Role, permissions collections.Permission) (err error) 48 | RemovePermissions(role *models.Role, permissions collections.Permission) (err error) 49 | ClearPermissions(role *models.Role) (err error) 50 | 51 | // Controls 52 | 53 | HasPermission(roles collections.Role, permission models.Permission) (b bool, err error) 54 | HasAllPermissions(roles collections.Role, permissions collections.Permission) (b bool, err error) 55 | HasAnyPermissions(roles collections.Role, permissions collections.Permission) (b bool, err error) 56 | } 57 | 58 | // RoleRepository its data access layer of role. 59 | type RoleRepository struct { 60 | Database *gorm.DB 61 | } 62 | 63 | // Migrate generate tables from the database. 64 | // @return error 65 | func (repository *RoleRepository) Migrate() (err error) { 66 | err = repository.Database.AutoMigrate(models.Role{}) 67 | err = repository.Database.AutoMigrate(pivot.UserRoles{}) 68 | return 69 | } 70 | 71 | // SINGLE FETCH OPTIONS 72 | 73 | // GetRoleByID get role by id. 74 | // @param uint 75 | // @return models.Role, error 76 | func (repository *RoleRepository) GetRoleByID(ID uint) (role models.Role, err error) { 77 | err = repository.Database.First(&role, "roles.id = ?", ID).Error 78 | return 79 | } 80 | 81 | // GetRoleByIDWithPermissions get role by id with its permissions. 82 | // @param uint 83 | // @return models.Role, error 84 | func (repository *RoleRepository) GetRoleByIDWithPermissions(ID uint) (role models.Role, err error) { 85 | err = repository.Database.Preload("Permissions").First(&role, "roles.id = ?", ID).Error 86 | return 87 | } 88 | 89 | // GetRoleByGuardName get role by guard name. 90 | // @param string 91 | // @return models.Role, error 92 | func (repository *RoleRepository) GetRoleByGuardName(guardName string) (role models.Role, err error) { 93 | err = repository.Database.Where("roles.guard_name = ?", guardName).First(&role).Error 94 | return 95 | } 96 | 97 | // GetRoleByGuardNameWithPermissions get role by guard name with its permissions. 98 | // @param string 99 | // @return models.Role, error 100 | func (repository *RoleRepository) GetRoleByGuardNameWithPermissions(guardName string) (role models.Role, err error) { 101 | err = repository.Database.Preload("Permissions").Where("roles.guard_name = ?", guardName).First(&role).Error 102 | return 103 | } 104 | 105 | // MULTIPLE FETCH OPTIONS 106 | 107 | // GetRoles get roles by ids. 108 | // @param []uint 109 | // @return collections.Role, error 110 | func (repository *RoleRepository) GetRoles(IDs []uint) (roles collections.Role, err error) { 111 | err = repository.Database.Where("roles.id IN (?)", IDs).Find(&roles).Error 112 | return 113 | } 114 | 115 | // GetRolesWithPermissions get roles by ids with its permissions. 116 | // @param []uint 117 | // @return collections.Role, error 118 | func (repository *RoleRepository) GetRolesWithPermissions(IDs []uint) (roles collections.Role, err error) { 119 | err = repository.Database.Preload("Permissions").Where("roles.id IN (?)", IDs).Find(&roles).Error 120 | return 121 | } 122 | 123 | // GetRolesByGuardNames get roles by guard names. 124 | // @param []string 125 | // @return collections.Role, error 126 | func (repository *RoleRepository) GetRolesByGuardNames(guardNames []string) (roles collections.Role, err error) { 127 | err = repository.Database.Where("roles.guard_name IN (?)", guardNames).Find(&roles).Error 128 | return 129 | } 130 | 131 | // GetRolesByGuardNamesWithPermissions get roles by guard names. 132 | // @param []string 133 | // @return collections.Role, error 134 | func (repository *RoleRepository) GetRolesByGuardNamesWithPermissions(guardNames []string) (roles collections.Role, err error) { 135 | err = repository.Database.Preload("Permissions").Where("roles.guard_name IN (?)", guardNames).Find(&roles).Error 136 | return 137 | } 138 | 139 | // ID FETCH OPTIONS 140 | 141 | // GetRoleIDs get role ids. (with pagination) 142 | // @param repositories_scopes.GormPager 143 | // @return []uint, int64, error 144 | func (repository *RoleRepository) GetRoleIDs(pagination scopes.GormPager) (roleIDs []uint, totalCount int64, err error) { 145 | err = repository.Database.Model(&models.Role{}).Count(&totalCount).Scopes(repository.paginate(pagination)).Pluck("roles.id", &roleIDs).Error 146 | return 147 | } 148 | 149 | // GetRoleIDsOfUser get role ids of user. (with pagination) 150 | // @param uint 151 | // @param repositories_scopes.GormPager 152 | // @return []uint, int64, error 153 | func (repository *RoleRepository) GetRoleIDsOfUser(userID uint, pagination scopes.GormPager) (roleIDs []uint, totalCount int64, err error) { 154 | err = repository.Database.Table("user_roles").Where("user_roles.user_id = ?", userID).Count(&totalCount).Scopes(repository.paginate(pagination)).Pluck("user_roles.role_id", &roleIDs).Error 155 | return 156 | } 157 | 158 | // GetRoleIDsOfPermission get role ids of permission. (with pagination) 159 | // @param uint 160 | // @param repositories_scopes.GormPager 161 | // @return []uint, int64, error 162 | func (repository *RoleRepository) GetRoleIDsOfPermission(permissionID uint, pagination scopes.GormPager) (roleIDs []uint, totalCount int64, err error) { 163 | err = repository.Database.Table("role_permissions").Where("role_permissions.permission_id = ?", permissionID).Count(&totalCount).Scopes(repository.paginate(pagination)).Pluck("role_permissions.role_id", &roleIDs).Error 164 | return 165 | } 166 | 167 | // FirstOrCreate & Updates & Delete 168 | 169 | // FirstOrCreate create new role if name not exist. 170 | // @param *models.Role 171 | // @return error 172 | func (repository *RoleRepository) FirstOrCreate(role *models.Role) error { 173 | return repository.Database.Where(models.Role{GuardName: role.GuardName}).FirstOrCreate(role).Error 174 | } 175 | 176 | // Updates update role. 177 | // @param *models.Role 178 | // @param map[string]interface{} 179 | // @return error 180 | func (repository *RoleRepository) Updates(role *models.Role, updates map[string]interface{}) (err error) { 181 | return repository.Database.Model(role).Updates(updates).Error 182 | } 183 | 184 | // Delete delete role. 185 | // @param *models.Role 186 | // @return error 187 | func (repository *RoleRepository) Delete(role *models.Role) (err error) { 188 | return repository.Database.Transaction(func(tx *gorm.DB) error { 189 | if err := tx.Where("user_roles.role_id = ?", role.ID).Delete(&pivot.UserRoles{}).Error; err != nil { 190 | tx.Rollback() 191 | return err 192 | } 193 | if err := tx.Delete(role).Error; err != nil { 194 | tx.Rollback() 195 | return err 196 | } 197 | return nil 198 | }) 199 | } 200 | 201 | // ACTIONS 202 | 203 | // AddPermissions add permissions to role. 204 | // @param *models.Role 205 | // @param collections.Permission 206 | // @return error 207 | func (repository *RoleRepository) AddPermissions(role *models.Role, permissions collections.Permission) error { 208 | return repository.Database.Model(role).Association("Permissions").Append(permissions.Origin()) 209 | } 210 | 211 | // ReplacePermissions replace permissions of role. 212 | // @param *models.Role 213 | // @param collections.Permission 214 | // @return error 215 | func (repository *RoleRepository) ReplacePermissions(role *models.Role, permissions collections.Permission) error { 216 | return repository.Database.Model(role).Association("Permissions").Replace(permissions.Origin()) 217 | } 218 | 219 | // RemovePermissions remove permissions of role. 220 | // @param *models.Role 221 | // @param collections.Permission 222 | // @return error 223 | func (repository *RoleRepository) RemovePermissions(role *models.Role, permissions collections.Permission) error { 224 | return repository.Database.Model(role).Association("Permissions").Delete(permissions.Origin()) 225 | } 226 | 227 | // ClearPermissions remove all permissions of role. 228 | // @param *models.Role 229 | // @return error 230 | func (repository *RoleRepository) ClearPermissions(role *models.Role) (err error) { 231 | return repository.Database.Model(role).Association("Permissions").Clear() 232 | } 233 | 234 | // Controls 235 | 236 | // HasPermission does the role or any of the roles have given permission? 237 | // @param collections.Role 238 | // @param models.Permission 239 | // @return bool, error 240 | func (repository *RoleRepository) HasPermission(roles collections.Role, permission models.Permission) (b bool, err error) { 241 | var count int64 242 | err = repository.Database.Table("role_permissions").Where("role_permissions.role_id IN (?)", roles.IDs()).Where("role_permissions.permission_id = ?", permission.ID).Count(&count).Error 243 | return count > 0, err 244 | } 245 | 246 | // HasAllPermissions does the role or roles have all the given permissions? 247 | // @param collections.Role 248 | // @param collections.Permission 249 | // @return bool, error 250 | func (repository *RoleRepository) HasAllPermissions(roles collections.Role, permissions collections.Permission) (b bool, err error) { 251 | var count int64 252 | err = repository.Database.Table("role_permissions").Where("role_permissions.role_id IN (?)", roles.IDs()).Where("role_permissions.permission_id IN (?)", permissions.IDs()).Count(&count).Error 253 | return roles.Len()*permissions.Len() == count, err 254 | } 255 | 256 | // HasAnyPermissions does the role or roles have any of the given permissions? 257 | // @param collections.Role 258 | // @param collections.Permission 259 | // @return bool, error 260 | func (repository *RoleRepository) HasAnyPermissions(roles collections.Role, permissions collections.Permission) (b bool, err error) { 261 | var count int64 262 | err = repository.Database.Table("role_permissions").Where("role_permissions.role_id IN (?)", roles.IDs()).Where("role_permissions.permission_id IN (?)", permissions.IDs()).Count(&count).Error 263 | return count > 0, err 264 | } 265 | 266 | // paginate pagging if pagination option is true. 267 | // @param repositories_scopes.GormPager 268 | // @return func(db *gorm.DB) *gorm.DB 269 | func (repository *RoleRepository) paginate(pagination scopes.GormPager) func(db *gorm.DB) *gorm.DB { 270 | return func(db *gorm.DB) *gorm.DB { 271 | if pagination != nil { 272 | db.Scopes(pagination.ToPaginate()) 273 | } 274 | 275 | return db 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /repositories/roleRepository_test.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "database/sql" 5 | "regexp" 6 | 7 | "github.com/DATA-DOG/go-sqlmock" 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | "gorm.io/driver/postgres" 11 | "gorm.io/gorm" 12 | 13 | "github.com/Permify/go-role/collections" 14 | "github.com/Permify/go-role/models" 15 | ) 16 | 17 | var _ = Describe("Role Repository", func() { 18 | var repository *RoleRepository 19 | var mock sqlmock.Sqlmock 20 | 21 | BeforeEach(func() { 22 | var db *sql.DB 23 | var err error 24 | 25 | db, mock, err = sqlmock.New() 26 | Expect(err).ShouldNot(HaveOccurred()) 27 | 28 | var gormDb *gorm.DB 29 | dialector := postgres.New(postgres.Config{ 30 | DSN: "sqlmock_db_0", 31 | DriverName: "postgres", 32 | Conn: db, 33 | PreferSimpleProtocol: true, 34 | }) 35 | gormDb, err = gorm.Open(dialector, &gorm.Config{}) 36 | Expect(err).ShouldNot(HaveOccurred()) 37 | 38 | repository = &RoleRepository{Database: gormDb} 39 | }) 40 | 41 | AfterEach(func() { 42 | err := mock.ExpectationsWereMet() 43 | Expect(err).ShouldNot(HaveOccurred()) 44 | }) 45 | 46 | Context("Get Role By ID", func() { 47 | It("found", func() { 48 | role := models.Role{ 49 | ID: 1, 50 | Name: "admin", 51 | GuardName: "admin", 52 | } 53 | 54 | rows := sqlmock.NewRows([]string{"id", "name", "guard_name"}). 55 | AddRow(role.ID, role.Name, role.GuardName) 56 | 57 | const sqlSelectOne = `SELECT * FROM "roles" WHERE roles.id = $1 ORDER BY "roles"."id" LIMIT 1` 58 | 59 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 60 | WithArgs(role.ID). 61 | WillReturnRows(rows) 62 | 63 | db, err := repository.GetRoleByID(role.ID) 64 | Expect(err).ShouldNot(HaveOccurred()) 65 | Expect(db).Should(Equal(role)) 66 | }) 67 | 68 | It("not found", func() { 69 | // ignore sql match 70 | mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) 71 | _, err := repository.GetRoleByID(1) 72 | Expect(err).Should(Equal(gorm.ErrRecordNotFound)) 73 | }) 74 | }) 75 | 76 | Context("Get Role By Guard Name", func() { 77 | It("found", func() { 78 | role := models.Role{ 79 | ID: 1, 80 | Name: "admin", 81 | GuardName: "admin", 82 | } 83 | 84 | rows := sqlmock.NewRows([]string{"id", "name", "guard_name"}). 85 | AddRow(role.ID, role.Name, role.GuardName) 86 | 87 | const sqlSelectOne = `SELECT * FROM "roles" WHERE roles.guard_name = $1 ORDER BY "roles"."id" LIMIT 1` 88 | 89 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 90 | WithArgs(role.GuardName). 91 | WillReturnRows(rows) 92 | 93 | db, err := repository.GetRoleByGuardName(role.GuardName) 94 | Expect(err).ShouldNot(HaveOccurred()) 95 | Expect(db).Should(Equal(role)) 96 | }) 97 | 98 | It("not found", func() { 99 | mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) 100 | _, err := repository.GetRoleByGuardName("admin") 101 | Expect(err).Should(Equal(gorm.ErrRecordNotFound)) 102 | }) 103 | }) 104 | 105 | Context("Get Roles", func() { 106 | It("found", func() { 107 | roles := []models.Role{ 108 | { 109 | ID: 1, 110 | Name: "admin", 111 | GuardName: "admin", 112 | }, 113 | } 114 | 115 | rows := sqlmock.NewRows([]string{"id", "name", "guard_name"}). 116 | AddRow(roles[0].ID, roles[0].Name, roles[0].GuardName) 117 | 118 | const sqlSelectOne = `SELECT * FROM "roles" WHERE roles.id IN ($1)` 119 | 120 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 121 | WithArgs(roles[0].ID). 122 | WillReturnRows(rows) 123 | 124 | value, err := repository.GetRoles([]uint{roles[0].ID}) 125 | Expect(err).ShouldNot(HaveOccurred()) 126 | Expect(value.Origin()).Should(Equal(roles)) 127 | }) 128 | }) 129 | 130 | Context("Get Roles By Guard Names", func() { 131 | It("found", func() { 132 | roles := []models.Role{ 133 | { 134 | ID: 1, 135 | Name: "admin", 136 | GuardName: "admin", 137 | }, 138 | } 139 | 140 | rows := sqlmock.NewRows([]string{"id", "name", "guard_name"}). 141 | AddRow(roles[0].ID, roles[0].Name, roles[0].GuardName) 142 | 143 | const sqlSelectOne = `SELECT * FROM "roles" WHERE roles.guard_name IN ($1)` 144 | 145 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 146 | WithArgs(roles[0].GuardName). 147 | WillReturnRows(rows) 148 | 149 | value, err := repository.GetRolesByGuardNames([]string{roles[0].GuardName}) 150 | Expect(err).ShouldNot(HaveOccurred()) 151 | Expect(value.Origin()).Should(Equal(roles)) 152 | }) 153 | }) 154 | 155 | Context("Has Permission", func() { 156 | It("found", func() { 157 | const sqlSelectOne = `SELECT count(*) FROM "role_permissions" WHERE role_permissions.role_id IN ($1) AND role_permissions.permission_id = $2` 158 | 159 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 160 | WithArgs(1, 1). 161 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 162 | AddRow(1)) 163 | 164 | db, err := repository.HasPermission(collections.Role([]models.Role{{ID: 1}}), models.Permission{ID: 1}) 165 | Expect(err).ShouldNot(HaveOccurred()) 166 | Expect(db).Should(Equal(true)) 167 | }) 168 | 169 | It("not found", func() { 170 | const sqlSelectOne = `SELECT count(*) FROM "role_permissions" WHERE role_permissions.role_id IN ($1) AND role_permissions.permission_id = $2` 171 | 172 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 173 | WithArgs(1, 1). 174 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 175 | AddRow(0)) 176 | 177 | db, err := repository.HasPermission(collections.Role([]models.Role{{ID: 1}}), models.Permission{ID: 1}) 178 | Expect(err).ShouldNot(HaveOccurred()) 179 | Expect(db).Should(Equal(false)) 180 | }) 181 | }) 182 | 183 | Context("Has All Permission", func() { 184 | It("found", func() { 185 | const sqlSelectOne = `SELECT count(*) FROM "role_permissions" WHERE role_permissions.role_id IN ($1) AND role_permissions.permission_id IN ($2)` 186 | 187 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 188 | WithArgs(1, 1). 189 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 190 | AddRow(1)) 191 | 192 | db, err := repository.HasAllPermissions(collections.Role([]models.Role{{ID: 1}}), collections.Permission([]models.Permission{{ID: 1}})) 193 | Expect(err).ShouldNot(HaveOccurred()) 194 | Expect(db).Should(Equal(true)) 195 | }) 196 | 197 | It("not found", func() { 198 | const sqlSelectOne = `SELECT count(*) FROM "role_permissions" WHERE role_permissions.role_id IN ($1,$2) AND role_permissions.permission_id IN ($3)` 199 | 200 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 201 | WithArgs(1, 2, 1). 202 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 203 | AddRow(1)) 204 | 205 | db, err := repository.HasAllPermissions(collections.Role([]models.Role{{ID: 1}, {ID: 2}}), collections.Permission([]models.Permission{{ID: 1}})) 206 | Expect(err).ShouldNot(HaveOccurred()) 207 | Expect(db).Should(Equal(false)) 208 | }) 209 | }) 210 | 211 | Context("Has Any Permission", func() { 212 | It("found", func() { 213 | const sqlSelectOne = `SELECT count(*) FROM "role_permissions" WHERE role_permissions.role_id IN ($1) AND role_permissions.permission_id IN ($2)` 214 | 215 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 216 | WithArgs(1, 1). 217 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 218 | AddRow(1)) 219 | 220 | db, err := repository.HasAnyPermissions(collections.Role([]models.Role{{ID: 1}}), collections.Permission([]models.Permission{{ID: 1}})) 221 | Expect(err).ShouldNot(HaveOccurred()) 222 | Expect(db).Should(Equal(true)) 223 | }) 224 | 225 | It("found", func() { 226 | const sqlSelectOne = `SELECT count(*) FROM "role_permissions" WHERE role_permissions.role_id IN ($1) AND role_permissions.permission_id IN ($2)` 227 | 228 | mock.ExpectQuery(regexp.QuoteMeta(sqlSelectOne)). 229 | WithArgs(1, 1). 230 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 231 | AddRow(0)) 232 | 233 | db, err := repository.HasAnyPermissions(collections.Role([]models.Role{{ID: 1}}), collections.Permission([]models.Permission{{ID: 1}})) 234 | Expect(err).ShouldNot(HaveOccurred()) 235 | Expect(db).Should(Equal(false)) 236 | }) 237 | }) 238 | }) 239 | -------------------------------------------------------------------------------- /repositories/scopes/pagination.go: -------------------------------------------------------------------------------- 1 | package scopes 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/Permify/go-role/helpers" 7 | "github.com/Permify/go-role/utils" 8 | ) 9 | 10 | // GormPager adds pagination capability to your gorm queries. 11 | type GormPager interface { 12 | ToPaginate() func(db *gorm.DB) *gorm.DB 13 | } 14 | 15 | // GormPagination represent pagination data for pagination. 16 | type GormPagination struct { 17 | *utils.Pagination 18 | } 19 | 20 | // ToPaginate adds pagination query to your gorm queries. 21 | func (r *GormPagination) ToPaginate() func(db *gorm.DB) *gorm.DB { 22 | return func(db *gorm.DB) *gorm.DB { 23 | return db.Offset(helpers.OffsetCal(r.Pagination.GetPage(), r.Pagination.GetLimit())).Limit(r.Pagination.GetLimit()) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /repositories/userRepository.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | "gorm.io/gorm/clause" 6 | 7 | "github.com/Permify/go-role/collections" 8 | "github.com/Permify/go-role/models" 9 | "github.com/Permify/go-role/models/pivot" 10 | ) 11 | 12 | // IUserRepository its data access layer abstraction of user. 13 | type IUserRepository interface { 14 | // actions 15 | 16 | AddPermissions(userID uint, permissions collections.Permission) (err error) 17 | ReplacePermissions(userID uint, permissions collections.Permission) (err error) 18 | RemovePermissions(userID uint, permissions collections.Permission) (err error) 19 | ClearPermissions(userID uint) (err error) 20 | 21 | AddRoles(userID uint, roles collections.Role) (err error) 22 | ReplaceRoles(userID uint, roles collections.Role) (err error) 23 | RemoveRoles(userID uint, roles collections.Role) (err error) 24 | ClearRoles(userID uint) (err error) 25 | 26 | // controls 27 | 28 | HasRole(userID uint, role models.Role) (b bool, err error) 29 | HasAllRoles(userID uint, roles collections.Role) (b bool, err error) 30 | HasAnyRoles(userID uint, roles collections.Role) (b bool, err error) 31 | 32 | HasDirectPermission(userID uint, permission models.Permission) (b bool, err error) 33 | HasAllDirectPermissions(userID uint, permissions collections.Permission) (b bool, err error) 34 | HasAnyDirectPermissions(userID uint, permissions collections.Permission) (b bool, err error) 35 | } 36 | 37 | // UserRepository its data access layer of user. 38 | type UserRepository struct { 39 | Database *gorm.DB 40 | } 41 | 42 | // ACTIONS 43 | 44 | // AddPermissions add direct permissions to user. 45 | // @param uint 46 | // @param collections.Permission 47 | // @return error 48 | func (repository *UserRepository) AddPermissions(userID uint, permissions collections.Permission) error { 49 | var userPermissions []pivot.UserPermissions 50 | for _, permission := range permissions.Origin() { 51 | userPermissions = append(userPermissions, pivot.UserPermissions{ 52 | UserID: userID, 53 | PermissionID: permission.ID, 54 | }) 55 | } 56 | return repository.Database.Clauses(clause.OnConflict{DoNothing: true}).Create(&userPermissions).Error 57 | } 58 | 59 | // ReplacePermissions replace direct permissions of user. 60 | // @param uint 61 | // @param collections.Permission 62 | // @return error 63 | func (repository *UserRepository) ReplacePermissions(userID uint, permissions collections.Permission) error { 64 | return repository.Database.Transaction(func(tx *gorm.DB) error { 65 | if err := tx.Where("user_permissions.user_id = ?", userID).Delete(&pivot.UserPermissions{}).Error; err != nil { 66 | tx.Rollback() 67 | return err 68 | } 69 | 70 | var userPermissions []pivot.UserPermissions 71 | for _, permission := range permissions.Origin() { 72 | userPermissions = append(userPermissions, pivot.UserPermissions{ 73 | UserID: userID, 74 | PermissionID: permission.ID, 75 | }) 76 | } 77 | 78 | if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&userPermissions).Error; err != nil { 79 | tx.Rollback() 80 | return err 81 | } 82 | 83 | return nil 84 | }) 85 | } 86 | 87 | // RemovePermissions remove direct permissions of user. 88 | // @param uint 89 | // @param collections.Permission 90 | // @return error 91 | func (repository *UserRepository) RemovePermissions(userID uint, permissions collections.Permission) error { 92 | var userPermissions []pivot.UserPermissions 93 | for _, permission := range permissions.Origin() { 94 | userPermissions = append(userPermissions, pivot.UserPermissions{ 95 | UserID: userID, 96 | PermissionID: permission.ID, 97 | }) 98 | } 99 | return repository.Database.Delete(&userPermissions).Error 100 | } 101 | 102 | // ClearPermissions remove all direct permissions of user. 103 | // @param uint 104 | // @return error 105 | func (repository *UserRepository) ClearPermissions(userID uint) (err error) { 106 | return repository.Database.Where("user_permissions.user_id = ?", userID).Delete(&pivot.UserPermissions{}).Error 107 | } 108 | 109 | // AddRoles add roles to user. 110 | // @param uint 111 | // @param collections.Role 112 | // @return error 113 | func (repository *UserRepository) AddRoles(userID uint, roles collections.Role) error { 114 | var userRoles []pivot.UserRoles 115 | for _, role := range roles.Origin() { 116 | userRoles = append(userRoles, pivot.UserRoles{ 117 | UserID: userID, 118 | RoleID: role.ID, 119 | }) 120 | } 121 | return repository.Database.Clauses(clause.OnConflict{DoNothing: true}).Create(&userRoles).Error 122 | } 123 | 124 | // ReplaceRoles replace roles of user. 125 | // @param uint 126 | // @param collections.Role 127 | // @return error 128 | func (repository *UserRepository) ReplaceRoles(userID uint, roles collections.Role) error { 129 | return repository.Database.Transaction(func(tx *gorm.DB) error { 130 | if err := tx.Where("user_roles.user_id = ?", userID).Delete(&pivot.UserRoles{}).Error; err != nil { 131 | tx.Rollback() 132 | return err 133 | } 134 | var userRoles []pivot.UserRoles 135 | for _, role := range roles.Origin() { 136 | userRoles = append(userRoles, pivot.UserRoles{ 137 | UserID: userID, 138 | RoleID: role.ID, 139 | }) 140 | } 141 | if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&userRoles).Error; err != nil { 142 | tx.Rollback() 143 | return err 144 | } 145 | return nil 146 | }) 147 | } 148 | 149 | // RemoveRoles remove roles of user. 150 | // @param uint 151 | // @param collections.Role 152 | // @return error 153 | func (repository *UserRepository) RemoveRoles(userID uint, roles collections.Role) error { 154 | var userRoles []pivot.UserRoles 155 | for _, role := range roles.Origin() { 156 | userRoles = append(userRoles, pivot.UserRoles{ 157 | UserID: userID, 158 | RoleID: role.ID, 159 | }) 160 | } 161 | return repository.Database.Delete(&userRoles).Error 162 | } 163 | 164 | // ClearRoles remove all roles of user. 165 | // @param uint 166 | // @return error 167 | func (repository *UserRepository) ClearRoles(userID uint) (err error) { 168 | return repository.Database.Where("user_roles.user_id = ?", userID).Delete(&pivot.UserRoles{}).Error 169 | } 170 | 171 | // CONTROLS 172 | 173 | // HasRole does the user have the given role? 174 | // @param uint 175 | // @param models.Role 176 | // @return bool, error 177 | func (repository *UserRepository) HasRole(userID uint, role models.Role) (b bool, err error) { 178 | var count int64 179 | err = repository.Database.Table("user_roles").Where("user_roles.user_id = ?", userID).Where("user_roles.role_id = ?", role.ID).Count(&count).Error 180 | return count > 0, err 181 | } 182 | 183 | // HasAllRoles does the user have all the given roles? 184 | // @param uint 185 | // @param collections.Role 186 | // @return bool, error 187 | func (repository *UserRepository) HasAllRoles(userID uint, roles collections.Role) (b bool, err error) { 188 | var count int64 189 | err = repository.Database.Table("user_roles").Where("user_roles.user_id = ?", userID).Where("user_roles.role_id IN (?)", roles.IDs()).Count(&count).Error 190 | return roles.Len() == count, err 191 | } 192 | 193 | // HasAnyRoles does the user have any of the given roles? 194 | // @param uint 195 | // @param collections.Role 196 | // @return bool, error 197 | func (repository *UserRepository) HasAnyRoles(userID uint, roles collections.Role) (b bool, err error) { 198 | var count int64 199 | err = repository.Database.Table("user_roles").Where("user_roles.user_id = ?", userID).Where("user_roles.role_id IN (?)", roles.IDs()).Count(&count).Error 200 | return count > 0, err 201 | } 202 | 203 | // HasDirectPermission does the user have the given permission? (not including the permissions of the roles) 204 | // @param uint 205 | // @param collections.Permission 206 | // @return bool, error 207 | func (repository *UserRepository) HasDirectPermission(userID uint, permission models.Permission) (b bool, err error) { 208 | var count int64 209 | err = repository.Database.Table("user_permissions").Where("user_permissions.user_id = ?", userID).Where("user_permissions.permission_id = ?", permission.ID).Count(&count).Error 210 | return count > 0, err 211 | } 212 | 213 | // HasAllDirectPermissions does the user have all the given permissions? (not including the permissions of the roles) 214 | // @param uint 215 | // @param collections.Permission 216 | // @return bool, error 217 | func (repository *UserRepository) HasAllDirectPermissions(userID uint, permissions collections.Permission) (b bool, err error) { 218 | var count int64 219 | err = repository.Database.Table("user_permissions").Where("user_permissions.user_id = ?", userID).Where("user_permissions.permission_id IN (?)", permissions.IDs()).Count(&count).Error 220 | return permissions.Len() == count, err 221 | } 222 | 223 | // HasAnyDirectPermissions does the user have any of the given permissions? (not including the permissions of the roles) 224 | // @param uint 225 | // @param collections.Permission 226 | // @return bool, error 227 | func (repository *UserRepository) HasAnyDirectPermissions(userID uint, permissions collections.Permission) (b bool, err error) { 228 | var count int64 229 | err = repository.Database.Table("user_permissions").Where("user_permissions.user_id = ?", userID).Where("user_permissions.permission_id IN (?)", permissions.IDs()).Count(&count).Error 230 | return count > 0, err 231 | } 232 | -------------------------------------------------------------------------------- /repositories/userRepository_test.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "database/sql" 5 | "regexp" 6 | 7 | "github.com/DATA-DOG/go-sqlmock" 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | "gorm.io/driver/postgres" 11 | "gorm.io/gorm" 12 | 13 | "github.com/Permify/go-role/collections" 14 | "github.com/Permify/go-role/models" 15 | "github.com/Permify/go-role/models/pivot" 16 | ) 17 | 18 | var _ = Describe("User Repository", func() { 19 | var repository *UserRepository 20 | var mock sqlmock.Sqlmock 21 | 22 | BeforeEach(func() { 23 | var db *sql.DB 24 | var err error 25 | 26 | db, mock, err = sqlmock.New() 27 | Expect(err).ShouldNot(HaveOccurred()) 28 | 29 | var gormDb *gorm.DB 30 | dialector := postgres.New(postgres.Config{ 31 | DSN: "sqlmock_db_0", 32 | DriverName: "postgres", 33 | Conn: db, 34 | PreferSimpleProtocol: true, 35 | }) 36 | gormDb, err = gorm.Open(dialector, &gorm.Config{}) 37 | Expect(err).ShouldNot(HaveOccurred()) 38 | 39 | repository = &UserRepository{Database: gormDb} 40 | }) 41 | 42 | AfterEach(func() { 43 | err := mock.ExpectationsWereMet() 44 | Expect(err).ShouldNot(HaveOccurred()) 45 | }) 46 | 47 | Context("Has Role", func() { 48 | It("found", func() { 49 | userRoles := pivot.UserRoles{ 50 | UserID: 1, 51 | RoleID: 1, 52 | } 53 | 54 | const query = `SELECT count(*) FROM "user_roles" WHERE user_roles.user_id = $1 AND user_roles.role_id = $2` 55 | 56 | mock.ExpectQuery(regexp.QuoteMeta(query)). 57 | WithArgs(userRoles.UserID, userRoles.RoleID). 58 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 59 | AddRow(1)) 60 | 61 | value, err := repository.HasRole(1, models.Role{ID: 1}) 62 | Expect(err).ShouldNot(HaveOccurred()) 63 | Expect(value).Should(Equal(true)) 64 | }) 65 | 66 | It("not found", func() { 67 | const query = `SELECT count(*) FROM "user_roles" WHERE user_roles.user_id = $1 AND user_roles.role_id = $2` 68 | 69 | mock.ExpectQuery(regexp.QuoteMeta(query)). 70 | WithArgs(1, 1). 71 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 72 | AddRow(0)) 73 | 74 | value, err := repository.HasRole(1, models.Role{ID: 1}) 75 | Expect(err).ShouldNot(HaveOccurred()) 76 | Expect(value).Should(Equal(false)) 77 | }) 78 | }) 79 | 80 | Context("Has All Roles", func() { 81 | It("found", func() { 82 | userRoles1 := pivot.UserRoles{ 83 | UserID: 1, 84 | RoleID: 1, 85 | } 86 | 87 | userRoles2 := pivot.UserRoles{ 88 | UserID: 1, 89 | RoleID: 2, 90 | } 91 | 92 | const query = `SELECT count(*) FROM "user_roles" WHERE user_roles.user_id = $1 AND user_roles.role_id IN ($2,$3)` 93 | 94 | mock.ExpectQuery(regexp.QuoteMeta(query)). 95 | WithArgs(userRoles1.UserID, userRoles1.RoleID, userRoles2.RoleID). 96 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 97 | AddRow(2)) 98 | 99 | value, err := repository.HasAllRoles(uint(1), collections.Role([]models.Role{{ID: 1}, {ID: 2}})) 100 | Expect(err).ShouldNot(HaveOccurred()) 101 | Expect(value).Should(Equal(true)) 102 | }) 103 | 104 | It("not found", func() { 105 | userRoles1 := pivot.UserRoles{ 106 | UserID: 1, 107 | RoleID: 1, 108 | } 109 | 110 | userRoles2 := pivot.UserRoles{ 111 | UserID: 1, 112 | RoleID: 2, 113 | } 114 | 115 | const query = `SELECT count(*) FROM "user_roles" WHERE user_roles.user_id = $1 AND user_roles.role_id IN ($2,$3)` 116 | 117 | mock.ExpectQuery(regexp.QuoteMeta(query)). 118 | WithArgs(userRoles1.UserID, userRoles1.RoleID, userRoles2.RoleID). 119 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 120 | AddRow(1)) 121 | 122 | value, err := repository.HasAllRoles(uint(1), collections.Role([]models.Role{{ID: 1}, {ID: 2}})) 123 | Expect(err).ShouldNot(HaveOccurred()) 124 | Expect(value).Should(Equal(false)) 125 | }) 126 | }) 127 | 128 | Context("Has Any Roles", func() { 129 | It("found", func() { 130 | userRoles1 := pivot.UserRoles{ 131 | UserID: 1, 132 | RoleID: 1, 133 | } 134 | 135 | const query = `SELECT count(*) FROM "user_roles" WHERE user_roles.user_id = $1 AND user_roles.role_id IN ($2,$3)` 136 | 137 | mock.ExpectQuery(regexp.QuoteMeta(query)). 138 | WithArgs(userRoles1.UserID, userRoles1.RoleID, 2). 139 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 140 | AddRow(1)) 141 | 142 | value, err := repository.HasAnyRoles(uint(1), collections.Role([]models.Role{{ID: 1}, {ID: 2}})) 143 | Expect(err).ShouldNot(HaveOccurred()) 144 | Expect(value).Should(Equal(true)) 145 | }) 146 | 147 | It("not found", func() { 148 | const query = `SELECT count(*) FROM "user_roles" WHERE user_roles.user_id = $1 AND user_roles.role_id IN ($2,$3)` 149 | 150 | mock.ExpectQuery(regexp.QuoteMeta(query)). 151 | WithArgs(1, 1, 2). 152 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 153 | AddRow(0)) 154 | 155 | value, err := repository.HasAllRoles(uint(1), collections.Role([]models.Role{{ID: 1}, {ID: 2}})) 156 | Expect(err).ShouldNot(HaveOccurred()) 157 | Expect(value).Should(Equal(false)) 158 | }) 159 | }) 160 | 161 | Context("Has Direct Permission", func() { 162 | It("found", func() { 163 | userPermissions := pivot.UserPermissions{ 164 | UserID: 1, 165 | PermissionID: 1, 166 | } 167 | 168 | const query = `SELECT count(*) FROM "user_permissions" WHERE user_permissions.user_id = $1 AND user_permissions.permission_id = $2` 169 | 170 | mock.ExpectQuery(regexp.QuoteMeta(query)). 171 | WithArgs(userPermissions.UserID, userPermissions.PermissionID). 172 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 173 | AddRow(1)) 174 | 175 | value, err := repository.HasDirectPermission(1, models.Permission{ID: 1}) 176 | Expect(err).ShouldNot(HaveOccurred()) 177 | Expect(value).Should(Equal(true)) 178 | }) 179 | 180 | It("not found", func() { 181 | const query = `SELECT count(*) FROM "user_permissions" WHERE user_permissions.user_id = $1 AND user_permissions.permission_id = $2` 182 | 183 | mock.ExpectQuery(regexp.QuoteMeta(query)). 184 | WithArgs(1, 1). 185 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 186 | AddRow(0)) 187 | 188 | value, err := repository.HasDirectPermission(1, models.Permission{ID: 1}) 189 | Expect(err).ShouldNot(HaveOccurred()) 190 | Expect(value).Should(Equal(false)) 191 | }) 192 | }) 193 | 194 | Context("Has All Direct Permissions", func() { 195 | It("found", func() { 196 | userPermissions1 := pivot.UserPermissions{ 197 | UserID: 1, 198 | PermissionID: 1, 199 | } 200 | 201 | userPermissions2 := pivot.UserPermissions{ 202 | UserID: 1, 203 | PermissionID: 2, 204 | } 205 | 206 | const query = `SELECT count(*) FROM "user_permissions" WHERE user_permissions.user_id = $1 AND user_permissions.permission_id IN ($2,$3)` 207 | 208 | mock.ExpectQuery(regexp.QuoteMeta(query)). 209 | WithArgs(userPermissions1.UserID, userPermissions1.PermissionID, userPermissions2.PermissionID). 210 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 211 | AddRow(2)) 212 | 213 | value, err := repository.HasAllDirectPermissions(uint(1), collections.Permission([]models.Permission{{ID: 1}, {ID: 2}})) 214 | Expect(err).ShouldNot(HaveOccurred()) 215 | Expect(value).Should(Equal(true)) 216 | }) 217 | 218 | It("not found", func() { 219 | userPermissions1 := pivot.UserPermissions{ 220 | UserID: 1, 221 | PermissionID: 1, 222 | } 223 | 224 | userPermissions2 := pivot.UserPermissions{ 225 | UserID: 1, 226 | PermissionID: 2, 227 | } 228 | 229 | const query = `SELECT count(*) FROM "user_permissions" WHERE user_permissions.user_id = $1 AND user_permissions.permission_id IN ($2,$3)` 230 | 231 | mock.ExpectQuery(regexp.QuoteMeta(query)). 232 | WithArgs(userPermissions1.UserID, userPermissions1.PermissionID, userPermissions2.PermissionID). 233 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 234 | AddRow(1)) 235 | 236 | value, err := repository.HasAllDirectPermissions(uint(1), collections.Permission([]models.Permission{{ID: 1}, {ID: 2}})) 237 | Expect(err).ShouldNot(HaveOccurred()) 238 | Expect(value).Should(Equal(false)) 239 | }) 240 | }) 241 | 242 | Context("Has Any Direct Permissions", func() { 243 | It("found", func() { 244 | userPermissions := pivot.UserPermissions{ 245 | UserID: 1, 246 | PermissionID: 1, 247 | } 248 | 249 | const query = `SELECT count(*) FROM "user_permissions" WHERE user_permissions.user_id = $1 AND user_permissions.permission_id IN ($2,$3)` 250 | 251 | mock.ExpectQuery(regexp.QuoteMeta(query)). 252 | WithArgs(userPermissions.UserID, userPermissions.PermissionID, 2). 253 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 254 | AddRow(1)) 255 | 256 | value, err := repository.HasAnyDirectPermissions(uint(1), collections.Permission([]models.Permission{{ID: 1}, {ID: 2}})) 257 | Expect(err).ShouldNot(HaveOccurred()) 258 | Expect(value).Should(Equal(true)) 259 | }) 260 | 261 | It("not found", func() { 262 | const query = `SELECT count(*) FROM "user_permissions" WHERE user_permissions.user_id = $1 AND user_permissions.permission_id IN ($2,$3)` 263 | 264 | mock.ExpectQuery(regexp.QuoteMeta(query)). 265 | WithArgs(1, 1, 2). 266 | WillReturnRows(sqlmock.NewRows([]string{"count"}). 267 | AddRow(0)) 268 | 269 | value, err := repository.HasAnyDirectPermissions(uint(1), collections.Permission([]models.Permission{{ID: 1}, {ID: 2}})) 270 | Expect(err).ShouldNot(HaveOccurred()) 271 | Expect(value).Should(Equal(false)) 272 | }) 273 | }) 274 | }) 275 | -------------------------------------------------------------------------------- /utils/pagination.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | // IPagination abstraction for your pagination data getters. 4 | type IPagination interface { 5 | Get() *Pagination 6 | GetPage() int 7 | GetLimit() int 8 | } 9 | 10 | // Pagination pagination data. 11 | type Pagination struct { 12 | Page int 13 | Limit int 14 | } 15 | 16 | // Get get pagination struct. 17 | func (p *Pagination) Get() *Pagination { 18 | return p 19 | } 20 | 21 | // GetPage get page value from pagination struct. 22 | func (p *Pagination) GetPage() int { 23 | if p.Page <= 0 { 24 | p.Page = 1 25 | } 26 | return p.Page 27 | } 28 | 29 | // GetLimit get limit value from pagination struct. 30 | func (p *Pagination) GetLimit() int { 31 | if p.Limit <= 0 { 32 | p.Limit = 20 33 | } 34 | return p.Limit 35 | } 36 | --------------------------------------------------------------------------------