User view (#94)

* fix: some funcitons

* feat(eventstore): implemented push events

* fix: move project eventstore to project package

* fix: change project eventstore funcs

* feat(eventstore): overwrite context data

* fix: change project eventstore

* fix: add project repo to mgmt server

* feat(types): SQL-config

* fix: commented code

* feat(eventstore): options to overwrite editor

* feat: auth interceptor and cockroach migrations

* fix: migrations

* fix: fix filter

* fix: not found on getbyid

* fix: use global sql config

* fix: add sequence

* fix: add some tests

* fix(eventstore): nullable sequence

* fix: add some tests

* merge

* fix: add some tests

* fix(migrations): correct statements for sequence

* fix: add some tests

* fix: add some tests

* fix: changes from mr

* fix: changes from mr

* fix: add some tests

* Update internal/eventstore/models/field.go

Co-Authored-By: livio-a <livio.a@gmail.com>

* fix(eventstore): code quality

* fix: add types to aggregate/Event-types

* fix: try tests

* fix(eventstore): rename modifier* to editor*

* fix(eventstore): delete editor_org

* fix(migrations): remove editor_org field,
rename modifier_* to editor_*

* fix: query tests

* fix: use prepare funcs

* fix: go mod

* fix: generate files

* fix(eventstore): tests

* fix(eventstore): rename modifier to editor

* fix(migrations): add cluster migration,
fix(migrations): fix typo of host in clean clsuter

* fix(eventstore): move health

* fix(eventstore): AggregateTypeFilter aggregateType as param

* code quality

* fix: go tests

* feat: add member funcs

* feat: add member model

* feat: add member events

* feat: add member repo model

* fix: better error func testing

* fix: project member funcs

* fix: add tests

* fix: add tests

* feat: implement member requests

* fix: merge master

* fix: merge master

* fix: read existing in project repo

* fix: fix tests

* feat: add internal cache

* feat: add cache mock

* fix: return values of cache mock

* feat: add project role

* fix: add cache config

* fix: add role to eventstore

* fix: use eventstore sdk

* fix: use eventstore sdk

* fix: add project role grpc requests

* fix: fix getby id

* fix: changes for mr

* fix: change value to interface

* feat: add app event creations

* fix: searchmethods

* Update internal/project/model/project_member.go

Co-Authored-By: Silvan <silvan.reusser@gmail.com>

* fix: use get project func

* fix: append events

* fix: check if value is string on equal ignore case

* fix: add changes test

* fix: add go mod

* fix: add some tests

* fix: return err not nil

* fix: return err not nil

* fix: add aggregate funcs and tests

* fix: add oidc aggregate funcs and tests

* fix: add oidc

* fix: add some tests

* fix: tests

* fix: oidc validation

* fix: generate client secret

* fix: generate client id

* fix: test change app

* fix: deactivate/reactivate application

* fix: change oidc config

* fix: change oidc config secret

* fix: implement grpc app funcs

* fix: add application requests

* fix: converter

* fix: converter

* fix: converter and generate clientid

* fix: tests

* feat: project grant aggregate

* feat: project grant

* fix: project grant check if role existing

* fix: project grant requests

* fix: project grant fixes

* fix: project grant member model

* fix: project grant member aggregate

* fix: project grant member eventstore

* fix: project grant member requests

* feat: user model

* feat: user command side

* user command side

* profile requests

* local config with gopass and more

* init for views (spooler, handler)

* init for views (spooler, handler)

* start view in management

* granted project

* Update internal/user/model/user.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/address.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/address.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/email.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/email.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/email.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/mfa.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/mfa.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/password.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/password.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/password.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/phone.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/phone.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/phone.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/user.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/user.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/user.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/usergrant/repository/eventsourcing/model/user_grant.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/usergrant/repository/eventsourcing/model/user_grant.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/usergrant/repository/eventsourcing/user_grant.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/user_test.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/eventstore_mock_test.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* changes from mr review

* save files into basedir

* changes from mr review

* changes from mr review

* implement granted project view

* Update internal/usergrant/repository/eventsourcing/cache.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update internal/usergrant/repository/eventsourcing/cache.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* changes requested on mr

* fix generate codes

* fix return if no events

* password code

* search granted projects

* fix search column

* update all projects on project change

* search roles

* filter org

* project members

* project grant members

* fix tests

* application view

* project grant search

* mock

* Update internal/user/repository/eventsourcing/model/password.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update internal/user/repository/eventsourcing/model/user.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* requests of mr

* check email

* test appendevents

* test appendevents

* Update internal/view/query.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update internal/eventstore/spooler/spooler.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update internal/view/query.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* merge request changes

* Update internal/project/repository/view/model/application.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* merge request changes

* Project view sql (#92)

* sql and configs

* error handling

* sql start in eventstore

* on error handling, config

* merge branches

* user view

* user grant view

* fix test

* user grant search

* fill data on user grant

* update data on user grant

* return caos errors

* converter list len

* merge master

* Update internal/management/repository/eventsourcing/handler/user_grant.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update internal/usergrant/repository/view/model/user_grant_query.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* typo

* Update internal/user/repository/view/model/user_query.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update internal/user/repository/view/user_view.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update pkg/management/api/grpc/user_converter.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update pkg/management/api/grpc/user_grant_converter.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* set my org query

Co-authored-by: adlerhurst <silvan.reusser@gmail.com>
Co-authored-by: livio-a <livio.a@gmail.com>
This commit is contained in:
Fabi
2020-05-12 06:30:53 +02:00
committed by GitHub
parent 6e105f662e
commit 5cbf537a91
40 changed files with 6135 additions and 3743 deletions

View File

@@ -0,0 +1,69 @@
package model
import (
"github.com/caos/zitadel/internal/model"
"time"
)
type UserGrantView struct {
ID string
ResourceOwner string
UserID string
ProjectID string
UserName string
FirstName string
LastName string
Email string
ProjectName string
OrgName string
OrgDomain string
RoleKeys []string
CreationDate time.Time
ChangeDate time.Time
State UserGrantState
Sequence uint64
}
type UserGrantSearchRequest struct {
Offset uint64
Limit uint64
SortingColumn UserGrantSearchKey
Asc bool
Queries []*UserGrantSearchQuery
}
type UserGrantSearchKey int32
const (
USERGRANTSEARCHKEY_UNSPECIFIED UserGrantSearchKey = iota
USERGRANTSEARCHKEY_USER_ID
USERGRANTSEARCHKEY_PROJECT_ID
USERGRANTSEARCHKEY_RESOURCEOWNER
USERGRANTSEARCHKEY_STATE
USERGRANTSEARCHKEY_GRANT_ID
)
type UserGrantSearchQuery struct {
Key UserGrantSearchKey
Method model.SearchMethod
Value string
}
type UserGrantSearchResponse struct {
Offset uint64
Limit uint64
TotalResult uint64
Result []*UserGrantView
}
func (r *UserGrantSearchRequest) EnsureLimit(limit uint64) {
if r.Limit == 0 || r.Limit > limit {
r.Limit = limit
}
}
func (r *UserGrantSearchRequest) AppendMyOrgQuery(orgID string) {
r.Queries = append(r.Queries, &UserGrantSearchQuery{Key: USERGRANTSEARCHKEY_RESOURCEOWNER, Method: model.SEARCHMETHOD_EQUALS, Value: orgID})
}

View File

@@ -0,0 +1,123 @@
package model
import (
"encoding/json"
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/usergrant/model"
es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
"github.com/lib/pq"
"time"
)
const (
UserGrantKeyID = "id"
UserGrantKeyUserID = "user_id"
UserGrantKeyProjectID = "project_id"
UserGrantKeyResourceOwner = "resource_owner"
UserGrantKeyState = "state"
)
type UserGrantView struct {
ID string `json:"-" gorm:"column:id;primary_key"`
ResourceOwner string `json:"-" gorm:"resource_owner"`
UserID string `json:"userId" gorm:"user_id"`
ProjectID string `json:"projectId" gorm:"column:project_id"`
UserName string `json:"-" gorm:"column:user_name"`
FirstName string `json:"-" gorm:"column:first_name"`
LastName string `json:"-" gorm:"column:last_name"`
Email string `json:"-" gorm:"column:email"`
ProjectName string `json:"-" gorm:"column:project_name"`
OrgName string `json:"-" gorm:"column:org_name"`
OrgDomain string `json:"-" gorm:"column:org_domain"`
RoleKeys pq.StringArray `json:"roleKeys" gorm:"column:role_keys"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
State int32 `json:"-" gorm:"column:grant_state"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
}
func UserGrantFromModel(grant *model.UserGrantView) *UserGrantView {
return &UserGrantView{
ID: grant.ID,
ResourceOwner: grant.ResourceOwner,
UserID: grant.UserID,
ProjectID: grant.ProjectID,
ChangeDate: grant.ChangeDate,
CreationDate: grant.CreationDate,
State: int32(grant.State),
UserName: grant.UserName,
FirstName: grant.FirstName,
LastName: grant.LastName,
Email: grant.Email,
ProjectName: grant.ProjectName,
OrgName: grant.OrgName,
OrgDomain: grant.OrgDomain,
RoleKeys: grant.RoleKeys,
Sequence: grant.Sequence,
}
}
func UserGrantToModel(grant *UserGrantView) *model.UserGrantView {
return &model.UserGrantView{
ID: grant.ID,
ResourceOwner: grant.ResourceOwner,
UserID: grant.UserID,
ProjectID: grant.ProjectID,
ChangeDate: grant.ChangeDate,
CreationDate: grant.CreationDate,
State: model.UserGrantState(grant.State),
UserName: grant.UserName,
FirstName: grant.FirstName,
LastName: grant.LastName,
Email: grant.Email,
ProjectName: grant.ProjectName,
OrgName: grant.OrgName,
OrgDomain: grant.OrgDomain,
RoleKeys: grant.RoleKeys,
Sequence: grant.Sequence,
}
}
func UserGrantsToModel(grants []*UserGrantView) []*model.UserGrantView {
result := make([]*model.UserGrantView, len(grants))
for i, g := range grants {
result[i] = UserGrantToModel(g)
}
return result
}
func (g *UserGrantView) AppendEvent(event *models.Event) (err error) {
g.ChangeDate = event.CreationDate
g.Sequence = event.Sequence
switch event.Type {
case es_model.UserGrantAdded:
g.State = int32(model.USERGRANTSTATE_ACTIVE)
g.CreationDate = event.CreationDate
g.setRootData(event)
err = g.setData(event)
case es_model.UserGrantChanged:
err = g.setData(event)
case es_model.UserGrantDeactivated:
g.State = int32(model.USERGRANTSTATE_INACTIVE)
case es_model.UserGrantReactivated:
g.State = int32(model.USERGRANTSTATE_ACTIVE)
}
return err
}
func (u *UserGrantView) setRootData(event *models.Event) {
u.ID = event.AggregateID
u.ResourceOwner = event.ResourceOwner
}
func (u *UserGrantView) setData(event *models.Event) error {
if err := json.Unmarshal(event.Data, u); err != nil {
logging.Log("EVEN-l9sw4").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(nil, "MODEL-7xhke", "could not unmarshal data")
}
return nil
}

View File

@@ -0,0 +1,67 @@
package model
import (
global_model "github.com/caos/zitadel/internal/model"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
"github.com/caos/zitadel/internal/view"
)
type UserGrantSearchRequest grant_model.UserGrantSearchRequest
type UserGrantSearchQuery grant_model.UserGrantSearchQuery
type UserGrantSearchKey grant_model.UserGrantSearchKey
func (req UserGrantSearchRequest) GetLimit() uint64 {
return req.Limit
}
func (req UserGrantSearchRequest) GetOffset() uint64 {
return req.Offset
}
func (req UserGrantSearchRequest) GetSortingColumn() view.ColumnKey {
if req.SortingColumn == grant_model.USERGRANTSEARCHKEY_UNSPECIFIED {
return nil
}
return UserGrantSearchKey(req.SortingColumn)
}
func (req UserGrantSearchRequest) GetAsc() bool {
return req.Asc
}
func (req UserGrantSearchRequest) GetQueries() []view.SearchQuery {
result := make([]view.SearchQuery, len(req.Queries))
for i, q := range req.Queries {
result[i] = UserGrantSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
}
return result
}
func (req UserGrantSearchQuery) GetKey() view.ColumnKey {
return UserGrantSearchKey(req.Key)
}
func (req UserGrantSearchQuery) GetMethod() global_model.SearchMethod {
return req.Method
}
func (req UserGrantSearchQuery) GetValue() interface{} {
return req.Value
}
func (key UserGrantSearchKey) ToColumnName() string {
switch grant_model.UserGrantSearchKey(key) {
case grant_model.USERGRANTSEARCHKEY_USER_ID:
return UserGrantKeyUserID
case grant_model.USERGRANTSEARCHKEY_PROJECT_ID:
return UserGrantKeyProjectID
case grant_model.USERGRANTSEARCHKEY_STATE:
return UserGrantKeyState
case grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER:
return UserGrantKeyResourceOwner
case grant_model.USERGRANTSEARCHKEY_GRANT_ID:
return UserGrantKeyID
default:
return ""
}
}

View File

@@ -0,0 +1,81 @@
package model
import (
"encoding/json"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/usergrant/model"
es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
"github.com/lib/pq"
"reflect"
"testing"
)
func mockUserGrantData(grant *es_model.UserGrant) []byte {
data, _ := json.Marshal(grant)
return data
}
func TestUserAppendEvent(t *testing.T) {
type args struct {
event *es_models.Event
grant *UserGrantView
}
tests := []struct {
name string
args args
result *UserGrantView
}{
{
name: "append added grant event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserGrantAdded, ResourceOwner: "OrgID", Data: mockUserGrantData(&es_model.UserGrant{UserID: "UserID", ProjectID: "ProjectID", RoleKeys: pq.StringArray{"Keys"}})},
grant: &UserGrantView{},
},
result: &UserGrantView{ID: "AggregateID", ResourceOwner: "OrgID", UserID: "UserID", ProjectID: "ProjectID", RoleKeys: pq.StringArray{"Keys"}, State: int32(model.USERGRANTSTATE_ACTIVE)},
},
{
name: "append change grant profile event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserGrantChanged, ResourceOwner: "OrgID", Data: mockUserGrantData(&es_model.UserGrant{RoleKeys: pq.StringArray{"KeysChanged"}})},
grant: &UserGrantView{ID: "AggregateID", ResourceOwner: "OrgID", UserID: "UserID", ProjectID: "ProjectID", RoleKeys: pq.StringArray{"Keys"}, State: int32(model.USERGRANTSTATE_ACTIVE)},
},
result: &UserGrantView{ID: "AggregateID", ResourceOwner: "OrgID", UserID: "UserID", ProjectID: "ProjectID", RoleKeys: pq.StringArray{"KeysChanged"}, State: int32(model.USERGRANTSTATE_ACTIVE)},
},
{
name: "append grant deactivate event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserGrantDeactivated, ResourceOwner: "OrgID"},
grant: &UserGrantView{ID: "AggregateID", ResourceOwner: "OrgID", UserID: "UserID", ProjectID: "ProjectID", RoleKeys: pq.StringArray{"Keys"}, State: int32(model.USERGRANTSTATE_ACTIVE)},
},
result: &UserGrantView{ID: "AggregateID", ResourceOwner: "OrgID", UserID: "UserID", ProjectID: "ProjectID", RoleKeys: pq.StringArray{"Keys"}, State: int32(model.USERGRANTSTATE_INACTIVE)},
},
{
name: "append grant reactivate event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserGrantReactivated, ResourceOwner: "OrgID"},
grant: &UserGrantView{ID: "AggregateID", ResourceOwner: "OrgID", UserID: "UserID", ProjectID: "ProjectID", RoleKeys: pq.StringArray{"Keys"}, State: int32(model.USERGRANTSTATE_INACTIVE)},
},
result: &UserGrantView{ID: "AggregateID", ResourceOwner: "OrgID", UserID: "UserID", ProjectID: "ProjectID", RoleKeys: pq.StringArray{"Keys"}, State: int32(model.USERGRANTSTATE_ACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.grant.AppendEvent(tt.args.event)
if tt.args.grant.ID != tt.result.ID {
t.Errorf("got wrong result ID: expected: %v, actual: %v ", tt.result.ID, tt.args.grant.ID)
}
if tt.args.grant.ResourceOwner != tt.result.ResourceOwner {
t.Errorf("got wrong result ResourceOwner: expected: %v, actual: %v ", tt.result.ResourceOwner, tt.args.grant.ResourceOwner)
}
if tt.args.grant.UserID != tt.result.UserID {
t.Errorf("got wrong result UserID: expected: %v, actual: %v ", tt.result.UserID, tt.args.grant.UserID)
}
if tt.args.grant.ProjectID != tt.result.ProjectID {
t.Errorf("got wrong result ProjectID: expected: %v, actual: %v ", tt.result.ProjectID, tt.args.grant.ProjectID)
}
if !reflect.DeepEqual(tt.args.grant.RoleKeys, tt.result.RoleKeys) {
t.Errorf("got wrong result RoleKeys: expected: %v, actual: %v ", tt.result.RoleKeys, tt.args.grant.RoleKeys)
}
})
}
}

