Skip to content

Commit

Permalink
feat: Add role api keys in UI (#3042)
Browse files Browse the repository at this point in the history
  • Loading branch information
novakzaballa authored Feb 16, 2024
1 parent 0a28ee0 commit b746d09
Show file tree
Hide file tree
Showing 7 changed files with 555 additions and 24 deletions.
13 changes: 12 additions & 1 deletion api/api_keys/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from django.conf import settings
from django.db import models
from django_lifecycle import BEFORE_UPDATE, LifecycleModelMixin, hook
from rest_framework_api_key.models import AbstractAPIKey, APIKeyManager
from softdelete.models import SoftDeleteManager, SoftDeleteObject

Expand All @@ -9,7 +11,7 @@ class MasterAPIKeyManager(APIKeyManager, SoftDeleteManager):
pass


class MasterAPIKey(AbstractAPIKey, SoftDeleteObject):
class MasterAPIKey(AbstractAPIKey, LifecycleModelMixin, SoftDeleteObject):
organisation = models.ForeignKey(
Organisation,
on_delete=models.CASCADE,
Expand All @@ -18,3 +20,12 @@ class MasterAPIKey(AbstractAPIKey, SoftDeleteObject):

objects = MasterAPIKeyManager()
is_admin = models.BooleanField(default=True)

@hook(BEFORE_UPDATE, when="is_admin", was=False, is_now=True)
def delete_role_api_keys(
self,
):
if settings.IS_RBAC_INSTALLED:
from rbac.models import MasterAPIKeyRole

MasterAPIKeyRole.objects.filter(master_api_key=self.id).delete()
130 changes: 130 additions & 0 deletions frontend/common/services/useMasterAPIKeyWithMasterAPIKeyRole.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { Res } from 'common/types/responses'
import { Req } from 'common/types/requests'
import { service } from 'common/service'

export const masterAPIKeyWithMasterAPIKeyRoleService = service
.enhanceEndpoints({
addTagTypes: ['MasterAPIKeyWithMasterAPIKeyRole', 'RoleMasterApiKey'],
})
.injectEndpoints({
endpoints: (builder) => ({
deleteMasterAPIKeyWithMasterAPIKeyRoles: builder.mutation<
Res['masterAPIKeyWithMasterAPIKeyRoles'],
Req['deleteMasterAPIKeyWithMasterAPIKeyRoles']
>({
invalidatesTags: ['MasterAPIKeyWithMasterAPIKeyRole'],
query: (query: Req['deleteMasterAPIKeyWithMasterAPIKeyRoles']) => ({
method: 'DELETE',
url: `organisations/${query.org_id}/master-api-keys/${query.prefix}/roles/${query.role_id}/detach-roles-from-master-api-key/`,
}),
}),
getMasterAPIKeyWithMasterAPIKeyRoles: builder.query<
Res['masterAPIKeyWithMasterAPIKeyRoles'],
Req['getMasterAPIKeyWithMasterAPIKeyRoles']
>({
providesTags: (res) => [
{ id: res?.id, type: 'MasterAPIKeyWithMasterAPIKeyRole' },
],
query: (query: Req['getMasterAPIKeyWithMasterAPIKeyRoles']) => ({
url: `organisations/${query.org_id}/master-api-keys/${query.prefix}/`,
}),
}),
getRolesMasterAPIKeyWithMasterAPIKeyRoles: builder.query<
Res['masterAPIKeyWithMasterAPIKeyRoles'],
Req['getMasterAPIKeyWithMasterAPIKeyRoles']
>({
providesTags: (res) => [
{ id: res?.id, type: 'MasterAPIKeyWithMasterAPIKeyRole' },
],
query: (query: Req['getMasterAPIKeyWithMasterAPIKeyRoles']) => ({
url: `organisations/${query.org_id}/master-api-keys/${query.prefix}/roles/`,
}),
}),
updateMasterAPIKeyWithMasterAPIKeyRoles: builder.mutation<
Res['masterAPIKeyWithMasterAPIKeyRoles'],
Req['updateMasterAPIKeyWithMasterAPIKeyRoles']
>({
invalidatesTags: ['MasterAPIKeyWithMasterAPIKeyRole'],
query: (query: Req['updateMasterAPIKeyWithMasterAPIKeyRoles']) => ({
body: query.body,
method: 'PUT',
url: `organisations/${query.org_id}/master-api-keys/${query.prefix}/`,
}),
}),
// END OF ENDPOINTS
}),
})

export async function getMasterAPIKeyWithMasterAPIKeyRoles(
store: any,
data: Req['getMasterAPIKeyWithMasterAPIKeyRoles'],
options?: Parameters<
typeof masterAPIKeyWithMasterAPIKeyRoleService.endpoints.getMasterAPIKeyWithMasterAPIKeyRoles.initiate
>[1],
) {
return store.dispatch(
masterAPIKeyWithMasterAPIKeyRoleService.endpoints.getMasterAPIKeyWithMasterAPIKeyRoles.initiate(
data,
options,
),
)
}

export async function getRolesMasterAPIKeyWithMasterAPIKeyRoles(
store: any,
data: Req['getMasterAPIKeyWithMasterAPIKeyRoles'],
options?: Parameters<
typeof masterAPIKeyWithMasterAPIKeyRoleService.endpoints.getRolesMasterAPIKeyWithMasterAPIKeyRoles.initiate
>[1],
) {
return store.dispatch(
masterAPIKeyWithMasterAPIKeyRoleService.endpoints.getRolesMasterAPIKeyWithMasterAPIKeyRoles.initiate(
data,
options,
),
)
}

export async function deleteMasterAPIKeyWithMasterAPIKeyRoles(
store: any,
data: Req['getMasterAPIKeyWithMasterAPIKeyRoles'],
options?: Parameters<
typeof masterAPIKeyWithMasterAPIKeyRoleService.endpoints.deleteMasterAPIKeyWithMasterAPIKeyRoles.initiate
>[1],
) {
return store.dispatch(
masterAPIKeyWithMasterAPIKeyRoleService.endpoints.deleteMasterAPIKeyWithMasterAPIKeyRoles.initiate(
data,
options,
),
)
}
export async function updateMasterAPIKeyWithMasterAPIKeyRoles(
store: any,
data: Req['updateMasterAPIKeyWithMasterAPIKeyRoles'],
options?: Parameters<
typeof masterAPIKeyWithMasterAPIKeyRoleService.endpoints.updateMasterAPIKeyWithMasterAPIKeyRoles.initiate
>[1],
) {
return store.dispatch(
masterAPIKeyWithMasterAPIKeyRoleService.endpoints.updateMasterAPIKeyWithMasterAPIKeyRoles.initiate(
data,
options,
),
)
}
// END OF FUNCTION_EXPORTS

export const {
useDeleteMasterAPIKeyWithMasterAPIKeyRolesMutation,
useGetMasterAPIKeyWithMasterAPIKeyRolesQuery,
useGetRolesMasterAPIKeyWithMasterAPIKeyRolesQuery,
useUpdateMasterAPIKeyWithMasterAPIKeyRolesMutation,
// END OF EXPORTS
} = masterAPIKeyWithMasterAPIKeyRoleService

/* Usage examples:
const { data, isLoading } = useGetMasterAPIKeyWithMasterAPIKeyRolesQuery({ id: 2 }, {}) //get hook
const [createMasterAPIKeyWithMasterAPIKeyRoles, { isLoading, data, isSuccess }] = useCreateMasterAPIKeyWithMasterAPIKeyRolesMutation() //create hook
masterAPIKeyWithMasterAPIKeyRoleService.endpoints.getMasterAPIKeyWithMasterAPIKeyRoles.select({id: 2})(store.getState()) //access data from any function
*/
135 changes: 135 additions & 0 deletions frontend/common/services/useRoleMasterApiKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { Res } from 'common/types/responses'
import { Req } from 'common/types/requests'
import { service } from 'common/service'

export const roleMasterApiKeyService = service
.enhanceEndpoints({
addTagTypes: ['RoleMasterApiKey', 'MasterAPIKeyWithMasterAPIKeyRole'],
})
.injectEndpoints({
endpoints: (builder) => ({
createRoleMasterApiKey: builder.mutation<
Res['roleMasterApiKey'],
Req['createRoleMasterApiKey']
>({
invalidatesTags: [
{ id: 'LIST', type: 'RoleMasterApiKey' },
'MasterAPIKeyWithMasterAPIKeyRole',
],
query: (query: Req['createRoleMasterApiKey']) => ({
body: query.body,
method: 'POST',
url: `organisations/${query.org_id}/roles/${query.role_id}/master-api-keys/`,
}),
}),
deleteRoleMasterApiKey: builder.mutation<
Res['roleMasterApiKey'],
Req['deleteRoleMasterApiKey']
>({
invalidatesTags: [
{ id: 'LIST', type: 'RoleMasterApiKey' },
'MasterAPIKeyWithMasterAPIKeyRole',
],
query: (query: Req['deleteRoleMasterApiKey']) => ({
method: 'DELETE',
url: `organisations/${query.org_id}/roles/${query.role_id}/master-api-keys/${query.id}/`,
}),
}),
getRoleMasterApiKey: builder.query<
Res['roleMasterApiKey'],
Req['getRoleMasterApiKey']
>({
providesTags: (res) => [{ id: res?.id, type: 'RoleMasterApiKey' }],
query: (query: Req['getRoleMasterApiKey']) => ({
url: `organisations/${query.org_id}/roles/${query.role_id}/master-api-keys/${query.prefix}/`,
}),
}),
updateRoleMasterApiKey: builder.mutation<
Res['roleMasterApiKey'],
Req['updateRoleMasterApiKey']
>({
invalidatesTags: (res) => [
{ id: 'LIST', type: 'RoleMasterApiKey' },
{ id: res?.id, type: 'RoleMasterApiKey' },
],
query: (query: Req['updateRoleMasterApiKey']) => ({
body: query,
method: 'PUT',
url: `organisations/${query.org_id}/roles/${query.role_id}/master-api-keys/${id}/`,
}),
}),
// END OF ENDPOINTS
}),
})

export async function createRoleMasterApiKey(
store: any,
data: Req['createRoleMasterApiKey'],
options?: Parameters<
typeof roleMasterApiKeyService.endpoints.createRoleMasterApiKey.initiate
>[1],
) {
return store.dispatch(
roleMasterApiKeyService.endpoints.createRoleMasterApiKey.initiate(
data,
options,
),
)
}
export async function deleteRoleMasterApiKey(
store: any,
data: Req['deleteRoleMasterApiKey'],
options?: Parameters<
typeof roleMasterApiKeyService.endpoints.deleteRoleMasterApiKey.initiate
>[1],
) {
return store.dispatch(
roleMasterApiKeyService.endpoints.deleteRoleMasterApiKey.initiate(
data,
options,
),
)
}
export async function getRoleMasterApiKey(
store: any,
data: Req['getRoleMasterApiKey'],
options?: Parameters<
typeof roleMasterApiKeyService.endpoints.getRoleMasterApiKey.initiate
>[1],
) {
return store.dispatch(
roleMasterApiKeyService.endpoints.getRoleMasterApiKey.initiate(
data,
options,
),
)
}
export async function updateRoleMasterApiKey(
store: any,
data: Req['updateRoleMasterApiKey'],
options?: Parameters<
typeof roleMasterApiKeyService.endpoints.updateRoleMasterApiKey.initiate
>[1],
) {
return store.dispatch(
roleMasterApiKeyService.endpoints.updateRoleMasterApiKey.initiate(
data,
options,
),
)
}
// END OF FUNCTION_EXPORTS

export const {
useCreateRoleMasterApiKeyMutation,
useDeleteRoleMasterApiKeyMutation,
useGetRoleMasterApiKeyQuery,
useUpdateRoleMasterApiKeyMutation,
// END OF EXPORTS
} = roleMasterApiKeyService

/* Usage examples:
const { data, isLoading } = useGetRoleMasterApiKeyQuery({ id: 2 }, {}) //get hook
const [createRoleMasterApiKey, { isLoading, data, isSuccess }] = useCreateRoleMasterApiKeyMutation() //create hook
roleMasterApiKeyService.endpoints.getRoleMasterApiKey.select({id: 2})(store.getState()) //access data from any function
*/
11 changes: 11 additions & 0 deletions frontend/common/types/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,17 @@ export type Req = {
getGetSubscriptionMetadata: { id: string }
getEnvironment: { id: string }
getSubscriptionMetadata: { id: string }
getRoleMasterApiKey: { org_id: number; role_id: number; id: string }
updateRoleMasterApiKey: { org_id: number; role_id: number; id: string }
deleteRoleMasterApiKey: { org_id: number; role_id: number; id: string }
createRoleMasterApiKey: { org_id: number; role_id: number }
getMasterAPIKeyWithMasterAPIKeyRoles: { org_id: number; prefix: string }
deleteMasterAPIKeyWithMasterAPIKeyRoles: {
org_id: number
prefix: string
role_id: number
}
getRolesMasterAPIKeyWithMasterAPIKeyRoles: { org_id: number; prefix: string }
createLaunchDarklyProjectImport: {
project_id: string
body: {
Expand Down
7 changes: 7 additions & 0 deletions frontend/common/types/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ export type RolePermissionUser = {
user: number
role: number
id: number
role_name: string
}
export type FeatureVersion = {
created_at: string
Expand Down Expand Up @@ -464,6 +465,12 @@ export type Res = {
environment: Environment
launchDarklyProjectImport: LaunchDarklyProjectImport
launchDarklyProjectsImport: LaunchDarklyProjectImport[]
roleMasterApiKey: { id: number; master_api_key: string; role: number }
masterAPIKeyWithMasterAPIKeyRoles: {
id: string
prefix: string
roles: RolePermissionUser[]
}
userWithRoles: PagedResponse<Role>
groupWithRole: PagedResponse<Role>
changeRequests: PagedResponse<ChangeRequestSummary>
Expand Down
Loading

0 comments on commit b746d09

Please sign in to comment.