feat: update user access (#151)
* feat: update user access * revoked timestamp field updated * updates * updates * updates
This commit is contained in:
parent
1f3dec6ea6
commit
b2541c8e9a
|
@ -53,3 +53,19 @@ export const InviteMembers = `
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const RevokeAccess = `
|
||||||
|
mutation revokeAccess($param: UpdateAccessInput!) {
|
||||||
|
_revoke_access(param: $param) {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const EnableAccess = `
|
||||||
|
mutation revokeAccess($param: UpdateAccessInput!) {
|
||||||
|
_enable_access(param: $param) {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
|
@ -81,6 +81,7 @@ export const UserDetailsQuery = `
|
||||||
signup_methods
|
signup_methods
|
||||||
roles
|
roles
|
||||||
created_at
|
created_at
|
||||||
|
revoked_timestamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ import {
|
||||||
FaAngleDown,
|
FaAngleDown,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import { EmailVerificationQuery, UserDetailsQuery } from '../graphql/queries';
|
import { EmailVerificationQuery, UserDetailsQuery } from '../graphql/queries';
|
||||||
import { UpdateUser } from '../graphql/mutation';
|
import { EnableAccess, RevokeAccess, UpdateUser } from '../graphql/mutation';
|
||||||
import EditUserModal from '../components/EditUserModal';
|
import EditUserModal from '../components/EditUserModal';
|
||||||
import DeleteUserModal from '../components/DeleteUserModal';
|
import DeleteUserModal from '../components/DeleteUserModal';
|
||||||
import InviteMembersModal from '../components/InviteMembersModal';
|
import InviteMembersModal from '../components/InviteMembersModal';
|
||||||
|
@ -67,6 +67,12 @@ interface userDataTypes {
|
||||||
signup_methods: string;
|
signup_methods: string;
|
||||||
roles: [string];
|
roles: [string];
|
||||||
created_at: number;
|
created_at: number;
|
||||||
|
revoked_timestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum updateAccessActions {
|
||||||
|
REVOKE = 'REVOKE',
|
||||||
|
ENABLE = 'ENABLE',
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMaxPages = (pagination: paginationPropTypes) => {
|
const getMaxPages = (pagination: paginationPropTypes) => {
|
||||||
|
@ -185,6 +191,66 @@ export default function Users() {
|
||||||
updateUserList();
|
updateUserList();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateAccessHandler = async (
|
||||||
|
id: string,
|
||||||
|
action: updateAccessActions
|
||||||
|
) => {
|
||||||
|
switch (action) {
|
||||||
|
case updateAccessActions.ENABLE:
|
||||||
|
const enableAccessRes = await client
|
||||||
|
.mutation(EnableAccess, {
|
||||||
|
param: {
|
||||||
|
user_id: id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.toPromise();
|
||||||
|
if (enableAccessRes.error) {
|
||||||
|
toast({
|
||||||
|
title: 'User access enable failed',
|
||||||
|
isClosable: true,
|
||||||
|
status: 'error',
|
||||||
|
position: 'bottom-right',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: 'User access enabled successfully',
|
||||||
|
isClosable: true,
|
||||||
|
status: 'success',
|
||||||
|
position: 'bottom-right',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
updateUserList();
|
||||||
|
break;
|
||||||
|
case updateAccessActions.REVOKE:
|
||||||
|
const revokeAccessRes = await client
|
||||||
|
.mutation(RevokeAccess, {
|
||||||
|
param: {
|
||||||
|
user_id: id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.toPromise();
|
||||||
|
if (revokeAccessRes.error) {
|
||||||
|
toast({
|
||||||
|
title: 'User access revoke failed',
|
||||||
|
isClosable: true,
|
||||||
|
status: 'error',
|
||||||
|
position: 'bottom-right',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: 'User access revoked successfully',
|
||||||
|
isClosable: true,
|
||||||
|
status: 'success',
|
||||||
|
position: 'bottom-right',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
updateUserList();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box m="5" py="5" px="10" bg="white" rounded="md">
|
<Box m="5" py="5" px="10" bg="white" rounded="md">
|
||||||
<Flex margin="2% 0" justifyContent="space-between" alignItems="center">
|
<Flex margin="2% 0" justifyContent="space-between" alignItems="center">
|
||||||
|
@ -206,6 +272,7 @@ export default function Users() {
|
||||||
<Th>Signup Methods</Th>
|
<Th>Signup Methods</Th>
|
||||||
<Th>Roles</Th>
|
<Th>Roles</Th>
|
||||||
<Th>Verified</Th>
|
<Th>Verified</Th>
|
||||||
|
<Th>Access</Th>
|
||||||
<Th>Actions</Th>
|
<Th>Actions</Th>
|
||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
|
@ -214,7 +281,7 @@ export default function Users() {
|
||||||
const { email_verified, created_at, ...rest }: any = user;
|
const { email_verified, created_at, ...rest }: any = user;
|
||||||
return (
|
return (
|
||||||
<Tr key={user.id} style={{ fontSize: 14 }}>
|
<Tr key={user.id} style={{ fontSize: 14 }}>
|
||||||
<Td>{user.email}</Td>
|
<Td maxW="300">{user.email}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
{dayjs(user.created_at * 1000).format('MMM DD, YYYY')}
|
{dayjs(user.created_at * 1000).format('MMM DD, YYYY')}
|
||||||
</Td>
|
</Td>
|
||||||
|
@ -229,6 +296,15 @@ export default function Users() {
|
||||||
{user.email_verified.toString()}
|
{user.email_verified.toString()}
|
||||||
</Tag>
|
</Tag>
|
||||||
</Td>
|
</Td>
|
||||||
|
<Td>
|
||||||
|
<Tag
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
colorScheme={user.revoked_timestamp ? 'red' : 'green'}
|
||||||
|
>
|
||||||
|
{user.revoked_timestamp ? 'Revoked' : 'Enabled'}
|
||||||
|
</Tag>
|
||||||
|
</Td>
|
||||||
<Td>
|
<Td>
|
||||||
<Menu>
|
<Menu>
|
||||||
<MenuButton as={Button} variant="unstyled" size="sm">
|
<MenuButton as={Button} variant="unstyled" size="sm">
|
||||||
|
@ -258,6 +334,29 @@ export default function Users() {
|
||||||
user={rest}
|
user={rest}
|
||||||
updateUserList={updateUserList}
|
updateUserList={updateUserList}
|
||||||
/>
|
/>
|
||||||
|
{user.revoked_timestamp ? (
|
||||||
|
<MenuItem
|
||||||
|
onClick={() =>
|
||||||
|
updateAccessHandler(
|
||||||
|
user.id,
|
||||||
|
updateAccessActions.ENABLE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Enable Access
|
||||||
|
</MenuItem>
|
||||||
|
) : (
|
||||||
|
<MenuItem
|
||||||
|
onClick={() =>
|
||||||
|
updateAccessHandler(
|
||||||
|
user.id,
|
||||||
|
updateAccessActions.REVOKE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Revoke Access
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
</MenuList>
|
</MenuList>
|
||||||
</Menu>
|
</Menu>
|
||||||
</Td>
|
</Td>
|
||||||
|
|
|
@ -27,6 +27,7 @@ type User struct {
|
||||||
Roles string `json:"roles" bson:"roles"`
|
Roles string `json:"roles" bson:"roles"`
|
||||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at"`
|
UpdatedAt int64 `json:"updated_at" bson:"updated_at"`
|
||||||
CreatedAt int64 `json:"created_at" bson:"created_at"`
|
CreatedAt int64 `json:"created_at" bson:"created_at"`
|
||||||
|
RevokedTimestamp *int64 `json:"revoked_timestamp" bson:"revoked_timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) AsAPIUser() *model.User {
|
func (user *User) AsAPIUser() *model.User {
|
||||||
|
@ -35,6 +36,7 @@ func (user *User) AsAPIUser() *model.User {
|
||||||
email := user.Email
|
email := user.Email
|
||||||
createdAt := user.CreatedAt
|
createdAt := user.CreatedAt
|
||||||
updatedAt := user.UpdatedAt
|
updatedAt := user.UpdatedAt
|
||||||
|
revokedTimestamp := user.RevokedTimestamp
|
||||||
return &model.User{
|
return &model.User{
|
||||||
ID: user.ID,
|
ID: user.ID,
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
|
@ -53,5 +55,6 @@ func (user *User) AsAPIUser() *model.User {
|
||||||
Roles: strings.Split(user.Roles, ","),
|
Roles: strings.Split(user.Roles, ","),
|
||||||
CreatedAt: &createdAt,
|
CreatedAt: &createdAt,
|
||||||
UpdatedAt: &updatedAt,
|
UpdatedAt: &updatedAt,
|
||||||
|
RevokedTimestamp: revokedTimestamp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,7 @@ type ComplexityRoot struct {
|
||||||
AdminLogout func(childComplexity int) int
|
AdminLogout func(childComplexity int) int
|
||||||
AdminSignup func(childComplexity int, params model.AdminSignupInput) int
|
AdminSignup func(childComplexity int, params model.AdminSignupInput) int
|
||||||
DeleteUser func(childComplexity int, params model.DeleteUserInput) int
|
DeleteUser func(childComplexity int, params model.DeleteUserInput) int
|
||||||
|
EnableAccess func(childComplexity int, param model.UpdateAccessInput) int
|
||||||
ForgotPassword func(childComplexity int, params model.ForgotPasswordInput) int
|
ForgotPassword func(childComplexity int, params model.ForgotPasswordInput) int
|
||||||
InviteMembers func(childComplexity int, params model.InviteMemberInput) int
|
InviteMembers func(childComplexity int, params model.InviteMemberInput) int
|
||||||
Login func(childComplexity int, params model.LoginInput) int
|
Login func(childComplexity int, params model.LoginInput) int
|
||||||
|
@ -123,6 +124,7 @@ type ComplexityRoot struct {
|
||||||
ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int
|
ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int
|
||||||
ResetPassword func(childComplexity int, params model.ResetPasswordInput) int
|
ResetPassword func(childComplexity int, params model.ResetPasswordInput) int
|
||||||
Revoke func(childComplexity int, params model.OAuthRevokeInput) int
|
Revoke func(childComplexity int, params model.OAuthRevokeInput) int
|
||||||
|
RevokeAccess func(childComplexity int, param model.UpdateAccessInput) int
|
||||||
Signup func(childComplexity int, params model.SignUpInput) int
|
Signup func(childComplexity int, params model.SignUpInput) int
|
||||||
UpdateEnv func(childComplexity int, params model.UpdateEnvInput) int
|
UpdateEnv func(childComplexity int, params model.UpdateEnvInput) int
|
||||||
UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int
|
UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int
|
||||||
|
@ -167,6 +169,7 @@ type ComplexityRoot struct {
|
||||||
PhoneNumberVerified func(childComplexity int) int
|
PhoneNumberVerified func(childComplexity int) int
|
||||||
Picture func(childComplexity int) int
|
Picture func(childComplexity int) int
|
||||||
PreferredUsername func(childComplexity int) int
|
PreferredUsername func(childComplexity int) int
|
||||||
|
RevokedTimestamp func(childComplexity int) int
|
||||||
Roles func(childComplexity int) int
|
Roles func(childComplexity int) int
|
||||||
SignupMethods func(childComplexity int) int
|
SignupMethods func(childComplexity int) int
|
||||||
UpdatedAt func(childComplexity int) int
|
UpdatedAt func(childComplexity int) int
|
||||||
|
@ -217,6 +220,8 @@ type MutationResolver interface {
|
||||||
AdminLogout(ctx context.Context) (*model.Response, error)
|
AdminLogout(ctx context.Context) (*model.Response, error)
|
||||||
UpdateEnv(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error)
|
UpdateEnv(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error)
|
||||||
InviteMembers(ctx context.Context, params model.InviteMemberInput) (*model.Response, error)
|
InviteMembers(ctx context.Context, params model.InviteMemberInput) (*model.Response, error)
|
||||||
|
RevokeAccess(ctx context.Context, param model.UpdateAccessInput) (*model.Response, error)
|
||||||
|
EnableAccess(ctx context.Context, param model.UpdateAccessInput) (*model.Response, error)
|
||||||
}
|
}
|
||||||
type QueryResolver interface {
|
type QueryResolver interface {
|
||||||
Meta(ctx context.Context) (*model.Meta, error)
|
Meta(ctx context.Context) (*model.Meta, error)
|
||||||
|
@ -672,6 +677,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Mutation.DeleteUser(childComplexity, args["params"].(model.DeleteUserInput)), true
|
return e.complexity.Mutation.DeleteUser(childComplexity, args["params"].(model.DeleteUserInput)), true
|
||||||
|
|
||||||
|
case "Mutation._enable_access":
|
||||||
|
if e.complexity.Mutation.EnableAccess == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation__enable_access_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.EnableAccess(childComplexity, args["param"].(model.UpdateAccessInput)), true
|
||||||
|
|
||||||
case "Mutation.forgot_password":
|
case "Mutation.forgot_password":
|
||||||
if e.complexity.Mutation.ForgotPassword == nil {
|
if e.complexity.Mutation.ForgotPassword == nil {
|
||||||
break
|
break
|
||||||
|
@ -763,6 +780,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Mutation.Revoke(childComplexity, args["params"].(model.OAuthRevokeInput)), true
|
return e.complexity.Mutation.Revoke(childComplexity, args["params"].(model.OAuthRevokeInput)), true
|
||||||
|
|
||||||
|
case "Mutation._revoke_access":
|
||||||
|
if e.complexity.Mutation.RevokeAccess == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation__revoke_access_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.RevokeAccess(childComplexity, args["param"].(model.UpdateAccessInput)), true
|
||||||
|
|
||||||
case "Mutation.signup":
|
case "Mutation.signup":
|
||||||
if e.complexity.Mutation.Signup == nil {
|
if e.complexity.Mutation.Signup == nil {
|
||||||
break
|
break
|
||||||
|
@ -1032,6 +1061,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.User.PreferredUsername(childComplexity), true
|
return e.complexity.User.PreferredUsername(childComplexity), true
|
||||||
|
|
||||||
|
case "User.revoked_timestamp":
|
||||||
|
if e.complexity.User.RevokedTimestamp == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.User.RevokedTimestamp(childComplexity), true
|
||||||
|
|
||||||
case "User.roles":
|
case "User.roles":
|
||||||
if e.complexity.User.Roles == nil {
|
if e.complexity.User.Roles == nil {
|
||||||
break
|
break
|
||||||
|
@ -1260,6 +1296,7 @@ type User {
|
||||||
roles: [String!]!
|
roles: [String!]!
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
|
revoked_timestamp: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Users {
|
type Users {
|
||||||
|
@ -1502,6 +1539,10 @@ input InviteMemberInput {
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input UpdateAccessInput {
|
||||||
|
user_id: String!
|
||||||
|
}
|
||||||
|
|
||||||
input ValidateJWTTokenInput {
|
input ValidateJWTTokenInput {
|
||||||
token_type: String!
|
token_type: String!
|
||||||
token: String!
|
token: String!
|
||||||
|
@ -1527,6 +1568,8 @@ type Mutation {
|
||||||
_admin_logout: Response!
|
_admin_logout: Response!
|
||||||
_update_env(params: UpdateEnvInput!): Response!
|
_update_env(params: UpdateEnvInput!): Response!
|
||||||
_invite_members(params: InviteMemberInput!): Response!
|
_invite_members(params: InviteMemberInput!): Response!
|
||||||
|
_revoke_access(param: UpdateAccessInput!): Response!
|
||||||
|
_enable_access(param: UpdateAccessInput!): Response!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
|
@ -1593,6 +1636,21 @@ func (ec *executionContext) field_Mutation__delete_user_args(ctx context.Context
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation__enable_access_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
var arg0 model.UpdateAccessInput
|
||||||
|
if tmp, ok := rawArgs["param"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("param"))
|
||||||
|
arg0, err = ec.unmarshalNUpdateAccessInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateAccessInput(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["param"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation__invite_members_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Mutation__invite_members_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
|
@ -1608,6 +1666,21 @@ func (ec *executionContext) field_Mutation__invite_members_args(ctx context.Cont
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation__revoke_access_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
var arg0 model.UpdateAccessInput
|
||||||
|
if tmp, ok := rawArgs["param"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("param"))
|
||||||
|
arg0, err = ec.unmarshalNUpdateAccessInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateAccessInput(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["param"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation__update_env_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Mutation__update_env_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
|
@ -4397,6 +4470,90 @@ func (ec *executionContext) _Mutation__invite_members(ctx context.Context, field
|
||||||
return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res)
|
return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation__revoke_access(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.field_Mutation__revoke_access_args(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
fc.Args = args
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Mutation().RevokeAccess(rctx, args["param"].(model.UpdateAccessInput))
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*model.Response)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation__enable_access(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.field_Mutation__enable_access_args(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
fc.Args = args
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Mutation().EnableAccess(rctx, args["param"].(model.UpdateAccessInput))
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*model.Response)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Pagination_limit(ctx context.Context, field graphql.CollectedField, obj *model.Pagination) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Pagination_limit(ctx context.Context, field graphql.CollectedField, obj *model.Pagination) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -5510,6 +5667,38 @@ func (ec *executionContext) _User_updated_at(ctx context.Context, field graphql.
|
||||||
return ec.marshalOInt642ᚖint64(ctx, field.Selections, res)
|
return ec.marshalOInt642ᚖint64(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _User_revoked_timestamp(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "User",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.RevokedTimestamp, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*int64)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOInt642ᚖint64(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Users_pagination(ctx context.Context, field graphql.CollectedField, obj *model.Users) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Users_pagination(ctx context.Context, field graphql.CollectedField, obj *model.Users) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -7644,6 +7833,29 @@ func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj i
|
||||||
return it, nil
|
return it, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalInputUpdateAccessInput(ctx context.Context, obj interface{}) (model.UpdateAccessInput, error) {
|
||||||
|
var it model.UpdateAccessInput
|
||||||
|
asMap := map[string]interface{}{}
|
||||||
|
for k, v := range obj.(map[string]interface{}) {
|
||||||
|
asMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range asMap {
|
||||||
|
switch k {
|
||||||
|
case "user_id":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("user_id"))
|
||||||
|
it.UserID, err = ec.unmarshalNString2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return it, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, obj interface{}) (model.UpdateEnvInput, error) {
|
func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, obj interface{}) (model.UpdateEnvInput, error) {
|
||||||
var it model.UpdateEnvInput
|
var it model.UpdateEnvInput
|
||||||
asMap := map[string]interface{}{}
|
asMap := map[string]interface{}{}
|
||||||
|
@ -8572,6 +8784,16 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
case "_revoke_access":
|
||||||
|
out.Values[i] = ec._Mutation__revoke_access(ctx, field)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
case "_enable_access":
|
||||||
|
out.Values[i] = ec._Mutation__enable_access(ctx, field)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
|
@ -8854,6 +9076,8 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj
|
||||||
out.Values[i] = ec._User_created_at(ctx, field, obj)
|
out.Values[i] = ec._User_created_at(ctx, field, obj)
|
||||||
case "updated_at":
|
case "updated_at":
|
||||||
out.Values[i] = ec._User_updated_at(ctx, field, obj)
|
out.Values[i] = ec._User_updated_at(ctx, field, obj)
|
||||||
|
case "revoked_timestamp":
|
||||||
|
out.Values[i] = ec._User_revoked_timestamp(ctx, field, obj)
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
|
@ -9466,6 +9690,11 @@ func (ec *executionContext) marshalNString2ᚕstringᚄ(ctx context.Context, sel
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalNUpdateAccessInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateAccessInput(ctx context.Context, v interface{}) (model.UpdateAccessInput, error) {
|
||||||
|
res, err := ec.unmarshalInputUpdateAccessInput(ctx, v)
|
||||||
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNUpdateEnvInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateEnvInput(ctx context.Context, v interface{}) (model.UpdateEnvInput, error) {
|
func (ec *executionContext) unmarshalNUpdateEnvInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateEnvInput(ctx context.Context, v interface{}) (model.UpdateEnvInput, error) {
|
||||||
res, err := ec.unmarshalInputUpdateEnvInput(ctx, v)
|
res, err := ec.unmarshalInputUpdateEnvInput(ctx, v)
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
|
|
@ -164,6 +164,10 @@ type SignUpInput struct {
|
||||||
RedirectURI *string `json:"redirect_uri"`
|
RedirectURI *string `json:"redirect_uri"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateAccessInput struct {
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
type UpdateEnvInput struct {
|
type UpdateEnvInput struct {
|
||||||
AdminSecret *string `json:"ADMIN_SECRET"`
|
AdminSecret *string `json:"ADMIN_SECRET"`
|
||||||
CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT"`
|
CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT"`
|
||||||
|
@ -249,6 +253,7 @@ type User struct {
|
||||||
Roles []string `json:"roles"`
|
Roles []string `json:"roles"`
|
||||||
CreatedAt *int64 `json:"created_at"`
|
CreatedAt *int64 `json:"created_at"`
|
||||||
UpdatedAt *int64 `json:"updated_at"`
|
UpdatedAt *int64 `json:"updated_at"`
|
||||||
|
RevokedTimestamp *int64 `json:"revoked_timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Users struct {
|
type Users struct {
|
||||||
|
|
|
@ -43,6 +43,7 @@ type User {
|
||||||
roles: [String!]!
|
roles: [String!]!
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
|
revoked_timestamp: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Users {
|
type Users {
|
||||||
|
@ -285,6 +286,10 @@ input InviteMemberInput {
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input UpdateAccessInput {
|
||||||
|
user_id: String!
|
||||||
|
}
|
||||||
|
|
||||||
input ValidateJWTTokenInput {
|
input ValidateJWTTokenInput {
|
||||||
token_type: String!
|
token_type: String!
|
||||||
token: String!
|
token: String!
|
||||||
|
@ -310,6 +315,8 @@ type Mutation {
|
||||||
_admin_logout: Response!
|
_admin_logout: Response!
|
||||||
_update_env(params: UpdateEnvInput!): Response!
|
_update_env(params: UpdateEnvInput!): Response!
|
||||||
_invite_members(params: InviteMemberInput!): Response!
|
_invite_members(params: InviteMemberInput!): Response!
|
||||||
|
_revoke_access(param: UpdateAccessInput!): Response!
|
||||||
|
_enable_access(param: UpdateAccessInput!): Response!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
|
|
|
@ -79,6 +79,14 @@ func (r *mutationResolver) InviteMembers(ctx context.Context, params model.Invit
|
||||||
return resolvers.InviteMembersResolver(ctx, params)
|
return resolvers.InviteMembersResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) RevokeAccess(ctx context.Context, param model.UpdateAccessInput) (*model.Response, error) {
|
||||||
|
return resolvers.RevokeAccessResolver(ctx, param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) EnableAccess(ctx context.Context, param model.UpdateAccessInput) (*model.Response, error) {
|
||||||
|
return resolvers.EnableAccessResolver(ctx, param)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) {
|
func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) {
|
||||||
return resolvers.MetaResolver(ctx)
|
return resolvers.MetaResolver(ctx)
|
||||||
}
|
}
|
||||||
|
@ -117,7 +125,5 @@ func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResol
|
||||||
// Query returns generated.QueryResolver implementation.
|
// Query returns generated.QueryResolver implementation.
|
||||||
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
|
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
|
||||||
|
|
||||||
type (
|
type mutationResolver struct{ *Resolver }
|
||||||
mutationResolver struct{ *Resolver }
|
type queryResolver struct{ *Resolver }
|
||||||
queryResolver struct{ *Resolver }
|
|
||||||
)
|
|
||||||
|
|
|
@ -95,9 +95,12 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
user.EmailVerifiedAt = &now
|
user.EmailVerifiedAt = &now
|
||||||
user, _ = db.Provider.AddUser(user)
|
user, _ = db.Provider.AddUser(user)
|
||||||
} else {
|
} else {
|
||||||
|
if user.RevokedTimestamp != nil {
|
||||||
|
c.JSON(400, gin.H{"error": "user access has been revoked"})
|
||||||
|
}
|
||||||
|
|
||||||
// user exists in db, check if method was google
|
// user exists in db, check if method was google
|
||||||
// if not append google to existing signup method and save it
|
// if not append google to existing signup method and save it
|
||||||
|
|
||||||
signupMethod := existingUser.SignupMethods
|
signupMethod := existingUser.SignupMethods
|
||||||
if !strings.Contains(signupMethod, provider) {
|
if !strings.Contains(signupMethod, provider) {
|
||||||
signupMethod = signupMethod + "," + provider
|
signupMethod = signupMethod + "," + provider
|
||||||
|
|
44
server/resolvers/enable_access.go
Normal file
44
server/resolvers/enable_access.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EnableAccessResolver is a resolver for enabling user access
|
||||||
|
func EnableAccessResolver(ctx context.Context, params model.UpdateAccessInput) (*model.Response, error) {
|
||||||
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
|
var res *model.Response
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !token.IsSuperAdmin(gc) {
|
||||||
|
return res, fmt.Errorf("unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := db.Provider.GetUserByID(params.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
user.RevokedTimestamp = nil
|
||||||
|
|
||||||
|
user, err = db.Provider.UpdateUser(user)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("error updating user:", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res = &model.Response{
|
||||||
|
Message: `user access enabled successfully`,
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -35,6 +35,10 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
return res, fmt.Errorf(`user with this email not found`)
|
return res, fmt.Errorf(`user with this email not found`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.RevokedTimestamp != nil {
|
||||||
|
return res, fmt.Errorf(`user access has been revoked`)
|
||||||
|
}
|
||||||
|
|
||||||
if !strings.Contains(user.SignupMethods, constants.SignupMethodBasicAuth) {
|
if !strings.Contains(user.SignupMethods, constants.SignupMethodBasicAuth) {
|
||||||
return res, fmt.Errorf(`user has not signed up email & password`)
|
return res, fmt.Errorf(`user has not signed up email & password`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,10 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
|
||||||
// 2. user has not signed up for one of the available role but trying to signup.
|
// 2. user has not signed up for one of the available role but trying to signup.
|
||||||
// Need to modify roles in this case
|
// Need to modify roles in this case
|
||||||
|
|
||||||
|
if user.RevokedTimestamp != nil {
|
||||||
|
return res, fmt.Errorf(`user access has been revoked`)
|
||||||
|
}
|
||||||
|
|
||||||
// find the unassigned roles
|
// find the unassigned roles
|
||||||
if len(params.Roles) <= 0 {
|
if len(params.Roles) <= 0 {
|
||||||
inputRoles = envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
inputRoles = envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
|
|
49
server/resolvers/revoke_access.go
Normal file
49
server/resolvers/revoke_access.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/sessionstore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RevokeAccessResolver is a resolver for revoking user access
|
||||||
|
func RevokeAccessResolver(ctx context.Context, params model.UpdateAccessInput) (*model.Response, error) {
|
||||||
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
|
var res *model.Response
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !token.IsSuperAdmin(gc) {
|
||||||
|
return res, fmt.Errorf("unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := db.Provider.GetUserByID(params.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().Unix()
|
||||||
|
user.RevokedTimestamp = &now
|
||||||
|
|
||||||
|
user, err = db.Provider.UpdateUser(user)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("error updating user:", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
go sessionstore.DeleteAllUserSession(fmt.Sprintf("%x", user.ID))
|
||||||
|
|
||||||
|
res = &model.Response{
|
||||||
|
Message: `user access revoked successfully`,
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user