Compare commits

...

3 Commits

Author SHA1 Message Date
vikrantgupta25
654382062e chore(user): keep /api/v1/user/me as a deprecated stub
Assisted-by: Claude Opus 5
2026-08-13 12:26:55 +05:30
vikrantgupta25
7b6f725c2f chore(user): remove deprecated user endpoints
Assisted-by: Claude Opus 5
2026-08-13 12:12:38 +05:30
vikrantgupta25
a2d82d029f test(integration): move role cleanups to the v2 user_roles API
Assisted-by: Claude Opus 5
2026-08-13 12:12:37 +05:30
17 changed files with 30 additions and 1728 deletions

View File

@@ -8866,31 +8866,6 @@ components:
oldPassword:
type: string
type: object
TypesDeprecatedUser:
properties:
createdAt:
format: date-time
type: string
displayName:
type: string
email:
type: string
id:
type: string
isRoot:
type: boolean
orgId:
type: string
role:
type: string
status:
type: string
updatedAt:
format: date-time
type: string
required:
- id
type: object
TypesIdentifiable:
properties:
id:
@@ -8898,31 +8873,6 @@ components:
required:
- id
type: object
TypesInvite:
properties:
createdAt:
format: date-time
type: string
email:
type: string
id:
type: string
inviteLink:
type: string
name:
type: string
orgId:
type: string
role:
type: string
token:
type: string
updatedAt:
format: date-time
type: string
required:
- id
type: object
TypesOrganization:
properties:
alias:
@@ -8957,17 +8907,6 @@ components:
- orgId
- email
type: object
TypesPostableInvite:
properties:
email:
type: string
frontendBaseUrl:
type: string
name:
type: string
role:
type: string
type: object
TypesPostableResetPassword:
properties:
password:
@@ -8975,13 +8914,6 @@ components:
token:
type: string
type: object
TypesPostableRole:
properties:
name:
type: string
required:
- name
type: object
TypesPostableVerifyResetPasswordToken:
properties:
token:
@@ -11396,70 +11328,6 @@ paths:
summary: Get field values
tags:
- fields
/api/v1/getResetPasswordToken/{id}:
get:
deprecated: true
description: This endpoint returns the reset password token by id
operationId: GetResetPasswordTokenDeprecated
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/TypesResetPasswordToken'
status:
type: string
required:
- status
- data
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Get reset password token
tags:
- users
/api/v1/global/config:
get:
deprecated: false
@@ -11489,69 +11357,6 @@ paths:
summary: Get global config
tags:
- global
/api/v1/invite:
post:
deprecated: true
description: This endpoint creates an invite for a user
operationId: CreateInvite
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TypesPostableInvite'
responses:
"201":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/TypesInvite'
status:
type: string
required:
- status
- data
type: object
description: Created
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Conflict
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Create invite
tags:
- users
/api/v1/llm_pricing_rules:
get:
deprecated: false
@@ -12203,40 +12008,6 @@ paths:
summary: Get query range result
tags:
- dashboard
/api/v1/resetPassword:
post:
deprecated: true
description: This endpoint resets the password by token
operationId: ResetPasswordDeprecated
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TypesPostableResetPassword'
responses:
"204":
description: No Content
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Conflict
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
summary: Reset password
tags:
- users
/api/v1/roles:
get:
deprecated: false
@@ -14427,73 +14198,14 @@ paths:
summary: Get aggregations for a trace
tags:
- tracedetail
/api/v1/user:
get:
deprecated: true
description: This endpoint lists all users
operationId: ListUsersDeprecated
responses:
"200":
content:
application/json:
schema:
properties:
data:
items:
$ref: '#/components/schemas/TypesDeprecatedUser'
type: array
status:
type: string
required:
- status
- data
type: object
description: OK
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: List users
tags:
- users
/api/v1/user/me:
get:
deprecated: true
description: This endpoint returns the user I belong to
description: This endpoint is deprecated and always fails. Use GET /api/v2/users/me
instead.
operationId: GetMyUserDeprecated
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/TypesDeprecatedUser'
status:
type: string
required:
- status
- data
type: object
description: OK
"401":
content:
@@ -14513,6 +14225,12 @@ paths:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
"501":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Implemented
security:
- tokenizer: []
summary: Get my user
@@ -23762,108 +23480,6 @@ paths:
summary: Get user roles
tags:
- users
post:
deprecated: true
description: This endpoint assigns the role to the user roles by user id
operationId: SetRoleByUserID
parameters:
- in: path
name: id
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TypesPostableRole'
responses:
"200":
description: OK
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Set user roles
tags:
- users
/api/v2/users/{id}/roles/{roleId}:
delete:
deprecated: true
description: This endpoint removes a role from the user by user id and role
id
operationId: RemoveUserRoleByUserIDAndRoleID
parameters:
- in: path
name: id
required: true
schema:
type: string
- in: path
name: roleId
required: true
schema:
type: string
responses:
"204":
description: No Content
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Remove a role from user
tags:
- users
/api/v2/users/me:
get:
deprecated: false

View File

