Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add delete organization and other removal operation functions #3507

Merged
merged 7 commits into from
Aug 10, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ mutation PopulateApi {
UILocalKubernetesOrganization: addDeployTargetToOrganization(input:{
deployTarget: 2001
organization: 1
})
}) {
id
}

UIProject1: addProject(
input: {
Expand Down
91 changes: 89 additions & 2 deletions services/api/src/models/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ export const Group = (clients: {
type: attributeKVOrNull('type', keycloakGroup),
path: keycloakGroup.path,
attributes: keycloakGroup.attributes,
subGroups: keycloakGroup.subGroups
subGroups: keycloakGroup.subGroups,
organization: parseInt(attributeKVOrNull('lagoon-organization', keycloakGroup)),
})
);

Expand Down Expand Up @@ -784,6 +785,90 @@ export const Group = (clients: {
}
};

// helper to remove project from groups
const removeProjectFromGroups = async (
projectId: number,
groups: Group[]
): Promise<void> => {
for (const g in groups) {
const group = groups[g]
const groupProjectIds = getProjectIdsFromGroup(group)
const newGroupProjects = R.pipe(
R.without([projectId]),
R.uniq,
R.join(',')
// @ts-ignore
)(groupProjectIds);

try {
await keycloakAdminClient.groups.update(
{
id: group.id
},
{
name: group.name,
attributes: {
...group.attributes,
'lagoon-projects': [newGroupProjects],
'group-lagoon-project-ids': [`{${JSON.stringify(group.name)}:[${newGroupProjects}]}`]
}
}
);
} catch (err) {
throw new Error(
`Error setting projects for group ${group.name}: ${err.message}`
);
}
}

// once the project is remove from the groups, update the cache
const allGroups = await loadAllGroups();
const keycloakGroups = await transformKeycloakGroups(allGroups);
const data = Buffer.from(JSON.stringify(keycloakGroups)).toString('base64')
try {
// then attempt to save it to redis
await saveRedisKeycloakCache("allgroups", data);
} catch (err) {
logger.warn(`Couldn't save redis keycloak cache: ${err.message}`);
}
};

// helper to remove all non default-users from project
const removeNonProjectDefaultUsersFromGroup = async (
group: Group,
project: String,
): Promise<Group> => {
const members = await getGroupMembership(group);

for (const u in members) {
if (members[u].user.email != "default-user@"+project) {
try {
await keycloakAdminClient.users.delFromGroup({
// @ts-ignore
id: members[u].user.id,
// @ts-ignore
groupId: members[u].roleSubgroupId
});
} catch (err) {
throw new Error(`Could not remove user from group: ${err.message}`);
}
}
}

// once the users are removed from the group, update the cache
const allGroups = await loadAllGroups();
const keycloakGroups = await transformKeycloakGroups(allGroups);
const data = Buffer.from(JSON.stringify(keycloakGroups)).toString('base64')
try {
// then attempt to save it to redis
await saveRedisKeycloakCache("allgroups", data);
} catch (err) {
logger.warn(`Couldn't save redis keycloak cache: ${err.message}`);
}

return await loadGroupById(group.id);
};

return {
loadAllGroups,
loadGroupById,
Expand All @@ -804,7 +889,9 @@ export const Group = (clients: {
removeUserFromGroup,
addProjectToGroup,
removeProjectFromGroup,
removeProjectFromGroups,
transformKeycloakGroups,
getGroupMembership
getGroupMembership,
removeNonProjectDefaultUsersFromGroup
};
};
6 changes: 6 additions & 0 deletions services/api/src/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,10 @@ const {
addOrganization,
getAllOrganizations,
updateOrganization,
deleteOrganization,
getOrganizationById,
addDeployTargetToOrganization,
removeDeployTargetFromOrganization,
getDeployTargetsByOrganizationId,
getGroupsByOrganizationId,
getUsersByOrganizationId,
Expand All @@ -256,6 +258,7 @@ const {
getOwnersByOrganizationId,
getProjectsByOrganizationId,
addProjectToOrganization,
removeProjectFromOrganization,
addGroupToOrganization,
getGroupsByOrganizationsProject,
getProjectGroupOrganizationAssociation, // WIP resolver
Expand Down Expand Up @@ -684,9 +687,12 @@ const resolvers = {
updateDeployTargetConfig,
addOrganization,
updateOrganization,
deleteOrganization,
addGroupToOrganization,
addProjectToOrganization,
removeProjectFromOrganization,
addDeployTargetToOrganization,
removeDeployTargetFromOrganization,
updateEnvironmentDeployTarget,
},
Subscription: {
Expand Down
42 changes: 42 additions & 0 deletions services/api/src/resources/notification/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,46 @@ export const Helpers = (sqlClientPool: Pool) => ({

return R.map(R.prop('nid'), result);
},
selectNotificationsByProjectId: async (
{ project }: { project: number },
) => {
let input = {pid: project, type: "slack"}
// get all the notifications for the projects
const slacks = await query(
sqlClientPool,
Sql.selectNotificationsByTypeByProjectId(input)
);
input.type = "rocketchat"
const rcs = await query(
sqlClientPool,
Sql.selectNotificationsByTypeByProjectId(input)
);
input.type = "microsoftteams"
const teams = await query(
sqlClientPool,
Sql.selectNotificationsByTypeByProjectId(input)
);
input.type = "email"
const email = await query(
sqlClientPool,
Sql.selectNotificationsByTypeByProjectId(input)
);
input.type = "webhook"
const webhook = await query(
sqlClientPool,
Sql.selectNotificationsByTypeByProjectId(input)
);
let result = [...slacks, ...rcs, ...teams, ...email, ...webhook]

return result
},
removeAllNotificationsFromProject: async (
{ project }: { project: number },
) => {
await query(sqlClientPool, Sql.deleteProjectNotificationByProjectId(project, "slack"));
await query(sqlClientPool, Sql.deleteProjectNotificationByProjectId(project, "rocketchat"));
await query(sqlClientPool, Sql.deleteProjectNotificationByProjectId(project, "microsoftteams"));
await query(sqlClientPool, Sql.deleteProjectNotificationByProjectId(project, "email"));
await query(sqlClientPool, Sql.deleteProjectNotificationByProjectId(project, "webhook"));
},
});
10 changes: 1 addition & 9 deletions services/api/src/resources/notification/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,15 +454,7 @@ export const getNotificationsByOrganizationId: ResolverFn = async (

const results = await Promise.all(
types.map(type =>
query(
sqlClientPool,
Sql.selectNotificationsByTypeByOrganizationId({
type,
oid,
contentType,
notificationSeverityThreshold
})
)
organizationHelpers(sqlClientPool).getNotificationsByTypeForOrganizationId(oid, type)
)
);

Expand Down
16 changes: 16 additions & 0 deletions services/api/src/resources/notification/sql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ export const Sql = {

return deleteQuery.toString();
},
deleteProjectNotificationByProjectId: (id: number, type: string) => {
const deleteQuery = knex.raw(
`DELETE pn
FROM project_notification as pn
LEFT JOIN :notificationTable: AS nt ON pn.nid = nt.id AND pn.type = :notificationType
LEFT JOIN project as p on pn.pid = p.id
WHERE p.id = :pid`,
{
pid: id,
notificationType: type,
notificationTable: `notification_${type}`
}
);

return deleteQuery.toString();
},
selectProjectById: input =>
knex('project')
.select('*')
Expand Down
9 changes: 9 additions & 0 deletions services/api/src/resources/organization/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export const Helpers = (sqlClientPool: Pool) => {
const rows = await query(sqlClientPool, Sql.selectOrganizationEnvironments(id));
return rows;
};
const getNotificationsByTypeForOrganizationId = async (id: number, type: string) => {
let input = {id: id, type: type}
const result = await query(
sqlClientPool,
Sql.selectNotificationsByTypeByOrganizationId(input)
);
return result
};
const getNotificationsForOrganizationId = async (id: number) => {
let input = {id: id, type: "slack"}
// get all the notifications for the projects
Expand Down Expand Up @@ -57,6 +65,7 @@ export const Helpers = (sqlClientPool: Pool) => {
getProjectsByOrganizationId,
getDeployTargetsByOrganizationId,
getNotificationsForOrganizationId,
getNotificationsByTypeForOrganizationId,
getEnvironmentsByOrganizationId,
}
};
Loading