Implement activate account page
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<e920b2bbd380e12014a100bfb963c8f7>>
|
* @generated SignedSource<<b79143becc90a4776f321d0e91db49bd>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
import { ConcreteRequest } from 'relay-runtime';
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
export type ActivateAccountInput = {
|
export type ActivateAccountInput = {
|
||||||
password: string;
|
password?: string | null | undefined;
|
||||||
token: string;
|
token: string;
|
||||||
};
|
};
|
||||||
export type ActivateAccountPageMutation$variables = {
|
export type ActivateAccountPageMutation$variables = {
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { formatError } from "@probo/helpers";
|
import { formatError, type GraphQLError } from "@probo/helpers";
|
||||||
import { usePageTitle } from "@probo/hooks";
|
import { usePageTitle } from "@probo/hooks";
|
||||||
import { useTranslate } from "@probo/i18n";
|
import { useTranslate } from "@probo/i18n";
|
||||||
import { Button, Field, useToast } from "@probo/ui";
|
import { useToast } from "@probo/ui";
|
||||||
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
import { useMutation } from "react-relay";
|
import { useMutation } from "react-relay";
|
||||||
import { Link, useNavigate, useSearchParams } from "react-router";
|
import { Link, useNavigate, useSearchParams } from "react-router";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import type { ActivateAccountPageMutation } from "#/__generated__/iam/ActivateAccountPageMutation.graphql";
|
import type { ActivateAccountPageMutation } from "#/__generated__/iam/ActivateAccountPageMutation.graphql";
|
||||||
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
|
||||||
|
|
||||||
const activateAccountMutation = graphql`
|
const activateAccountMutation = graphql`
|
||||||
mutation ActivateAccountPageMutation(
|
mutation ActivateAccountPageMutation(
|
||||||
@@ -22,64 +21,45 @@ const activateAccountMutation = graphql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const schema = z.object({
|
|
||||||
password: z.string().min(8),
|
|
||||||
fullName: z.string().min(2),
|
|
||||||
});
|
|
||||||
|
|
||||||
type FormData = z.infer<typeof schema>;
|
|
||||||
|
|
||||||
export default function ActivateAccountPage() {
|
export default function ActivateAccountPage() {
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const fullNameFromParams = searchParams.get("fullName") || "";
|
const submittedRef = useRef<boolean>(false);
|
||||||
|
|
||||||
usePageTitle(__("Sign up"));
|
usePageTitle(__("Activate Account"));
|
||||||
|
|
||||||
const { register, handleSubmit, formState } = useFormWithSchema(schema, {
|
|
||||||
defaultValues: {
|
|
||||||
password: "",
|
|
||||||
fullName: fullNameFromParams,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const [activateAccount] = useMutation<ActivateAccountPageMutation>(activateAccountMutation);
|
const [activateAccount] = useMutation<ActivateAccountPageMutation>(activateAccountMutation);
|
||||||
|
|
||||||
const onSubmit = (data: FormData) => {
|
const handleActivateAccount = useCallback((token: string) => {
|
||||||
const token = searchParams.get("token");
|
if (submittedRef.current) return;
|
||||||
if (!token) {
|
|
||||||
toast({
|
|
||||||
title: __("Signup failed"),
|
|
||||||
description: __("Invalid or missing invitation token"),
|
|
||||||
variant: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
activateAccount({
|
activateAccount({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: { token },
|
||||||
token,
|
|
||||||
password: data.password,
|
|
||||||
fullName: data.fullName,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
onCompleted: (_, e) => {
|
onCompleted: (_, errors: GraphQLError[] | null) => {
|
||||||
if (e) {
|
if (errors) {
|
||||||
|
for (const err of errors) {
|
||||||
|
if (err.extensions?.code === "ALREADY_AUTHENTICATED") {
|
||||||
|
window.location.href = "/";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
toast({
|
toast({
|
||||||
title: __("Signup failed"),
|
title: __("Activation failed"),
|
||||||
description: formatError(__("Signup failed"), e),
|
description: formatError(__("Activation failed"), errors),
|
||||||
variant: "error",
|
variant: "error",
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: __("Success"),
|
title: __("Success"),
|
||||||
description: __(
|
description: __(
|
||||||
"Account created successfully. Please accept your invitation to join the organization.",
|
"Account activated successfully.",
|
||||||
),
|
),
|
||||||
variant: "success",
|
variant: "success",
|
||||||
});
|
});
|
||||||
@@ -87,60 +67,37 @@ export default function ActivateAccountPage() {
|
|||||||
},
|
},
|
||||||
onError: (e) => {
|
onError: (e) => {
|
||||||
toast({
|
toast({
|
||||||
title: __("Signup failed"),
|
title: __("Activation failed"),
|
||||||
description: e.message,
|
description: e.message,
|
||||||
variant: "error",
|
variant: "error",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}, [__, toast, activateAccount, navigate]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const token = searchParams.get("token");
|
||||||
|
if (!submittedRef.current && token) {
|
||||||
|
void handleActivateAccount(token.trim());
|
||||||
|
submittedRef.current = true;
|
||||||
|
}
|
||||||
|
}, [handleActivateAccount, searchParams]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6 w-full max-w-md mx-auto pt-8">
|
<div className="space-y-6 w-full max-w-md mx-auto pt-8">
|
||||||
<div className="space-y-2 text-center">
|
<div className="space-y-2 text-center">
|
||||||
<h1 className="text-3xl font-bold">{__("Create your account")}</h1>
|
<h1 className="text-3xl font-bold">{__("Account Activation")}</h1>
|
||||||
<p className="text-txt-tertiary">
|
<p className="text-txt-tertiary">
|
||||||
{__("Set your password to join the organization")}
|
{__("Activating your account…")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="text-center mt-6 text-sm text-txt-secondary">
|
||||||
<form onSubmit={e => void handleSubmit(onSubmit)(e)} className="space-y-4">
|
<Link
|
||||||
<Field
|
to="/auth/login"
|
||||||
label={__("Full Name")}
|
className="underline hover:text-txt-primary"
|
||||||
type="text"
|
>
|
||||||
placeholder={__("John Doe")}
|
{__("Go back")}
|
||||||
{...register("fullName")}
|
</Link>
|
||||||
required
|
|
||||||
error={formState.errors.fullName?.message}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field
|
|
||||||
label={__("Password")}
|
|
||||||
type="password"
|
|
||||||
placeholder="••••••••"
|
|
||||||
{...register("password")}
|
|
||||||
required
|
|
||||||
error={formState.errors.password?.message}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button type="submit" className="w-xs h-10 mx-auto mt-6" disabled={formState.isLoading}>
|
|
||||||
{formState.isLoading
|
|
||||||
? __("Creating account...")
|
|
||||||
: __("Create account")}
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div className="text-center">
|
|
||||||
<p className="text-sm text-txt-tertiary">
|
|
||||||
{__("Already have an account?")}
|
|
||||||
{" "}
|
|
||||||
<Link
|
|
||||||
to="/auth/login"
|
|
||||||
className="underline text-txt-primary hover:text-txt-secondary"
|
|
||||||
>
|
|
||||||
{__("Log in here")}
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ export const Invitation = () => {
|
|||||||
return (
|
return (
|
||||||
<EmailLayout subject={'Invitation to join {{.OrganizationName}} on Probo'}>
|
<EmailLayout subject={'Invitation to join {{.OrganizationName}} on Probo'}>
|
||||||
<Text style={bodyText}>
|
<Text style={bodyText}>
|
||||||
You have been invited to join organization <strong>{'{{.OrganizationName}}'}</strong> on Probo. Click the button below to accept the invitation:
|
You have been invited to join organization <strong>{'{{.OrganizationName}}'}</strong> on Probo. Click the button below to activate your account:
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Section style={buttonContainer}>
|
<Section style={buttonContainer}>
|
||||||
<Button style={button} href={'{{.InvitationUrl}}'}>
|
<Button style={button} href={'{{.InvitationUrl}}'}>
|
||||||
Accept Invitation
|
Activate Account
|
||||||
</Button>
|
</Button>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Text style={footerText}>
|
<Text style={footerText}>
|
||||||
If you don't want to accept the invitation, you can ignore this email.
|
If you don't want to do so, you can ignore this email.
|
||||||
</Text>
|
</Text>
|
||||||
</EmailLayout>
|
</EmailLayout>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ Probo
|
|||||||
|
|
||||||
Hi {{.RecipientFullName}},
|
Hi {{.RecipientFullName}},
|
||||||
|
|
||||||
You have been invited to join organization {{.OrganizationName}} on Probo. Click the link below to accept the invitation:
|
You have been invited to join organization {{.OrganizationName}} on Probo. Click the link below to activate your account:
|
||||||
|
|
||||||
{{.InvitationUrl}}
|
{{.InvitationUrl}}
|
||||||
|
|
||||||
If you don't want to accept the invitation, you can ignore this email.
|
If you don't want to do so, you can ignore this email.
|
||||||
|
|
||||||
{{.SenderCompanyHeadquarterAddress}}
|
{{.SenderCompanyHeadquarterAddress}}
|
||||||
Powered By Probo
|
Powered By Probo
|
||||||
|
|||||||
@@ -293,7 +293,6 @@ func (i *Invitations) ExpireByUserID(
|
|||||||
expires_at = NOW()
|
expires_at = NOW()
|
||||||
WHERE
|
WHERE
|
||||||
user_id = @user_id
|
user_id = @user_id
|
||||||
AND organization_id = @organization_id
|
|
||||||
AND %s
|
AND %s
|
||||||
AND %s
|
AND %s
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ type (
|
|||||||
|
|
||||||
CreateIdentityFromInvitationRequest struct {
|
CreateIdentityFromInvitationRequest struct {
|
||||||
InvitationToken string
|
InvitationToken string
|
||||||
Password string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadOrCreateIdentityRequest struct {
|
LoadOrCreateIdentityRequest struct {
|
||||||
@@ -92,7 +91,6 @@ func (req CreateIdentityFromInvitationRequest) Validate() error {
|
|||||||
v := validator.New()
|
v := validator.New()
|
||||||
|
|
||||||
v.Check(req.InvitationToken, "invitationToken", validator.NotEmpty())
|
v.Check(req.InvitationToken, "invitationToken", validator.NotEmpty())
|
||||||
v.Check(req.Password, "password", PasswordValidator())
|
|
||||||
|
|
||||||
return v.Error()
|
return v.Error()
|
||||||
}
|
}
|
||||||
@@ -153,11 +151,6 @@ func (s *AuthService) ActivateAccount(
|
|||||||
now = time.Now()
|
now = time.Now()
|
||||||
)
|
)
|
||||||
|
|
||||||
hashedPassword, err := s.hp.HashPassword([]byte(req.Password))
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("cannot hash password: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.pg.WithTx(
|
err = s.pg.WithTx(
|
||||||
ctx,
|
ctx,
|
||||||
func(tx pg.Conn) error {
|
func(tx pg.Conn) error {
|
||||||
@@ -197,7 +190,6 @@ func (s *AuthService) ActivateAccount(
|
|||||||
return fmt.Errorf("cannot load identity: %w", err)
|
return fmt.Errorf("cannot load identity: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
identity.HashedPassword = hashedPassword
|
|
||||||
identity.EmailAddressVerified = true
|
identity.EmailAddressVerified = true
|
||||||
identity.UpdatedAt = now
|
identity.UpdatedAt = now
|
||||||
|
|
||||||
|
|||||||
@@ -326,15 +326,15 @@ func (e ErrInvitationNotDeleted) Error() string {
|
|||||||
return fmt.Sprintf("cannot delete invitation %q in %q status", e.InvitationID, e.Status)
|
return fmt.Sprintf("cannot delete invitation %q in %q status", e.InvitationID, e.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrPasswordRequired struct {
|
type ErrPasswordAuthenticationRequired struct {
|
||||||
Reason string
|
Reason string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPasswordRequiredError(reason string) *ErrPasswordRequired {
|
func NewPasswordAuthenticationRequiredError(reason string) *ErrPasswordAuthenticationRequired {
|
||||||
return &ErrPasswordRequired{Reason: reason}
|
return &ErrPasswordAuthenticationRequired{Reason: reason}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrPasswordRequired) Error() string {
|
func (e *ErrPasswordAuthenticationRequired) Error() string {
|
||||||
return fmt.Sprintf("password authentication required: %s", e.Reason)
|
return fmt.Sprintf("password authentication required: %s", e.Reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -573,16 +573,23 @@ func (s SessionService) AssumeOrganizationSession(
|
|||||||
return fmt.Errorf("cannot load SAML configuration: %w", err)
|
return fmt.Errorf("cannot load SAML configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && samlConfig.EnforcementPolicy == coredata.SAMLEnforcementPolicyRequired {
|
if err == nil {
|
||||||
if rootSession.AuthMethod != coredata.AuthMethodSAML {
|
switch samlConfig.EnforcementPolicy {
|
||||||
return NewSAMLAuthenticationRequiredError("policy_requirement")
|
case coredata.SAMLEnforcementPolicyRequired:
|
||||||
|
if rootSession.AuthMethod != coredata.AuthMethodSAML {
|
||||||
|
return NewSAMLAuthenticationRequiredError("policy_requirement")
|
||||||
|
}
|
||||||
|
case coredata.SAMLEnforcementPolicyOptional:
|
||||||
|
// SAML is optional: both PASSWORD and SAML root sessions are allowed.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch rootSession.AuthMethod {
|
||||||
|
case coredata.AuthMethodPassword:
|
||||||
|
case coredata.AuthMethodSAML:
|
||||||
|
// No (or non-required) SAML configuration: require a password-authenticated or magic-link root session
|
||||||
|
// (eg. when switching into a password-based org from a SAML login)
|
||||||
|
return NewPasswordAuthenticationRequiredError("password_authentication_required")
|
||||||
}
|
}
|
||||||
} else if err == nil && samlConfig.EnforcementPolicy == coredata.SAMLEnforcementPolicyOptional {
|
|
||||||
// SAML is optional: both PASSWORD and SAML root sessions are allowed.
|
|
||||||
} else if rootSession.AuthMethod != coredata.AuthMethodPassword {
|
|
||||||
// No (or non-required) SAML configuration: require a password-authenticated root session
|
|
||||||
// (eg. when switching into a password-based org from a SAML login).
|
|
||||||
return NewPasswordRequiredError("password_authentication_required")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tenantID := scope.GetTenantID()
|
tenantID := scope.GetTenantID()
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ type Identity implements Node {
|
|||||||
last: Int
|
last: Int
|
||||||
before: CursorKey
|
before: CursorKey
|
||||||
orderBy: ProfileOrder
|
orderBy: ProfileOrder
|
||||||
|
filter: ProfileFilter
|
||||||
): ProfileConnection @goField(forceResolver: true)
|
): ProfileConnection @goField(forceResolver: true)
|
||||||
|
|
||||||
sessions(
|
sessions(
|
||||||
@@ -512,6 +513,11 @@ enum ProfileOrderField
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input ProfileFilter {
|
||||||
|
excludeContractEnded: Boolean
|
||||||
|
state: ProfileState
|
||||||
|
}
|
||||||
|
|
||||||
input ProfileOrder
|
input ProfileOrder
|
||||||
@goModel(
|
@goModel(
|
||||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.ProfileOrderBy"
|
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.ProfileOrderBy"
|
||||||
@@ -628,7 +634,6 @@ input SignUpInput {
|
|||||||
|
|
||||||
input ActivateAccountInput {
|
input ActivateAccountInput {
|
||||||
token: String!
|
token: String!
|
||||||
password: String!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input ForgotPasswordInput {
|
input ForgotPasswordInput {
|
||||||
@@ -794,6 +799,10 @@ type ActivateAccountPayload {
|
|||||||
profile: Profile
|
profile: Profile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreatePasswordPayload {
|
||||||
|
success: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
type ForgotPasswordPayload {
|
type ForgotPasswordPayload {
|
||||||
success: Boolean!
|
success: Boolean!
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,10 @@ type ComplexityRoot struct {
|
|||||||
Organization func(childComplexity int) int
|
Organization func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CreatePasswordPayload struct {
|
||||||
|
Success func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
CreatePersonalAPIKeyPayload struct {
|
CreatePersonalAPIKeyPayload struct {
|
||||||
PersonalAPIKeyEdge func(childComplexity int) int
|
PersonalAPIKeyEdge func(childComplexity int) int
|
||||||
Token func(childComplexity int) int
|
Token func(childComplexity int) int
|
||||||
@@ -159,7 +163,7 @@ type ComplexityRoot struct {
|
|||||||
ID func(childComplexity int) int
|
ID func(childComplexity int) int
|
||||||
Permission func(childComplexity int, action string) int
|
Permission func(childComplexity int, action string) int
|
||||||
PersonalAPIKeys func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey) int
|
PersonalAPIKeys func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey) int
|
||||||
Profiles func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy) int
|
Profiles func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy, filter *types.ProfileFilter) int
|
||||||
Sessions func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SessionOrder) int
|
Sessions func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SessionOrder) int
|
||||||
UpdatedAt func(childComplexity int) int
|
UpdatedAt func(childComplexity int) int
|
||||||
}
|
}
|
||||||
@@ -499,7 +503,7 @@ type ConnectorResolver interface {
|
|||||||
Permission(ctx context.Context, obj *types.Connector, action string) (bool, error)
|
Permission(ctx context.Context, obj *types.Connector, action string) (bool, error)
|
||||||
}
|
}
|
||||||
type IdentityResolver interface {
|
type IdentityResolver interface {
|
||||||
Profiles(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy) (*types.ProfileConnection, error)
|
Profiles(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy, filter *types.ProfileFilter) (*types.ProfileConnection, error)
|
||||||
Sessions(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SessionOrder) (*types.SessionConnection, error)
|
Sessions(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SessionOrder) (*types.SessionConnection, error)
|
||||||
PersonalAPIKeys(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.PersonalAPIKeyConnection, error)
|
PersonalAPIKeys(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.PersonalAPIKeyConnection, error)
|
||||||
SsoLoginURL(ctx context.Context, obj *types.Identity) (*string, error)
|
SsoLoginURL(ctx context.Context, obj *types.Identity) (*string, error)
|
||||||
@@ -727,6 +731,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
|
|
||||||
return e.complexity.CreateOrganizationPayload.Organization(childComplexity), true
|
return e.complexity.CreateOrganizationPayload.Organization(childComplexity), true
|
||||||
|
|
||||||
|
case "CreatePasswordPayload.success":
|
||||||
|
if e.complexity.CreatePasswordPayload.Success == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.CreatePasswordPayload.Success(childComplexity), true
|
||||||
|
|
||||||
case "CreatePersonalAPIKeyPayload.personalAPIKeyEdge":
|
case "CreatePersonalAPIKeyPayload.personalAPIKeyEdge":
|
||||||
if e.complexity.CreatePersonalAPIKeyPayload.PersonalAPIKeyEdge == nil {
|
if e.complexity.CreatePersonalAPIKeyPayload.PersonalAPIKeyEdge == nil {
|
||||||
break
|
break
|
||||||
@@ -877,7 +888,7 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.complexity.Identity.Profiles(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ProfileOrderBy)), true
|
return e.complexity.Identity.Profiles(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ProfileOrderBy), args["filter"].(*types.ProfileFilter)), true
|
||||||
case "Identity.sessions":
|
case "Identity.sessions":
|
||||||
if e.complexity.Identity.Sessions == nil {
|
if e.complexity.Identity.Sessions == nil {
|
||||||
break
|
break
|
||||||
@@ -2357,6 +2368,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
|||||||
ec.unmarshalInputForgotPasswordInput,
|
ec.unmarshalInputForgotPasswordInput,
|
||||||
ec.unmarshalInputInvitationOrder,
|
ec.unmarshalInputInvitationOrder,
|
||||||
ec.unmarshalInputInviteUserInput,
|
ec.unmarshalInputInviteUserInput,
|
||||||
|
ec.unmarshalInputProfileFilter,
|
||||||
ec.unmarshalInputProfileOrder,
|
ec.unmarshalInputProfileOrder,
|
||||||
ec.unmarshalInputRegenerateSCIMTokenInput,
|
ec.unmarshalInputRegenerateSCIMTokenInput,
|
||||||
ec.unmarshalInputRemoveUserInput,
|
ec.unmarshalInputRemoveUserInput,
|
||||||
@@ -2614,6 +2626,7 @@ type Identity implements Node {
|
|||||||
last: Int
|
last: Int
|
||||||
before: CursorKey
|
before: CursorKey
|
||||||
orderBy: ProfileOrder
|
orderBy: ProfileOrder
|
||||||
|
filter: ProfileFilter
|
||||||
): ProfileConnection @goField(forceResolver: true)
|
): ProfileConnection @goField(forceResolver: true)
|
||||||
|
|
||||||
sessions(
|
sessions(
|
||||||
@@ -2985,6 +2998,11 @@ enum ProfileOrderField
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input ProfileFilter {
|
||||||
|
excludeContractEnded: Boolean
|
||||||
|
state: ProfileState
|
||||||
|
}
|
||||||
|
|
||||||
input ProfileOrder
|
input ProfileOrder
|
||||||
@goModel(
|
@goModel(
|
||||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.ProfileOrderBy"
|
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.ProfileOrderBy"
|
||||||
@@ -3101,7 +3119,6 @@ input SignUpInput {
|
|||||||
|
|
||||||
input ActivateAccountInput {
|
input ActivateAccountInput {
|
||||||
token: String!
|
token: String!
|
||||||
password: String!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input ForgotPasswordInput {
|
input ForgotPasswordInput {
|
||||||
@@ -3267,6 +3284,10 @@ type ActivateAccountPayload {
|
|||||||
profile: Profile
|
profile: Profile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreatePasswordPayload {
|
||||||
|
success: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
type ForgotPasswordPayload {
|
type ForgotPasswordPayload {
|
||||||
success: Boolean!
|
success: Boolean!
|
||||||
}
|
}
|
||||||
@@ -3557,6 +3578,11 @@ func (ec *executionContext) field_Identity_profiles_args(ctx context.Context, ra
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
args["orderBy"] = arg4
|
args["orderBy"] = arg4
|
||||||
|
arg5, err := graphql.ProcessArgField(ctx, rawArgs, "filter", ec.unmarshalOProfileFilter2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProfileFilter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args["filter"] = arg5
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4730,6 +4756,35 @@ func (ec *executionContext) fieldContext_CreateOrganizationPayload_membership(_
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _CreatePasswordPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.CreatePasswordPayload) (ret graphql.Marshaler) {
|
||||||
|
return graphql.ResolveField(
|
||||||
|
ctx,
|
||||||
|
ec.OperationContext,
|
||||||
|
field,
|
||||||
|
ec.fieldContext_CreatePasswordPayload_success,
|
||||||
|
func(ctx context.Context) (any, error) {
|
||||||
|
return obj.Success, nil
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
ec.marshalNBoolean2bool,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_CreatePasswordPayload_success(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "CreatePasswordPayload",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type Boolean does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _CreatePersonalAPIKeyPayload_personalAPIKeyEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreatePersonalAPIKeyPayload) (ret graphql.Marshaler) {
|
func (ec *executionContext) _CreatePersonalAPIKeyPayload_personalAPIKeyEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreatePersonalAPIKeyPayload) (ret graphql.Marshaler) {
|
||||||
return graphql.ResolveField(
|
return graphql.ResolveField(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -5377,7 +5432,7 @@ func (ec *executionContext) _Identity_profiles(ctx context.Context, field graphq
|
|||||||
ec.fieldContext_Identity_profiles,
|
ec.fieldContext_Identity_profiles,
|
||||||
func(ctx context.Context) (any, error) {
|
func(ctx context.Context) (any, error) {
|
||||||
fc := graphql.GetFieldContext(ctx)
|
fc := graphql.GetFieldContext(ctx)
|
||||||
return ec.resolvers.Identity().Profiles(ctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.ProfileOrderBy))
|
return ec.resolvers.Identity().Profiles(ctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.ProfileOrderBy), fc.Args["filter"].(*types.ProfileFilter))
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
ec.marshalOProfileConnection2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProfileConnection,
|
ec.marshalOProfileConnection2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProfileConnection,
|
||||||
@@ -15129,7 +15184,7 @@ func (ec *executionContext) unmarshalInputActivateAccountInput(ctx context.Conte
|
|||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"token", "password"}
|
fieldsInOrder := [...]string{"token"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -15143,13 +15198,6 @@ func (ec *executionContext) unmarshalInputActivateAccountInput(ctx context.Conte
|
|||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.Token = data
|
it.Token = data
|
||||||
case "password":
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password"))
|
|
||||||
data, err := ec.unmarshalNString2string(ctx, v)
|
|
||||||
if err != nil {
|
|
||||||
return it, err
|
|
||||||
}
|
|
||||||
it.Password = data
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15770,6 +15818,40 @@ func (ec *executionContext) unmarshalInputInviteUserInput(ctx context.Context, o
|
|||||||
return it, nil
|
return it, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalInputProfileFilter(ctx context.Context, obj any) (types.ProfileFilter, error) {
|
||||||
|
var it types.ProfileFilter
|
||||||
|
asMap := map[string]any{}
|
||||||
|
for k, v := range obj.(map[string]any) {
|
||||||
|
asMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsInOrder := [...]string{"excludeContractEnded", "state"}
|
||||||
|
for _, k := range fieldsInOrder {
|
||||||
|
v, ok := asMap[k]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch k {
|
||||||
|
case "excludeContractEnded":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("excludeContractEnded"))
|
||||||
|
data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.ExcludeContractEnded = data
|
||||||
|
case "state":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
|
||||||
|
data, err := ec.unmarshalOProfileState2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐProfileState(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.State = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return it, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalInputProfileOrder(ctx context.Context, obj any) (types.ProfileOrderBy, error) {
|
func (ec *executionContext) unmarshalInputProfileOrder(ctx context.Context, obj any) (types.ProfileOrderBy, error) {
|
||||||
var it types.ProfileOrderBy
|
var it types.ProfileOrderBy
|
||||||
asMap := map[string]any{}
|
asMap := map[string]any{}
|
||||||
@@ -16955,6 +17037,45 @@ func (ec *executionContext) _CreateOrganizationPayload(ctx context.Context, sel
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var createPasswordPayloadImplementors = []string{"CreatePasswordPayload"}
|
||||||
|
|
||||||
|
func (ec *executionContext) _CreatePasswordPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreatePasswordPayload) graphql.Marshaler {
|
||||||
|
fields := graphql.CollectFields(ec.OperationContext, sel, createPasswordPayloadImplementors)
|
||||||
|
|
||||||
|
out := graphql.NewFieldSet(fields)
|
||||||
|
deferred := make(map[string]*graphql.FieldSet)
|
||||||
|
for i, field := range fields {
|
||||||
|
switch field.Name {
|
||||||
|
case "__typename":
|
||||||
|
out.Values[i] = graphql.MarshalString("CreatePasswordPayload")
|
||||||
|
case "success":
|
||||||
|
out.Values[i] = ec._CreatePasswordPayload_success(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Dispatch(ctx)
|
||||||
|
if out.Invalids > 0 {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
|
||||||
|
|
||||||
|
for label, dfs := range deferred {
|
||||||
|
ec.processDeferredGroup(graphql.DeferredGroup{
|
||||||
|
Label: label,
|
||||||
|
Path: graphql.GetPath(ctx),
|
||||||
|
FieldSet: dfs,
|
||||||
|
Context: ctx,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
var createPersonalAPIKeyPayloadImplementors = []string{"CreatePersonalAPIKeyPayload"}
|
var createPersonalAPIKeyPayloadImplementors = []string{"CreatePersonalAPIKeyPayload"}
|
||||||
|
|
||||||
func (ec *executionContext) _CreatePersonalAPIKeyPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreatePersonalAPIKeyPayload) graphql.Marshaler {
|
func (ec *executionContext) _CreatePersonalAPIKeyPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreatePersonalAPIKeyPayload) graphql.Marshaler {
|
||||||
@@ -23298,6 +23419,14 @@ func (ec *executionContext) marshalOProfileConnection2ᚖgoᚗproboᚗincᚋprob
|
|||||||
return ec._ProfileConnection(ctx, sel, v)
|
return ec._ProfileConnection(ctx, sel, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalOProfileFilter2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProfileFilter(ctx context.Context, v any) (*types.ProfileFilter, error) {
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
res, err := ec.unmarshalInputProfileFilter(ctx, v)
|
||||||
|
return &res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalOProfileOrder2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProfileOrderBy(ctx context.Context, v any) (*types.ProfileOrderBy, error) {
|
func (ec *executionContext) unmarshalOProfileOrder2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProfileOrderBy(ctx context.Context, v any) (*types.ProfileOrderBy, error) {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -23306,6 +23435,36 @@ func (ec *executionContext) unmarshalOProfileOrder2ᚖgoᚗproboᚗincᚋprobo
|
|||||||
return &res, graphql.ErrorOnPath(ctx, err)
|
return &res, graphql.ErrorOnPath(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalOProfileState2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐProfileState(ctx context.Context, v any) (*coredata.ProfileState, error) {
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
tmp, err := graphql.UnmarshalString(v)
|
||||||
|
res := unmarshalOProfileState2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐProfileState[tmp]
|
||||||
|
return &res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalOProfileState2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐProfileState(ctx context.Context, sel ast.SelectionSet, v *coredata.ProfileState) graphql.Marshaler {
|
||||||
|
if v == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
_ = sel
|
||||||
|
_ = ctx
|
||||||
|
res := graphql.MarshalString(marshalOProfileState2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐProfileState[*v])
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
unmarshalOProfileState2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐProfileState = map[string]coredata.ProfileState{
|
||||||
|
"ACTIVE": coredata.ProfileStateActive,
|
||||||
|
"INACTIVE": coredata.ProfileStateInactive,
|
||||||
|
}
|
||||||
|
marshalOProfileState2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐProfileState = map[coredata.ProfileState]string{
|
||||||
|
coredata.ProfileStateActive: "ACTIVE",
|
||||||
|
coredata.ProfileStateInactive: "INACTIVE",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func (ec *executionContext) marshalORegenerateSCIMTokenPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRegenerateSCIMTokenPayload(ctx context.Context, sel ast.SelectionSet, v *types.RegenerateSCIMTokenPayload) graphql.Marshaler {
|
func (ec *executionContext) marshalORegenerateSCIMTokenPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRegenerateSCIMTokenPayload(ctx context.Context, sel ast.SelectionSet, v *types.RegenerateSCIMTokenPayload) graphql.Marshaler {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return graphql.Null
|
return graphql.Null
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ type (
|
|||||||
|
|
||||||
Resolver any
|
Resolver any
|
||||||
ParentID gid.GID
|
ParentID gid.GID
|
||||||
|
Filters *coredata.MembershipProfileFilter
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,6 +38,7 @@ func NewProfileConnection(
|
|||||||
p *page.Page[*coredata.MembershipProfile, coredata.MembershipProfileOrderField],
|
p *page.Page[*coredata.MembershipProfile, coredata.MembershipProfileOrderField],
|
||||||
resolver any,
|
resolver any,
|
||||||
parentID gid.GID,
|
parentID gid.GID,
|
||||||
|
filters *coredata.MembershipProfileFilter,
|
||||||
) *ProfileConnection {
|
) *ProfileConnection {
|
||||||
edges := make([]*ProfileEdge, len(p.Data))
|
edges := make([]*ProfileEdge, len(p.Data))
|
||||||
for i, profile := range p.Data {
|
for i, profile := range p.Data {
|
||||||
@@ -49,6 +51,7 @@ func NewProfileConnection(
|
|||||||
|
|
||||||
Resolver: resolver,
|
Resolver: resolver,
|
||||||
ParentID: parentID,
|
ParentID: parentID,
|
||||||
|
Filters: filters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ type AcceptInvitationPayload struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ActivateAccountInput struct {
|
type ActivateAccountInput struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
Password string `json:"password"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActivateAccountPayload struct {
|
type ActivateAccountPayload struct {
|
||||||
@@ -92,6 +91,10 @@ type CreateOrganizationPayload struct {
|
|||||||
Membership *Membership `json:"membership"`
|
Membership *Membership `json:"membership"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreatePasswordPayload struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
type CreatePersonalAPIKeyInput struct {
|
type CreatePersonalAPIKeyInput struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ExpiresAt time.Time `json:"expiresAt"`
|
ExpiresAt time.Time `json:"expiresAt"`
|
||||||
@@ -339,6 +342,11 @@ type ProfileEdge struct {
|
|||||||
Node *Profile `json:"node"`
|
Node *Profile `json:"node"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProfileFilter struct {
|
||||||
|
ExcludeContractEnded *bool `json:"excludeContractEnded,omitempty"`
|
||||||
|
State *coredata.ProfileState `json:"state,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type Query struct {
|
type Query struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,17 +33,24 @@ func (r *connectorResolver) Permission(ctx context.Context, obj *types.Connector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Profiles is the resolver for the profiles field.
|
// Profiles is the resolver for the profiles field.
|
||||||
func (r *identityResolver) Profiles(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy) (*types.ProfileConnection, error) {
|
func (r *identityResolver) Profiles(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy, filter *types.ProfileFilter) (*types.ProfileConnection, error) {
|
||||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList, authz.WithSkipAssumptionCheck()); err != nil {
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList, authz.WithSkipAssumptionCheck()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
filter := coredata.NewMembershipProfileFilter(nil)
|
filters := coredata.NewMembershipProfileFilter(nil)
|
||||||
|
if filter != nil {
|
||||||
|
filters = coredata.NewMembershipProfileFilter(filter.ExcludeContractEnded)
|
||||||
|
if filter.State != nil {
|
||||||
|
filters.WithState(*filter.State)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if gqlutils.OnlyTotalCountSelected(ctx) {
|
if gqlutils.OnlyTotalCountSelected(ctx) {
|
||||||
return &types.ProfileConnection{
|
return &types.ProfileConnection{
|
||||||
Resolver: r,
|
Resolver: r,
|
||||||
ParentID: obj.ID,
|
ParentID: obj.ID,
|
||||||
|
Filters: filters,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,13 +67,13 @@ func (r *identityResolver) Profiles(ctx context.Context, obj *types.Identity, fi
|
|||||||
|
|
||||||
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
||||||
|
|
||||||
page, err := r.iam.AccountService.ListProfilesForIdentity(ctx, obj.ID, cursor, filter)
|
page, err := r.iam.AccountService.ListProfilesForIdentity(ctx, obj.ID, cursor, filters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot list profiles", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot list profiles", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.NewProfileConnection(page, r, obj.ID), nil
|
return types.NewProfileConnection(page, r, obj.ID, filters), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sessions is the resolver for the sessions field.
|
// Sessions is the resolver for the sessions field.
|
||||||
@@ -381,7 +388,6 @@ func (r *mutationResolver) ActivateAccount(ctx context.Context, input types.Acti
|
|||||||
ctx,
|
ctx,
|
||||||
&iam.CreateIdentityFromInvitationRequest{
|
&iam.CreateIdentityFromInvitationRequest{
|
||||||
InvitationToken: input.Token,
|
InvitationToken: input.Token,
|
||||||
Password: input.Password,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -565,19 +571,19 @@ func (r *mutationResolver) AssumeOrganizationSession(ctx context.Context, input
|
|||||||
childSession, membership, err := r.iam.SessionService.AssumeOrganizationSession(ctx, rootSession.ID, input.OrganizationID, input.Continue)
|
childSession, membership, err := r.iam.SessionService.AssumeOrganizationSession(ctx, rootSession.ID, input.OrganizationID, input.Continue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var (
|
var (
|
||||||
errMembershipNotFound *iam.ErrMembershipNotFound
|
errMembershipNotFound *iam.ErrMembershipNotFound
|
||||||
errPasswordRequired *iam.ErrPasswordRequired
|
errPasswordAuthenticationRequired *iam.ErrPasswordAuthenticationRequired
|
||||||
errSAMLAuthenticationRequired *iam.ErrSAMLAuthenticationRequired
|
errSAMLAuthenticationRequired *iam.ErrSAMLAuthenticationRequired
|
||||||
)
|
)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case errors.As(err, &errMembershipNotFound):
|
case errors.As(err, &errMembershipNotFound):
|
||||||
return nil, gqlutils.NotFound(ctx, err)
|
return nil, gqlutils.NotFound(ctx, err)
|
||||||
|
|
||||||
case errors.As(err, &errPasswordRequired):
|
case errors.As(err, &errPasswordAuthenticationRequired):
|
||||||
return &types.AssumeOrganizationSessionPayload{
|
return &types.AssumeOrganizationSessionPayload{
|
||||||
Result: types.PasswordRequired{
|
Result: types.PasswordRequired{
|
||||||
Reason: types.ReauthenticationReason(errPasswordRequired.Reason),
|
Reason: types.ReauthenticationReason(errPasswordAuthenticationRequired.Reason),
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
@@ -1199,7 +1205,7 @@ func (r *organizationResolver) Profiles(ctx context.Context, obj *types.Organiza
|
|||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.NewProfileConnection(page, r, obj.ID), nil
|
return types.NewProfileConnection(page, r, obj.ID, filter), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SamlConfigurations is the resolver for the samlConfigurations field.
|
// SamlConfigurations is the resolver for the samlConfigurations field.
|
||||||
|
|||||||
Reference in New Issue
Block a user