@@ -9934,47 +9934,6 @@ export interface TypesChangePasswordRequestDTO {
oldPassword?: string;
}
export interface TypesDeprecatedUserDTO {
/**
* @type string
* @format date-time
*/
createdAt?: string;
/**
* @type string
*/
displayName?: string;
/**
* @type string
*/
email?: string;
/**
* @type string
*/
id: string;
/**
* @type boolean
*/
isRoot?: boolean;
/**
* @type string
*/
orgId?: string;
/**
* @type string
*/
role?: string;
/**
* @type string
*/
status?: string;
/**
* @type string
* @format date-time
*/
updatedAt?: string;
}
export interface TypesIdentifiableDTO {
/**
* @type string
@@ -9982,47 +9941,6 @@ export interface TypesIdentifiableDTO {
id: string;
}
export interface TypesInviteDTO {
/**
* @type string
* @format date-time
*/
createdAt?: string;
/**
* @type string
*/
email?: string;
/**
* @type string
*/
id: string;
/**
* @type string
*/
inviteLink?: string;
/**
* @type string
*/
name?: string;
/**
* @type string
*/
orgId?: string;
/**
* @type string
*/
role?: string;
/**
* @type string
*/
token?: string;
/**
* @type string
* @format date-time
*/
updatedAt?: string;
}
export interface TypesOrganizationDTO {
/**
* @type string
@@ -10072,25 +9990,6 @@ export interface TypesPostableForgotPasswordDTO {
orgId: string;
}
export interface TypesPostableInviteDTO {
/**
* @type string
*/
email?: string;
/**
* @type string
*/
frontendBaseUrl?: string;
/**
* @type string
*/
name?: string;
/**
* @type string
*/
role?: string;
}
export interface TypesPostableResetPasswordDTO {
/**
* @type string
@@ -10102,13 +10001,6 @@ export interface TypesPostableResetPasswordDTO {
token?: string;
}
export interface TypesPostableRoleDTO {
/**
* @type string
*/
name: string;
}
export interface TypesPostableVerifyResetPasswordTokenDTO {
/**
* @type string
@@ -10751,17 +10643,6 @@ export type GetFieldsValues200 = {
status: string;
};
export type GetResetPasswordTokenDeprecatedPathParameters = {
id: string;
};
export type GetResetPasswordTokenDeprecated200 = {
data: TypesResetPasswordTokenDTO;
/**
* @type string
*/
status: string;
};
export type GetGlobalConfig200 = {
data: GlobaltypesConfigDTO;
/**
@@ -10770,14 +10651,6 @@ export type GetGlobalConfig200 = {
status: string;
};
export type CreateInvite201 = {
data: TypesInviteDTO;
/**
* @type string
*/
status: string;
};
export type ListLLMPricingRulesParams = {
/**
* @type integer
@@ -11190,25 +11063,6 @@ export type GetTraceAggregations200 = {
status: string;
};
export type ListUsersDeprecated200 = {
/**
* @type array
*/
data: TypesDeprecatedUserDTO[];
/**
* @type string
*/
status: string;
};
export type GetMyUserDeprecated200 = {
data: TypesDeprecatedUserDTO;
/**
* @type string
*/
status: string;
};
export type ListUserPreferences200 = {
/**
* @type array
@@ -12403,13 +12257,6 @@ export type GetRolesByUserID200 = {
status: string;
};
export type SetRoleByUserIDPathParameters = {
id: string;
};
export type RemoveUserRoleByUserIDAndRoleIDPathParameters = {
id: string;
roleId: string;
};
export type GetMyUser200 = {
data: AuthtypesUserWithRolesDTO;
/**

View File

@@ -20,7 +20,6 @@ import type {
import type {
AuthtypesPostableUserDTO,
AuthtypesPostableUserRoleDTO,
CreateInvite201,
CreateResetPasswordToken201,
CreateResetPasswordTokenPathParameters,
CreateUser201,
@@ -28,10 +27,7 @@ import type {
DeleteUserPathParameters,
DeleteUserRolePathParameters,
GetMyUser200,
GetMyUserDeprecated200,
GetResetPasswordToken200,
GetResetPasswordTokenDeprecated200,
GetResetPasswordTokenDeprecatedPathParameters,
GetResetPasswordTokenPathParameters,
GetRolesByUserID200,
GetRolesByUserIDPathParameters,
@@ -42,15 +38,10 @@ import type {
GetUsersByRoleID200,
GetUsersByRoleIDPathParameters,
ListUsers200,
ListUsersDeprecated200,
RemoveUserRoleByUserIDAndRoleIDPathParameters,
RenderErrorResponseDTO,
SetRoleByUserIDPathParameters,
TypesChangePasswordRequestDTO,
TypesPostableForgotPasswordDTO,
TypesPostableInviteDTO,
TypesPostableResetPasswordDTO,
TypesPostableRoleDTO,
TypesPostableVerifyResetPasswordTokenDTO,
TypesUpdatableUserDTO,
UpdateUserPathParameters,
@@ -60,379 +51,12 @@ import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type { ErrorType, BodyType } from '../../../generatedAPIInstance';
/**
* This endpoint returns the reset password token by id
* @deprecated
* @summary Get reset password token
*/
export const getResetPasswordTokenDeprecated = (
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetResetPasswordTokenDeprecated200>({
url: `/api/v1/getResetPasswordToken/${id}`,
method: 'GET',
signal,
});
};
export const getGetResetPasswordTokenDeprecatedQueryKey = ({
id,
}: GetResetPasswordTokenDeprecatedPathParameters) => {
return [`/api/v1/getResetPasswordToken/${id}`] as const;
};
export const getGetResetPasswordTokenDeprecatedQueryOptions = <
TData = Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetResetPasswordTokenDeprecatedQueryKey({ id });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>
> = ({ signal }) => getResetPasswordTokenDeprecated({ id }, signal);
return {
queryKey,
queryFn,
enabled: !!id,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetResetPasswordTokenDeprecatedQueryResult = NonNullable<
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>
>;
export type GetResetPasswordTokenDeprecatedQueryError =
ErrorType<RenderErrorResponseDTO>;
/**
* @deprecated
* @summary Get reset password token
*/
export function useGetResetPasswordTokenDeprecated<
TData = Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetResetPasswordTokenDeprecatedQueryOptions(
{ id },
options,
);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* @deprecated
* @summary Get reset password token
*/
export const invalidateGetResetPasswordTokenDeprecated = async (
queryClient: QueryClient,
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetResetPasswordTokenDeprecatedQueryKey({ id }) },
options,
);
return queryClient;
};
/**
* This endpoint creates an invite for a user
* @deprecated
* @summary Create invite
*/
export const createInvite = (
typesPostableInviteDTO?: BodyType<TypesPostableInviteDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<CreateInvite201>({
url: `/api/v1/invite`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: typesPostableInviteDTO,
signal,
});
};
export const getCreateInviteMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createInvite>>,
TError,
{ data?: BodyType<TypesPostableInviteDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createInvite>>,
TError,
{ data?: BodyType<TypesPostableInviteDTO> },
TContext
> => {
const mutationKey = ['createInvite'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createInvite>>,
{ data?: BodyType<TypesPostableInviteDTO> }
> = (props) => {
const { data } = props ?? {};
return createInvite(data);
};
return { mutationFn, ...mutationOptions };
};
export type CreateInviteMutationResult = NonNullable<
Awaited<ReturnType<typeof createInvite>>
>;
export type CreateInviteMutationBody =
| BodyType<TypesPostableInviteDTO>
| undefined;
export type CreateInviteMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @deprecated
* @summary Create invite
*/
export const useCreateInvite = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createInvite>>,
TError,
{ data?: BodyType<TypesPostableInviteDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createInvite>>,
TError,
{ data?: BodyType<TypesPostableInviteDTO> },
TContext
> => {
return useMutation(getCreateInviteMutationOptions(options));
};
/**
* This endpoint resets the password by token
* @deprecated
* @summary Reset password
*/
export const resetPasswordDeprecated = (
typesPostableResetPasswordDTO?: BodyType<TypesPostableResetPasswordDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/resetPassword`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: typesPostableResetPasswordDTO,
signal,
});
};
export const getResetPasswordDeprecatedMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof resetPasswordDeprecated>>,
TError,
{ data?: BodyType<TypesPostableResetPasswordDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof resetPasswordDeprecated>>,
TError,
{ data?: BodyType<TypesPostableResetPasswordDTO> },
TContext
> => {
const mutationKey = ['resetPasswordDeprecated'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof resetPasswordDeprecated>>,
{ data?: BodyType<TypesPostableResetPasswordDTO> }
> = (props) => {
const { data } = props ?? {};
return resetPasswordDeprecated(data);
};
return { mutationFn, ...mutationOptions };
};
export type ResetPasswordDeprecatedMutationResult = NonNullable<
Awaited<ReturnType<typeof resetPasswordDeprecated>>
>;
export type ResetPasswordDeprecatedMutationBody =
| BodyType<TypesPostableResetPasswordDTO>
| undefined;
export type ResetPasswordDeprecatedMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @deprecated
* @summary Reset password
*/
export const useResetPasswordDeprecated = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof resetPasswordDeprecated>>,
TError,
{ data?: BodyType<TypesPostableResetPasswordDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof resetPasswordDeprecated>>,
TError,
{ data?: BodyType<TypesPostableResetPasswordDTO> },
TContext
> => {
return useMutation(getResetPasswordDeprecatedMutationOptions(options));
};
/**
* This endpoint lists all users
* @deprecated
* @summary List users
*/
export const listUsersDeprecated = (signal?: AbortSignal) => {
return GeneratedAPIInstance<ListUsersDeprecated200>({
url: `/api/v1/user`,
method: 'GET',
signal,
});
};
export const getListUsersDeprecatedQueryKey = () => {
return [`/api/v1/user`] as const;
};
export const getListUsersDeprecatedQueryOptions = <
TData = Awaited<ReturnType<typeof listUsersDeprecated>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listUsersDeprecated>>,
TError,
TData
>;
}) => {
const { query: queryOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getListUsersDeprecatedQueryKey();
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listUsersDeprecated>>
> = ({ signal }) => listUsersDeprecated(signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listUsersDeprecated>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListUsersDeprecatedQueryResult = NonNullable<
Awaited<ReturnType<typeof listUsersDeprecated>>
>;
export type ListUsersDeprecatedQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @deprecated
* @summary List users
*/
export function useListUsersDeprecated<
TData = Awaited<ReturnType<typeof listUsersDeprecated>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listUsersDeprecated>>,
TError,
TData
>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListUsersDeprecatedQueryOptions(options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* @deprecated
* @summary List users
*/
export const invalidateListUsersDeprecated = async (
queryClient: QueryClient,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListUsersDeprecatedQueryKey() },
options,
);
return queryClient;
};
/**
* This endpoint returns the user I belong to
* This endpoint is deprecated and always fails. Use GET /api/v2/users/me instead.
* @deprecated
* @summary Get my user
*/
export const getMyUserDeprecated = (signal?: AbortSignal) => {
return GeneratedAPIInstance<GetMyUserDeprecated200>({
return GeneratedAPIInstance<void>({
url: `/api/v1/user/me`,
method: 'GET',
signal,
@@ -1834,189 +1458,6 @@ export const invalidateGetRolesByUserID = async (
return queryClient;
};
/**
* This endpoint assigns the role to the user roles by user id
* @deprecated
* @summary Set user roles
*/
export const setRoleByUserID = (
{ id }: SetRoleByUserIDPathParameters,
typesPostableRoleDTO?: BodyType<TypesPostableRoleDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v2/users/${id}/roles`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: typesPostableRoleDTO,
signal,
});
};
export const getSetRoleByUserIDMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof setRoleByUserID>>,
TError,
{
pathParams: SetRoleByUserIDPathParameters;
data?: BodyType<TypesPostableRoleDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof setRoleByUserID>>,
TError,
{
pathParams: SetRoleByUserIDPathParameters;
data?: BodyType<TypesPostableRoleDTO>;
},
TContext
> => {
const mutationKey = ['setRoleByUserID'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof setRoleByUserID>>,
{
pathParams: SetRoleByUserIDPathParameters;
data?: BodyType<TypesPostableRoleDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return setRoleByUserID(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type SetRoleByUserIDMutationResult = NonNullable<
Awaited<ReturnType<typeof setRoleByUserID>>
>;
export type SetRoleByUserIDMutationBody =
| BodyType<TypesPostableRoleDTO>
| undefined;
export type SetRoleByUserIDMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @deprecated
* @summary Set user roles
*/
export const useSetRoleByUserID = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof setRoleByUserID>>,
TError,
{
pathParams: SetRoleByUserIDPathParameters;
data?: BodyType<TypesPostableRoleDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof setRoleByUserID>>,
TError,
{
pathParams: SetRoleByUserIDPathParameters;
data?: BodyType<TypesPostableRoleDTO>;
},
TContext
> => {
return useMutation(getSetRoleByUserIDMutationOptions(options));
};
/**
* This endpoint removes a role from the user by user id and role id
* @deprecated
* @summary Remove a role from user
*/
export const removeUserRoleByUserIDAndRoleID = (
{ id, roleId }: RemoveUserRoleByUserIDAndRoleIDPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v2/users/${id}/roles/${roleId}`,
method: 'DELETE',
signal,
});
};
export const getRemoveUserRoleByUserIDAndRoleIDMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof removeUserRoleByUserIDAndRoleID>>,
TError,
{ pathParams: RemoveUserRoleByUserIDAndRoleIDPathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof removeUserRoleByUserIDAndRoleID>>,
TError,
{ pathParams: RemoveUserRoleByUserIDAndRoleIDPathParameters },
TContext
> => {
const mutationKey = ['removeUserRoleByUserIDAndRoleID'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof removeUserRoleByUserIDAndRoleID>>,
{ pathParams: RemoveUserRoleByUserIDAndRoleIDPathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return removeUserRoleByUserIDAndRoleID(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type RemoveUserRoleByUserIDAndRoleIDMutationResult = NonNullable<
Awaited<ReturnType<typeof removeUserRoleByUserIDAndRoleID>>
>;
export type RemoveUserRoleByUserIDAndRoleIDMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @deprecated
* @summary Remove a role from user
*/
export const useRemoveUserRoleByUserIDAndRoleID = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof removeUserRoleByUserIDAndRoleID>>,
TError,
{ pathParams: RemoveUserRoleByUserIDAndRoleIDPathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof removeUserRoleByUserIDAndRoleID>>,
TError,
{ pathParams: RemoveUserRoleByUserIDAndRoleIDPathParameters },
TContext
> => {
return useMutation(getRemoveUserRoleByUserIDAndRoleIDMutationOptions(options));
};
/**
* This endpoint returns the user I belong to
* @summary Get my user v2

View File

@@ -10,40 +10,6 @@ import (
)
func (provider *provider) addUserRoutes(router *mux.Router) error {
if err := router.Handle("/api/v1/invite", handler.New(provider.authzMiddleware.AdminAccess(provider.userHandler.CreateInvite), handler.OpenAPIDef{
ID: "CreateInvite",
Tags: []string{"users"},
Summary: "Create invite",
Description: "This endpoint creates an invite for a user",
Request: new(types.PostableInvite),
RequestContentType: "application/json",
Response: new(types.Invite),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusCreated,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusConflict},
Deprecated: true,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
})).Methods(http.MethodPost).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/user", handler.New(provider.authzMiddleware.AdminAccess(provider.userHandler.ListUsersDeprecated), handler.OpenAPIDef{
ID: "ListUsersDeprecated",
Tags: []string{"users"},
Summary: "List users",
Description: "This endpoint lists all users",
Request: nil,
RequestContentType: "",
Response: make([]*types.DeprecatedUser, 0),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{},
Deprecated: true,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
})).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v2/users", handler.New(provider.authzMiddleware.AdminAccess(provider.userHandler.ListUsers), handler.OpenAPIDef{
ID: "ListUsers",
Tags: []string{"users"},
@@ -65,13 +31,13 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
ID: "GetMyUserDeprecated",
Tags: []string{"users"},
Summary: "Get my user",
Description: "This endpoint returns the user I belong to",
Description: "This endpoint is deprecated and always fails. Use GET /api/v2/users/me instead.",
Request: nil,
RequestContentType: "",
Response: new(types.DeprecatedUser),
ResponseContentType: "application/json",
Response: nil,
ResponseContentType: "",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{},
ErrorStatusCodes: []int{http.StatusNotImplemented},
Deprecated: true,
SecuritySchemes: []handler.OpenAPISecurityScheme{{Name: authtypes.IdentNProviderTokenizer.StringValue()}},
})).Methods(http.MethodGet).GetError(); err != nil {
@@ -180,23 +146,6 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
return err
}
if err := router.Handle("/api/v1/getResetPasswordToken/{id}", handler.New(provider.authzMiddleware.AdminAccess(provider.userHandler.GetResetPasswordTokenDeprecated), handler.OpenAPIDef{
ID: "GetResetPasswordTokenDeprecated",
Tags: []string{"users"},
Summary: "Get reset password token",
Description: "This endpoint returns the reset password token by id",
Request: nil,
RequestContentType: "",
Response: new(types.ResetPasswordToken),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
Deprecated: true,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
})).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v2/users/{id}/reset_password_tokens", handler.New(provider.authzMiddleware.AdminAccess(provider.userHandler.GetResetPasswordToken), handler.OpenAPIDef{
ID: "GetResetPasswordToken",
Tags: []string{"users"},
@@ -248,23 +197,6 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
return err
}
if err := router.Handle("/api/v1/resetPassword", handler.New(provider.authzMiddleware.OpenAccess(provider.userHandler.ResetPassword), handler.OpenAPIDef{
ID: "ResetPasswordDeprecated",
Tags: []string{"users"},
Summary: "Reset password",
Description: "This endpoint resets the password by token",
Request: new(types.PostableResetPassword),
RequestContentType: "application/json",
Response: nil,
ResponseContentType: "",
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusConflict},
Deprecated: true,
SecuritySchemes: []handler.OpenAPISecurityScheme{},
})).Methods(http.MethodPost).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v2/users/me/factor_password", handler.New(provider.authzMiddleware.OpenAccess(provider.userHandler.ChangePassword), handler.OpenAPIDef{
ID: "UpdateMyPassword",
Tags: []string{"users"},
@@ -333,40 +265,6 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
return err
}
if err := router.Handle("/api/v2/users/{id}/roles", handler.New(provider.authzMiddleware.AdminAccess(provider.userHandler.SetRoleByUserID), handler.OpenAPIDef{
ID: "SetRoleByUserID",
Tags: []string{"users"},
Summary: "Set user roles",
Description: "This endpoint assigns the role to the user roles by user id",
Request: new(types.PostableRole),
RequestContentType: "application/json",
Response: nil,
ResponseContentType: "",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusNotFound},
Deprecated: true,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
})).Methods(http.MethodPost).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v2/users/{id}/roles/{roleId}", handler.New(provider.authzMiddleware.AdminAccess(provider.userHandler.RemoveUserRoleByRoleID), handler.OpenAPIDef{
ID: "RemoveUserRoleByUserIDAndRoleID",
Tags: []string{"users"},
Summary: "Remove a role from user",
Description: "This endpoint removes a role from the user by user id and role id",
Request: nil,
RequestContentType: "",
Response: nil,
ResponseContentType: "",
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{http.StatusNotFound},
Deprecated: true,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
})).Methods(http.MethodDelete).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v2/roles/{id}/users", handler.New(provider.authzMiddleware.AdminAccess(provider.userHandler.GetUsersByRoleID), handler.OpenAPIDef{
ID: "GetUsersByRoleID",
Tags: []string{"users"},

View File

@@ -37,53 +37,6 @@ func (module *getter) GetRootUserByOrgID(ctx context.Context, orgID valuer.UUID)
return rootUser, userRoles, nil
}
func (module *getter) ListDeprecatedUsersByOrgID(ctx context.Context, orgID valuer.UUID) ([]*types.DeprecatedUser, error) {
users, err := module.store.ListUsersByOrgID(ctx, orgID)
if err != nil {
return nil, err
}
// filter root users if feature flag `hide_root_users` is true
evalCtx := featuretypes.NewFlaggerEvaluationContext(orgID)
hideRootUsers := module.flagger.BooleanOrEmpty(ctx, flagger.FeatureHideRootUser, evalCtx)
if hideRootUsers {
users = slices.DeleteFunc(users, func(user *types.User) bool { return user.IsRoot })
}
userIDs := make([]valuer.UUID, len(users))
for idx, user := range users {
userIDs[idx] = user.ID
}
userRoles, err := module.userRoleStore.ListUserRolesByOrgIDAndUserIDs(ctx, orgID, userIDs)
if err != nil {
return nil, err
}
// Build userID → role name mapping directly from the joined Role
userIDToRoleNames := make(map[valuer.UUID][]string)
for _, ur := range userRoles {
if ur.Role != nil {
userIDToRoleNames[ur.UserID] = append(userIDToRoleNames[ur.UserID], ur.Role.Name)
}
}
deprecatedUsers := make([]*types.DeprecatedUser, 0, len(users))
for _, user := range users {
roleNames := userIDToRoleNames[user.ID]
if len(roleNames) == 0 {
return nil, errors.Newf(errors.TypeInternal, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found for user: %s", user.ID.String())
}
role := authtypes.SigNozManagedRoleToExistingLegacyRole[roleNames[0]]
deprecatedUsers = append(deprecatedUsers, types.NewDeprecatedUserFromUserAndRole(user, role))
}
return deprecatedUsers, nil
}
func (module *getter) ListUsersByOrgID(ctx context.Context, orgID valuer.UUID) ([]*types.User, error) {
users, err := module.store.ListUsersByOrgID(ctx, orgID)
if err != nil {
@@ -101,58 +54,10 @@ func (module *getter) ListUsersByOrgID(ctx context.Context, orgID valuer.UUID) (
return users, nil
}
func (module *getter) GetDeprecatedUserByOrgIDAndID(ctx context.Context, orgID valuer.UUID, id valuer.UUID) (*types.DeprecatedUser, error) {
user, err := module.store.GetByOrgIDAndID(ctx, orgID, id)
if err != nil {
return nil, err
}
userRoles, err := module.GetRolesByUserID(ctx, id)
if err != nil {
return nil, err
}
if len(userRoles) == 0 {
return nil, errors.New(errors.TypeInternal, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found")
}
if userRoles[0].Role == nil {
return nil, errors.New(errors.TypeInternal, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
}
role := authtypes.SigNozManagedRoleToExistingLegacyRole[userRoles[0].Role.Name]
return types.NewDeprecatedUserFromUserAndRole(user, role), nil
}
func (module *getter) GetUserByOrgIDAndID(ctx context.Context, orgID valuer.UUID, userID valuer.UUID) (*types.User, error) {
return module.store.GetByOrgIDAndID(ctx, orgID, userID)
}
func (module *getter) Get(ctx context.Context, id valuer.UUID) (*types.DeprecatedUser, error) {
user, err := module.store.GetUser(ctx, id)
if err != nil {
return nil, err
}
userRoles, err := module.GetRolesByUserID(ctx, id)
if err != nil {
return nil, err
}
if len(userRoles) == 0 {
return nil, errors.New(errors.TypeInternal, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found")
}
if userRoles[0].Role == nil {
return nil, errors.New(errors.TypeInternal, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
}
role := authtypes.SigNozManagedRoleToExistingLegacyRole[userRoles[0].Role.Name]
return types.NewDeprecatedUserFromUserAndRole(user, role), nil
}
func (module *getter) ListUsersByEmailAndOrgIDs(ctx context.Context, email valuer.Email, orgIDs []valuer.UUID) ([]*types.User, error) {
return module.store.ListUsersByEmailAndOrgIDs(ctx, email, orgIDs)
}

View File

@@ -61,33 +61,6 @@ func (handler *handler) CreateUser(rw http.ResponseWriter, r *http.Request) {
render.Success(rw, http.StatusCreated, types.Identifiable{ID: user.ID})
}
func (handler *handler) CreateInvite(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
var req types.PostableInvite
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
render.Error(rw, err)
return
}
invites, err := handler.setter.CreateBulkInvite(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.IdentityID()), valuer.MustNewEmail(claims.Email), &types.PostableBulkInviteRequest{
Invites: []types.PostableInvite{req},
})
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusCreated, invites[0])
}
func (handler *handler) GetUser(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
@@ -121,22 +94,8 @@ func (handler *handler) GetUser(w http.ResponseWriter, r *http.Request) {
}
func (handler *handler) GetMyUserDeprecated(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(w, err)
return
}
user, err := handler.getter.GetDeprecatedUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.UserID))
if err != nil {
render.Error(w, err)
return
}
render.Success(w, http.StatusOK, user)
render.Error(w, errors.New(errors.TypeUnsupported, types.ErrCodeUserDeprecated,
"the v1 user API is deprecated; instead, get your user with GET /api/v2/users/me"))
}
func (handler *handler) GetMyUser(w http.ResponseWriter, r *http.Request) {
@@ -194,25 +153,6 @@ func (handler *handler) UpdateMyUser(w http.ResponseWriter, r *http.Request) {
render.Success(w, http.StatusNoContent, nil)
}
func (handler *handler) ListUsersDeprecated(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(w, err)
return
}
users, err := handler.getter.ListDeprecatedUsersByOrgID(ctx, valuer.MustNewUUID(claims.OrgID))
if err != nil {
render.Error(w, err)
return
}
render.Success(w, http.StatusOK, users)
}
func (handler *handler) ListUsers(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
@@ -284,33 +224,6 @@ func (handler *handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
render.Success(w, http.StatusNoContent, nil)
}
func (handler *handler) GetResetPasswordTokenDeprecated(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
id := mux.Vars(r)["id"]
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(w, err)
return
}
user, err := handler.getter.GetDeprecatedUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(id))
if err != nil {
render.Error(w, err)
return
}
token, err := handler.setter.GetOrCreateResetPasswordToken(ctx, user.ID)
if err != nil {
render.Error(w, err)
return
}
render.Success(w, http.StatusOK, token)
}
func (handler *handler) GetResetPasswordToken(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
@@ -481,68 +394,6 @@ func (handler *handler) GetRolesByUserID(w http.ResponseWriter, r *http.Request)
render.Success(w, http.StatusOK, roles)
}
func (handler *handler) SetRoleByUserID(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
userID := mux.Vars(r)["id"]
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(w, err)
return
}
if userID == claims.UserID {
render.Error(w, errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "users cannot call this api on self"))
return
}
postableRole := new(types.PostableRole)
if err := json.NewDecoder(r.Body).Decode(postableRole); err != nil {
render.Error(w, err)
return
}
if postableRole.Name == "" {
render.Error(w, errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "role name is required"))
return
}
if _, err := handler.setter.AddUserRole(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID), postableRole.Name); err != nil {
render.Error(w, err)
return
}
render.Success(w, http.StatusOK, nil)
}
func (handler *handler) RemoveUserRoleByRoleID(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
userID := mux.Vars(r)["id"]
roleID := mux.Vars(r)["roleId"]
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(w, err)
return
}
if userID == claims.UserID {
render.Error(w, errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "users cannot call this api on self"))
return
}
if err := handler.setter.RemoveUserRole(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID), valuer.MustNewUUID(roleID)); err != nil {
render.Error(w, err)
return
}
render.Success(w, http.StatusNoContent, nil)
}
func (handler *handler) GetUsersByRoleID(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()

View File

@@ -55,119 +55,6 @@ func NewSetter(store types.UserStore, tokenizer tokenizer.Tokenizer, emailing em
}
}
// CreateBulk implements invite.Module.
func (module *setter) CreateBulkInvite(ctx context.Context, orgID valuer.UUID, identityID valuer.UUID, identityEmail valuer.Email, bulkInvites *types.PostableBulkInviteRequest) ([]*types.Invite, error) {
// validate all emails to be invited
emails := make([]string, len(bulkInvites.Invites))
for idx, invite := range bulkInvites.Invites {
emails[idx] = invite.Email.StringValue()
}
users, err := module.store.GetUsersByEmailsOrgIDAndStatuses(ctx, orgID, emails, []string{types.UserStatusActive.StringValue(), types.UserStatusPendingInvite.StringValue()})
if err != nil {
return nil, err
}
if len(users) > 0 {
if err := users[0].ErrIfRoot(); err != nil {
return nil, errors.WithAdditionalf(err, "Cannot send invite to root user")
}
if users[0].Status == types.UserStatusPendingInvite {
return nil, errors.Newf(errors.TypeAlreadyExists, errors.CodeAlreadyExists, "An invite already exists for this email: %s", users[0].Email.StringValue())
}
return nil, errors.Newf(errors.TypeAlreadyExists, errors.CodeAlreadyExists, "User already exists with this email: %s", users[0].Email.StringValue())
}
type userWithResetToken struct {
User *types.User
ResetPasswordToken *types.ResetPasswordToken
Role types.Role
}
newUsersWithResetToken := make([]*userWithResetToken, len(bulkInvites.Invites))
if err := module.store.RunInTx(ctx, func(ctx context.Context) error {
for idx, invite := range bulkInvites.Invites {
// create a new user with pending invite status
newUser, err := types.NewUser(invite.Name, invite.Email, orgID, types.UserStatusPendingInvite)
if err != nil {
return err
}
// store the user and password in db
err = module.createUserWithoutGrant(ctx, newUser, root.WithRoleNames([]string{authtypes.MustGetSigNozManagedRoleFromExistingRole(invite.Role)}))
if err != nil {
return err
}
// generate reset password token
resetPasswordToken, err := module.GetOrCreateResetPasswordToken(ctx, newUser.ID)
if err != nil {
module.settings.Logger().ErrorContext(ctx, "failed to create reset password token for invited user", errors.Attr(err))
return err
}
newUsersWithResetToken[idx] = &userWithResetToken{
User: newUser,
ResetPasswordToken: resetPasswordToken,
Role: invite.Role,
}
}
return nil
}); err != nil {
return nil, err
}
invites := make([]*types.Invite, len(bulkInvites.Invites))
// send password reset emails to all the invited users
for idx, userWithToken := range newUsersWithResetToken {
module.analytics.TrackUser(ctx, orgID.String(), identityID.String(), "Invite Sent", map[string]any{
"invitee_email": userWithToken.User.Email,
"invitee_role": userWithToken.Role,
})
invite := &types.Invite{
Identifiable: types.Identifiable{
ID: userWithToken.User.ID,
},
Name: userWithToken.User.DisplayName,
Email: userWithToken.User.Email,
Token: userWithToken.ResetPasswordToken.Token,
Role: userWithToken.Role,
OrgID: userWithToken.User.OrgID,
TimeAuditable: types.TimeAuditable{
CreatedAt: userWithToken.User.CreatedAt,
UpdatedAt: userWithToken.User.UpdatedAt,
},
}
invites[idx] = invite
frontendBaseUrl := bulkInvites.Invites[idx].FrontendBaseUrl
if frontendBaseUrl == "" {
module.settings.Logger().InfoContext(ctx, "frontend base url is not provided, skipping email", slog.Any("invitee_email", userWithToken.User.Email))
continue
}
resetLink := userWithToken.ResetPasswordToken.FactorPasswordResetLink(frontendBaseUrl)
tokenLifetime := module.config.Password.Invite.MaxTokenLifetime
humanizedTokenLifetime := strings.TrimSpace(humanize.RelTime(time.Now(), time.Now().Add(tokenLifetime), "", ""))
if err := module.emailing.SendHTML(ctx, userWithToken.User.Email.String(), "You're Invited to Join SigNoz", emailtypes.TemplateNameInvitationEmail, map[string]any{
"inviter_email": identityEmail.StringValue(),
"link": resetLink,
"Expiry": humanizedTokenLifetime,
}); err != nil {
module.settings.Logger().ErrorContext(ctx, "failed to send invite email", errors.Attr(err))
}
}
return invites, nil
}
func (module *setter) CreateUser(ctx context.Context, user *types.User, opts ...root.CreateUserOption) error {
createUserOpts := root.NewCreateUserOptions(opts...)

View File

@@ -7,7 +7,6 @@ import (
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/uptrace/bun"
)
type userRoleStore struct {
@@ -19,26 +18,6 @@ func NewUserRoleStore(sqlstore sqlstore.SQLStore, settings factory.ProviderSetti
return &userRoleStore{sqlstore: sqlstore, settings: settings}
}
func (store *userRoleStore) ListUserRolesByOrgIDAndUserIDs(ctx context.Context, orgID valuer.UUID, userIDs []valuer.UUID) ([]*authtypes.UserRole, error) {
userRoles := make([]*authtypes.UserRole, 0)
err := store.sqlstore.
BunDBCtx(ctx).
NewSelect().
Model(&userRoles).
Join("JOIN users").
JoinOn("users.id = user_role.user_id").
Where("users.org_id = ?", orgID).
Where("users.id IN (?)", bun.In(userIDs)).
Relation("Role").
Scan(ctx)
if err != nil {
return nil, err
}
return userRoles, nil
}
func (store *userRoleStore) GetUserRoleByOrgIDAndID(ctx context.Context, orgID valuer.UUID, id valuer.UUID) (*authtypes.UserRole, error) {
userRole := new(authtypes.UserRole)

View File

@@ -40,9 +40,6 @@ type Setter interface {
UpdateAnyUser(ctx context.Context, orgID valuer.UUID, user *types.User) error
DeleteUser(ctx context.Context, orgID valuer.UUID, id string, deletedBy string) error
// invite
CreateBulkInvite(ctx context.Context, orgID valuer.UUID, identityID valuer.UUID, identityEmail valuer.Email, bulkInvites *types.PostableBulkInviteRequest) ([]*types.Invite, error)
// Creates a pending invite user with the roles given via opts and emails them the invite link.
CreatePendingInviteUser(ctx context.Context, identityID valuer.UUID, identityEmail valuer.Email, frontendBaseURL string, user *types.User, opts ...CreateUserOption) (*types.User, error)
@@ -60,16 +57,11 @@ type Getter interface {
GetRootUserByOrgID(context.Context, valuer.UUID) (*types.User, []*authtypes.UserRole, error)
// Get gets the users based on the given org id
ListDeprecatedUsersByOrgID(context.Context, valuer.UUID) ([]*types.DeprecatedUser, error)
ListUsersByOrgID(ctx context.Context, orgID valuer.UUID) ([]*types.User, error)
// Get deprecated user object by orgID and id.
GetDeprecatedUserByOrgIDAndID(context.Context, valuer.UUID, valuer.UUID) (*types.DeprecatedUser, error)
// Get user by orgID and id.
GetUserByOrgIDAndID(ctx context.Context, orgID valuer.UUID, userID valuer.UUID) (*types.User, error)
// Get user by id.
Get(context.Context, valuer.UUID) (*types.DeprecatedUser, error)
// List users by email and org ids.
ListUsersByEmailAndOrgIDs(context.Context, valuer.Email, []valuer.UUID) ([]*types.User, error)
@@ -105,11 +97,7 @@ type Getter interface {
}
type Handler interface {
// invite
CreateInvite(http.ResponseWriter, *http.Request)
// users
ListUsersDeprecated(http.ResponseWriter, *http.Request)
ListUsers(http.ResponseWriter, *http.Request)
CreateUser(http.ResponseWriter, *http.Request)
UpdateUser(http.ResponseWriter, *http.Request)
@@ -119,8 +107,6 @@ type Handler interface {
GetMyUser(http.ResponseWriter, *http.Request)
UpdateMyUser(http.ResponseWriter, *http.Request)
GetRolesByUserID(http.ResponseWriter, *http.Request)
SetRoleByUserID(http.ResponseWriter, *http.Request)
RemoveUserRoleByRoleID(http.ResponseWriter, *http.Request)
GetUsersByRoleID(http.ResponseWriter, *http.Request)
// user roles
@@ -129,7 +115,6 @@ type Handler interface {
DeleteUserRole(http.ResponseWriter, *http.Request)
// Reset Password
GetResetPasswordTokenDeprecated(http.ResponseWriter, *http.Request)
GetResetPasswordToken(http.ResponseWriter, *http.Request)
CreateResetPasswordToken(http.ResponseWriter, *http.Request)
VerifyResetPasswordToken(http.ResponseWriter, *http.Request)

View File

@@ -53,12 +53,6 @@ var (
types.RoleEditor: SigNozEditorRoleName,
types.RoleViewer: SigNozViewerRoleName,
}
SigNozManagedRoleToExistingLegacyRole = map[string]types.Role{
SigNozAdminRoleName: types.RoleAdmin,
SigNozEditorRoleName: types.RoleEditor,
SigNozViewerRoleName: types.RoleViewer,
}
)
type Role struct {

View File

@@ -119,9 +119,6 @@ type UserRoleStore interface {
// get a single user role entry by org id and its own id
GetUserRoleByOrgIDAndID(ctx context.Context, orgID valuer.UUID, id valuer.UUID) (*UserRole, error)
// list all user_role entries for
ListUserRolesByOrgIDAndUserIDs(ctx context.Context, orgID valuer.UUID, userIDs []valuer.UUID) ([]*UserRole, error)
// delete user role entries by user id
DeleteUserRoles(ctx context.Context, userID valuer.UUID) error

View File

@@ -1,83 +0,0 @@
package types
import (
"encoding/json"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/uptrace/bun"
)
var (
ErrInviteAlreadyExists = errors.MustNewCode("invite_already_exists")
ErrInviteNotFound = errors.MustNewCode("invite_not_found")
)
type GettableInvite = Invite
type Invite struct {
bun.BaseModel `bun:"table:user_invite"`
Identifiable
TimeAuditable
Name string `bun:"name,type:text" json:"name"`
Email valuer.Email `bun:"email,type:text" json:"email"`
Token string `bun:"token,type:text" json:"token"`
Role Role `bun:"role,type:text" json:"role"`
OrgID valuer.UUID `bun:"org_id,type:text" json:"orgId"`
InviteLink string `bun:"-" json:"inviteLink"`
}
type PostableInvite struct {
Name string `json:"name"`
Email valuer.Email `json:"email"`
Role Role `json:"role"`
FrontendBaseUrl string `json:"frontendBaseUrl"`
}
type PostableBulkInviteRequest struct {
Invites []PostableInvite `json:"invites" required:"true" nullable:"false"`
}
func (request *PostableBulkInviteRequest) UnmarshalJSON(data []byte) error {
type Alias PostableBulkInviteRequest
var temp Alias
if err := json.Unmarshal(data, &temp); err != nil {
return err
}
// check for duplicate emails in the same request
seen := make(map[string]struct{}, len(temp.Invites))
for _, invite := range temp.Invites {
email := invite.Email.StringValue()
if _, exists := seen[email]; exists {
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "Duplicate email in request: %s", email)
}
seen[email] = struct{}{}
}
*request = PostableBulkInviteRequest(temp)
return nil
}
func NewInvite(name string, role Role, orgID valuer.UUID, email valuer.Email) (*Invite, error) {
invite := &Invite{
Identifiable: Identifiable{
ID: valuer.GenerateUUID(),
},
Name: name,
Email: email,
Token: valuer.GenerateUUID().String(),
Role: role,
OrgID: orgID,
TimeAuditable: TimeAuditable{
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
},
}
return invite, nil
}

View File

@@ -25,6 +25,7 @@ var (
ErrCodeUserStatusDeleted = errors.MustNewCode("user_status_deleted")
ErrCodeUserStatusPendingInvite = errors.MustNewCode("user_status_pending_invite")
ErrCodeUserStatusNotPendingInvite = errors.MustNewCode("user_status_not_pending_invite")
ErrCodeUserDeprecated = errors.MustNewCode("user_deprecated")
)
var (
@@ -46,19 +47,10 @@ type User struct {
TimeAuditable
}
type DeprecatedUser struct {
*User
Role Role `json:"role"`
}
type UpdatableUser struct {
DisplayName string `json:"displayName" required:"true"`
}
type PostableRole struct {
Name string `json:"name" required:"true"`
}
type PostableRegisterOrgAndAdmin struct {
Name string `json:"name"`
Email valuer.Email `json:"email"`
@@ -121,13 +113,6 @@ func NewRootUser(displayName string, email valuer.Email, orgID valuer.UUID) (*Us
}, nil
}
func NewDeprecatedUserFromUserAndRole(user *User, role Role) *DeprecatedUser {
return &DeprecatedUser{
user,
role,
}
}
// Update applies mutable fields from the input to the user. Immutable fields
// (email, is_root, org_id, id) are preserved. Only non-zero input fields are applied.
func (u *User) Update(displayName string) {

View File

@@ -583,15 +583,15 @@ def test_dashboard_authz_cleanup(
actor = find_user_by_email(signoz, admin_token, _ACTOR_EMAIL)
response = requests.get(
signoz.self.host_configs["8080"].get(f"/api/v2/users/{actor['id']}/roles"),
signoz.self.host_configs["8080"].get(f"/api/v2/users/{actor['id']}"),
headers={"Authorization": f"Bearer {admin_token}"},
timeout=5,
)
assert response.status_code == HTTPStatus.OK, response.text
actor_entry = next((role for role in response.json()["data"] if role["name"] == _ACTOR_ROLE_NAME), None)
actor_entry = next((ur for ur in response.json()["data"]["userRoles"] if ur["role"]["name"] == _ACTOR_ROLE_NAME), None)
if actor_entry is not None:
response = requests.delete(
signoz.self.host_configs["8080"].get(f"/api/v2/users/{actor['id']}/roles/{actor_entry['id']}"),
signoz.self.host_configs["8080"].get(f"/api/v2/user_roles/{actor_entry['id']}"),
headers={"Authorization": f"Bearer {admin_token}"},
timeout=5,
)

View File

@@ -260,12 +260,12 @@ def test_role_fga_cleanup(
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
user = find_user_by_email(signoz, admin_token, _ACTOR_USER_EMAIL)
resp = requests.get(signoz.self.host_configs["8080"].get(f"/api/v2/users/{user['id']}/roles"), headers={"Authorization": f"Bearer {admin_token}"}, timeout=5)
resp = requests.get(signoz.self.host_configs["8080"].get(f"/api/v2/users/{user['id']}"), headers={"Authorization": f"Bearer {admin_token}"}, timeout=5)
assert resp.status_code == HTTPStatus.OK, resp.text
actor_entry = next((r for r in resp.json()["data"] if r["name"] == _ACTOR_ROLE_NAME), None)
actor_entry = next((ur for ur in resp.json()["data"]["userRoles"] if ur["role"]["name"] == _ACTOR_ROLE_NAME), None)
if actor_entry is not None:
resp = requests.delete(
signoz.self.host_configs["8080"].get(f"/api/v2/users/{user['id']}/roles/{actor_entry['id']}"),
signoz.self.host_configs["8080"].get(f"/api/v2/user_roles/{actor_entry['id']}"),
headers={"Authorization": f"Bearer {admin_token}"},
timeout=5,
)

View File

@@ -319,12 +319,12 @@ def test_saved_view_fga_cleanup(
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
user = find_user_by_email(signoz, admin_token, _SAVED_VIEW_FGA_CUSTOM_USER_EMAIL)
resp = requests.get(signoz.self.host_configs["8080"].get(f"/api/v2/users/{user['id']}/roles"), headers={"Authorization": f"Bearer {admin_token}"}, timeout=5)
resp = requests.get(signoz.self.host_configs["8080"].get(f"/api/v2/users/{user['id']}"), headers={"Authorization": f"Bearer {admin_token}"}, timeout=5)
assert resp.status_code == HTTPStatus.OK, resp.text
custom_entry = next((r for r in resp.json()["data"] if r["name"] == _SAVED_VIEW_FGA_CUSTOM_ROLE_NAME), None)
custom_entry = next((ur for ur in resp.json()["data"]["userRoles"] if ur["role"]["name"] == _SAVED_VIEW_FGA_CUSTOM_ROLE_NAME), None)
if custom_entry is not None:
resp = requests.delete(
signoz.self.host_configs["8080"].get(f"/api/v2/users/{user['id']}/roles/{custom_entry['id']}"),
signoz.self.host_configs["8080"].get(f"/api/v2/user_roles/{custom_entry['id']}"),
headers={"Authorization": f"Bearer {admin_token}"},
timeout=5,
)

View File

@@ -285,12 +285,12 @@ def test_delete_custom_role_cleanup(
role_id = find_role_by_name(signoz, admin_token, _SA_FGA_CUSTOM_ROLE_NAME)
user = find_user_by_email(signoz, admin_token, _SA_FGA_CUSTOM_USER_EMAIL)
resp = requests.get(signoz.self.host_configs["8080"].get(f"/api/v2/users/{user['id']}/roles"), headers={"Authorization": f"Bearer {admin_token}"}, timeout=5)
resp = requests.get(signoz.self.host_configs["8080"].get(f"/api/v2/users/{user['id']}"), headers={"Authorization": f"Bearer {admin_token}"}, timeout=5)
assert resp.status_code == HTTPStatus.OK, resp.text
custom_entry = next((r for r in resp.json()["data"] if r["name"] == _SA_FGA_CUSTOM_ROLE_NAME), None)
custom_entry = next((ur for ur in resp.json()["data"]["userRoles"] if ur["role"]["name"] == _SA_FGA_CUSTOM_ROLE_NAME), None)
if custom_entry is not None:
resp = requests.delete(
signoz.self.host_configs["8080"].get(f"/api/v2/users/{user['id']}/roles/{custom_entry['id']}"),
signoz.self.host_configs["8080"].get(f"/api/v2/user_roles/{custom_entry['id']}"),
headers={"Authorization": f"Bearer {admin_token}"},
timeout=5,
)