├── .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 | 
4 |
5 |
6 | [](https://pkg.go.dev/github.com/Permify/go-role)
7 | [](https://goreportcard.com/report/github.com/Permify/go-role)
8 | 
9 | 
10 | [](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 | [](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 |
433 |
434 |
435 |
436 |
437 |
438 |
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 | 
3 |
4 | [](https://goreportcard.com/report/github.com/Permify/permify-gorm)
5 | 
6 | 
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 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 | [comment]: <> ()
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 |
--------------------------------------------------------------------------------