View File

@@ -0,0 +1,75 @@
package view
import (
global_model "github.com/caos/zitadel/internal/model"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
"github.com/caos/zitadel/internal/view"
"github.com/jinzhu/gorm"
)
func UserGrantByID(db *gorm.DB, table, grantID string) (*model.UserGrantView, error) {
user := new(model.UserGrantView)
query := view.PrepareGetByKey(table, model.UserGrantSearchKey(grant_model.USERGRANTSEARCHKEY_GRANT_ID), grantID)
err := query(db, user)
return user, err
}
func SearchUserGrants(db *gorm.DB, table string, req *grant_model.UserGrantSearchRequest) ([]*model.UserGrantView, int, error) {
users := make([]*model.UserGrantView, 0)
query := view.PrepareSearchQuery(table, model.UserGrantSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
count, err := query(db, &users)
if err != nil {
return nil, 0, err
}
return users, count, nil
}
func UserGrantsByUserID(db *gorm.DB, table, userID string) ([]*model.UserGrantView, error) {
users := make([]*model.UserGrantView, 0)
queries := []*grant_model.UserGrantSearchQuery{
&grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_USER_ID, Value: userID, Method: global_model.SEARCHMETHOD_EQUALS},
}
query := view.PrepareSearchQuery(table, model.UserGrantSearchRequest{Queries: queries})
_, err := query(db, &users)
if err != nil {
return nil, err
}
return users, nil
}
func UserGrantsByProjectID(db *gorm.DB, table, projectID string) ([]*model.UserGrantView, error) {
users := make([]*model.UserGrantView, 0)
queries := []*grant_model.UserGrantSearchQuery{
&grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_PROJECT_ID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS},
}
query := view.PrepareSearchQuery(table, model.UserGrantSearchRequest{Queries: queries})
_, err := query(db, &users)
if err != nil {
return nil, err
}
return users, nil
}
func UserGrantsByOrgID(db *gorm.DB, table, orgID string) ([]*model.UserGrantView, error) {
users := make([]*model.UserGrantView, 0)
queries := []*grant_model.UserGrantSearchQuery{
&grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER, Value: orgID, Method: global_model.SEARCHMETHOD_EQUALS},
}
query := view.PrepareSearchQuery(table, model.UserGrantSearchRequest{Queries: queries})
_, err := query(db, &users)
if err != nil {
return nil, err
}
return users, nil
}
func PutUserGrant(db *gorm.DB, table string, grant *model.UserGrantView) error {
save := view.PrepareSave(table)
return save(db, grant)
}
func DeleteUserGrant(db *gorm.DB, table, grantID string) error {
delete := view.PrepareDeleteByKey(table, model.UserGrantSearchKey(grant_model.USERGRANTSEARCHKEY_GRANT_ID), grantID)
return delete(db)
}