Skip to content

Commit 173b0b8

Browse files
authored
Merge pull request #288 from weaviate/feat/new-user-fields
feat(v1.30.1): retrieve users' last login time and preview API keys
2 parents d9dc910 + 9df0dca commit 173b0b8

File tree

6 files changed

+220
-38
lines changed

6 files changed

+220
-38
lines changed

.github/workflows/main.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ env:
1313
WEAVIATE_127: 1.27.15
1414
WEAVIATE_128: 1.28.11
1515
WEAVIATE_129: 1.29.1
16-
WEAVIATE_130: 1.30.0
16+
WEAVIATE_130: 1.30.1
1717

1818
concurrency:
1919
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}

src/openapi/schema.ts

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ export interface paths {
4343
'/replication/replicate': {
4444
post: operations['replicate'];
4545
};
46+
'/replication/replicate/{id}': {
47+
/** Returns the details of a replication operation for a given shard, identified by the provided replication operation id. */
48+
get: operations['replicationDetails'];
49+
};
4650
'/users/own-info': {
4751
get: operations['getOwnInfo'];
4852
};
@@ -286,6 +290,18 @@ export interface definitions {
286290
dbUserType: 'db_user' | 'db_env_user';
287291
/** @description activity status of the returned user */
288292
active: boolean;
293+
/**
294+
* Format: date-time
295+
* @description Date and time in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)
296+
*/
297+
createdAt?: unknown;
298+
/** @description First 3 letters of the associated API-key */
299+
apiKeyFirstLetters?: unknown;
300+
/**
301+
* Format: date-time
302+
* @description Date and time in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)
303+
*/
304+
lastUsedAt?: unknown;
289305
};
290306
UserApiKey: {
291307
/** @description The apikey */
@@ -568,6 +584,8 @@ export interface definitions {
568584
indexNullState?: boolean;
569585
/** @description Index length of properties (default: 'false'). */
570586
indexPropertyLength?: boolean;
587+
/** @description Using BlockMax WAND for query execution (default: 'false', will be 'true' for new collections created after 1.30). */
588+
usingBlockMaxWAND?: boolean;
571589
};
572590
/** @description Configure how replication is executed in a cluster */
573591
ReplicationConfig: {
@@ -689,6 +707,29 @@ export interface definitions {
689707
/** @description The shard id holding the replica to be deleted */
690708
shardId: string;
691709
};
710+
/** @description The current status and details of a replication operation, including information about the resources involved in the replication process. */
711+
ReplicationReplicateDetailsReplicaResponse: {
712+
/** @description The unique id of the replication operation. */
713+
id: string;
714+
/** @description The id of the shard to collect replication details for. */
715+
shardId: string;
716+
/** @description The name of the collection holding data being replicated. */
717+
collection: string;
718+
/** @description The id of the node where the source replica is allocated. */
719+
sourceNodeId: string;
720+
/** @description The id of the node where the target replica is allocated. */
721+
targetNodeId: string;
722+
/**
723+
* @description The current status of the replication operation, indicating the replication phase the operation is in.
724+
* @enum {string}
725+
*/
726+
status:
727+
| 'READY'
728+
| 'INDEXING'
729+
| 'REPLICATION_FINALIZING'
730+
| 'REPLICATION_HYDRATING'
731+
| 'REPLICATION_DEHYDRATING';
732+
};
692733
/** @description A single peer in the network. */
693734
PeerUpdate: {
694735
/**
@@ -1728,6 +1769,37 @@ export interface operations {
17281769
};
17291770
};
17301771
};
1772+
/** Returns the details of a replication operation for a given shard, identified by the provided replication operation id. */
1773+
replicationDetails: {
1774+
parameters: {
1775+
path: {
1776+
/** The replication operation id to get details for. */
1777+
id: string;
1778+
};
1779+
};
1780+
responses: {
1781+
/** The details of the replication operation. */
1782+
200: {
1783+
schema: definitions['ReplicationReplicateDetailsReplicaResponse'];
1784+
};
1785+
/** Malformed request. */
1786+
400: {
1787+
schema: definitions['ErrorResponse'];
1788+
};
1789+
/** Unauthorized or invalid credentials. */
1790+
401: unknown;
1791+
/** Forbidden */
1792+
403: {
1793+
schema: definitions['ErrorResponse'];
1794+
};
1795+
/** Shard replica operation not found */
1796+
404: unknown;
1797+
/** An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error. */
1798+
500: {
1799+
schema: definitions['ErrorResponse'];
1800+
};
1801+
};
1802+
};
17311803
getOwnInfo: {
17321804
responses: {
17331805
/** Info about the user */
@@ -1743,8 +1815,14 @@ export interface operations {
17431815
};
17441816
};
17451817
listAllUsers: {
1818+
parameters: {
1819+
query: {
1820+
/** Whether to include the last used time of the users */
1821+
includeLastUsedTime?: boolean;
1822+
};
1823+
};
17461824
responses: {
1747-
/** Info about the user */
1825+
/** Info about the users */
17481826
200: {
17491827
schema: definitions['DBUserInfo'][];
17501828
};
@@ -1766,6 +1844,10 @@ export interface operations {
17661844
/** user id */
17671845
user_id: string;
17681846
};
1847+
query: {
1848+
/** Whether to include the last used time of the given user */
1849+
includeLastUsedTime?: boolean;
1850+
};
17691851
};
17701852
responses: {
17711853
/** Info about the user */
@@ -1780,6 +1862,10 @@ export interface operations {
17801862
};
17811863
/** user not found */
17821864
404: unknown;
1865+
/** Request body is well-formed (i.e., syntactically correct), but semantically erroneous. */
1866+
422: {
1867+
schema: definitions['ErrorResponse'];
1868+
};
17831869
/** An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error. */
17841870
500: {
17851871
schema: definitions['ErrorResponse'];

src/roles/util.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ import {
2929
UsersPermission,
3030
} from './types.js';
3131

32+
/** ZERO_TIME is the timestamp Weaviate server sends in abscence of a value (null value). */
33+
const ZERO_TIME = '0001-01-01T00:00:00.000Z';
34+
3235
export class PermissionGuards {
3336
private static includes = <A extends string>(permission: Permission, ...actions: A[]): boolean =>
3437
actions.filter((a) => Array.from<string>(permission.actions).includes(a)).length > 0;
@@ -155,13 +158,18 @@ export class Map {
155158
id: user.userId,
156159
roleNames: user.roles,
157160
active: user.active,
161+
createdAt: Map.unknownDate(user.createdAt),
162+
lastUsedAt: Map.unknownDate(user.lastUsedAt),
163+
apiKeyFirstLetters: user.apiKeyFirstLetters as string,
158164
});
159165
static dbUsers = (users: WeaviateDBUser[]): UserDB[] => users.map(Map.dbUser);
160166
static assignedUsers = (users: WeaviateAssignedUser[]): UserAssignment[] =>
161167
users.map((user) => ({
162168
id: user.userId || '',
163169
userType: user.userType,
164170
}));
171+
static unknownDate = (date?: unknown): Date | undefined =>
172+
date !== undefined && typeof date === 'string' && date !== ZERO_TIME ? new Date(date) : undefined;
165173
}
166174

167175
class PermissionsMapping {

src/users/index.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ import {
88
} from '../openapi/types.js';
99
import { Role } from '../roles/types.js';
1010
import { Map } from '../roles/util.js';
11-
import { AssignRevokeOptions, DeactivateOptions, GetAssignedRolesOptions, User, UserDB } from './types.js';
11+
import {
12+
AssignRevokeOptions,
13+
DeactivateOptions,
14+
GetAssignedRolesOptions,
15+
GetUserOptions,
16+
User,
17+
UserDB,
18+
} from './types.js';
1219

1320
/**
1421
* Operations supported for 'db', 'oidc', and legacy (non-namespaced) users.
@@ -116,14 +123,14 @@ export interface DBUsers extends UsersBase {
116123
* @param {string} userId The ID of the user to get.
117124
* @returns {Promise<UserDB>} ID, status, and assigned roles of a 'db_*' user.
118125
*/
119-
byName: (userId: string) => Promise<UserDB>;
126+
byName: (userId: string, opts?: GetUserOptions) => Promise<UserDB>;
120127

121128
/**
122129
* List all 'db_user' / 'db_env_user' users.
123130
*
124131
* @returns {Promise<UserDB[]>} ID, status, and assigned roles for each 'db_*' user.
125132
*/
126-
listAll: () => Promise<UserDB[]>;
133+
listAll: (opts?: GetUserOptions) => Promise<UserDB[]>;
127134
}
128135

129136
/** Operations supported for namespaced 'oidc' users.*/
@@ -195,8 +202,17 @@ const db = (connection: ConnectionREST): DBUsers => {
195202
.postEmpty<DeactivateOptions | null>(`/users/db/${userId}/deactivate`, opts || null)
196203
.then(() => true)
197204
.catch(expectCode(409)),
198-
byName: (userId: string) => connection.get<WeaviateDBUser>(`/users/db/${userId}`, true).then(Map.dbUser),
199-
listAll: () => connection.get<WeaviateDBUser[]>('/users/db', true).then(Map.dbUsers),
205+
byName: (userId: string, opts?: GetUserOptions) =>
206+
connection
207+
.get<WeaviateDBUser>(
208+
`/users/db/${userId}?includeLastUsedTime=${opts?.includeLastUsedTime || false}`,
209+
true
210+
)
211+
.then(Map.dbUser),
212+
listAll: (opts?: GetUserOptions) =>
213+
connection
214+
.get<WeaviateDBUser[]>(`/users/db?includeLastUsedTime=${opts?.includeLastUsedTime || false}`, true)
215+
.then(Map.dbUsers),
200216
};
201217
};
202218

@@ -238,9 +254,7 @@ const namespacedUsers = (connection: ConnectionREST): NamespacedUsers => {
238254
getAssignedRoles: (userType: UserTypeInternal, userId: string, opts?: GetAssignedRolesOptions) =>
239255
connection
240256
.get<WeaviateRole[]>(
241-
`/authz/users/${userId}/roles/${userType}${
242-
opts?.includePermissions ? '?&includeFullRoles=true' : ''
243-
}`
257+
`/authz/users/${userId}/roles/${userType}?includeFullRoles=${opts?.includePermissions || false}`
244258
)
245259
.then(Map.roles),
246260
assignRoles: (roleNames: string | string[], userId: string, opts?: AssignRevokeOptions) =>

0 commit comments

Comments
 (0)