Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
],
"license": "MIT",
"dependencies": {
"axios": "^1.6.8",
"axios": "^1.7.2",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"express": "^4.19.2",
Expand All @@ -49,10 +49,10 @@
"helmet": "^7.1.0",
"jsonwebtoken": "^9.0.2",
"moment": "^2.30.1",
"mongodb": "^6.6.2",
"mongodb": "^6.7.0",
"mongoose": "^8.4.0",
"pino": "^9.1.0",
"pino-pretty": "^11.0.0",
"pino-pretty": "^11.1.0",
"swagger-ui-express": "^5.0.0",
"switcher-client": "^4.1.0",
"validator": "^13.12.0"
Expand All @@ -63,7 +63,7 @@
"jest": "^29.7.0",
"jest-sonar-reporter": "^2.0.0",
"node-notifier": "^10.0.1",
"nodemon": "^3.1.0",
"nodemon": "^3.1.2",
"sinon": "^18.0.0",
"supertest": "^7.0.0"
},
Expand Down
15 changes: 4 additions & 11 deletions src/api-docs/schemas/slack.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { TicketStatusType } from '../../models/slack_ticket.js';

const ticket = {
type: 'object',
properties: {
slack: {
type: 'string',
description: 'The Slack ID'
},
environment: {
type: 'string',
description: 'The environment'
Expand All @@ -23,11 +25,6 @@ const ticket = {
type: 'string',
description: 'The ticket observations'
},
ticket_status: {
type: 'string',
enum: Object.values(TicketStatusType),
default: TicketStatusType.OPENED
},
date_closed: {
type: 'string',
description: 'The date closed'
Expand Down Expand Up @@ -187,10 +184,6 @@ const slack = {
}
}
},
tickets: {
type: 'array',
items: ticket
},
createdAt: {
type: 'string',
description: 'The date and time the Slack was created',
Expand Down
2 changes: 1 addition & 1 deletion src/models/slack.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import mongoose from 'mongoose';
import moment from 'moment';
import { SlackTicket } from './slack_ticket';
import { SlackTicket } from './slack_ticket.js';

const slackSchema = new mongoose.Schema({
user_id: {
Expand Down
11 changes: 0 additions & 11 deletions src/models/slack_ticket.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ import mongoose from 'mongoose';
import moment from 'moment';

export const SLACK_SUB = 'Switcher Slack App';
export const TicketStatusType = Object.freeze({
OPENED: 'OPENED',
APPROVED: 'APPROVED',
DENIED: 'DENIED'
});

export const TicketValidationType = Object.freeze({
VALIDATED: 'VALIDATED',
Expand Down Expand Up @@ -38,12 +33,6 @@ const slackTicketSchema = new mongoose.Schema({
observations: {
type: String
},
ticket_status: {
type: String,
enum: Object.values(TicketStatusType),
default: TicketStatusType.OPENED,
required: true
},
date_closed: {
type: Date
}
Expand Down
8 changes: 1 addition & 7 deletions src/routers/slack.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { check, query } from 'express-validator';
import { NotFoundError, responseException } from '../exceptions/index.js';
import { auth, slackAuth } from '../middleware/auth.js';
import { validate } from '../middleware/validators.js';
import { TicketStatusType } from '../models/slack_ticket.js';
import { SwitcherKeys } from '../external/switcher-api-facade.js';
import { getDomainById } from '../services/domain.js';
import * as Services from '../services/slack.js';
Expand Down Expand Up @@ -177,19 +176,14 @@ router.get('/slack/v1/installation/:domain', auth, [
const { slack_ticket, installation_payload, settings } =
await Services.getSlackOrError({ id: domain.integrations.slack });

const openedTickets = slack_ticket.filter(t => t.ticket_status === TicketStatusType.OPENED).length;
const approvedTickets = slack_ticket.filter(t => t.ticket_status === TicketStatusType.APPROVED).length;

res.send({
team_id: installation_payload.team_id,
team_name: installation_payload.team_name,
bot_scopes: installation_payload.bot_scopes,
channel: installation_payload.incoming_webhook_channel,
is_enterprise: installation_payload.is_enterprise_install,
installed_at: installation_payload.installed_at,
tickets_opened: openedTickets,
tickets_approved: approvedTickets,
tickets_denied: (slack_ticket.length - openedTickets - approvedTickets),
tickets_opened: slack_ticket.length,
settings
});
} catch (e) {
Expand Down
23 changes: 10 additions & 13 deletions src/services/slack.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Slack from '../models/slack.js';
import { TicketStatusType, SLACK_SUB, TicketValidationType, SlackTicket } from '../models/slack_ticket.js';
import { SLACK_SUB, TicketValidationType, SlackTicket } from '../models/slack_ticket.js';
import { BadRequestError, NotFoundError, PermissionError } from '../exceptions/index.js';
import { checkSlackIntegration } from '../external/switcher-api-facade.js';
import { getConfig } from './config.js';
Expand All @@ -14,8 +14,7 @@ import { isQueryValid } from './common.js';
* Otherwise, validates if ticket content is valid
*/
async function canCreateTicket(slack, ticket_content) {
const slackTickets = await hasSlackTicket(
slack._id, ticket_content, TicketStatusType.OPENED);
const slackTickets = await hasSlackTicket(slack._id, ticket_content);

if (slackTickets.length) {
return slackTickets[0];
Expand Down Expand Up @@ -59,11 +58,10 @@ async function deleteSlackTicketsBySlackId(slackId) {
return SlackTicket.deleteMany({ slack: slackId });
}

async function hasSlackTicket(slackId, ticket_content, status) {
async function hasSlackTicket(slackId, ticket_content) {
const tickets = await SlackTicket.find({
slack: slackId,
...ticket_content,
ticket_status: status
...ticket_content
});

return tickets;
Expand Down Expand Up @@ -211,31 +209,30 @@ export async function createTicket(ticket_content, enterprise_id, team_id) {
export async function processTicket(enterprise_id, team_id, ticket_id, approved) {
const slack = await getSlackOrError({ enterprise_id, team_id });
await getDomainById(slack.domain);
const ticket = slack.slack_ticket.filter(
t => String(t.id) === String(ticket_id) &&
t.ticket_status === TicketStatusType.OPENED);
const ticket = slack.slack_ticket.filter(t => String(t.id) === String(ticket_id));

if (!ticket.length) {
throw new NotFoundError('Ticket not found');
}

if (approved) {
ticket[0].ticket_status = TicketStatusType.APPROVED;
await closeTicket(slack.domain, ticket[0]);
} else {
ticket[0].ticket_status = TicketStatusType.DENIED;
await closeTicket(null, ticket[0]);
}

await slack.save();
return ticket[0];
}

async function closeTicket(domain, ticket) {
ticket.date_closed = Date.now();
if (ticket.ticket_status === TicketStatusType.APPROVED) {

// Approved when domain is provided
if (domain) {
await approveChange(domain, ticket);
}

await SlackTicket.deleteOne({ _id: ticket._id });
}

async function approveChange(domain, ticket) {
Expand Down
16 changes: 16 additions & 0 deletions tests/slack.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,10 @@ describe('Slack Route - Process Ticket', () => {
//given
const { ticket } = await createTicket();

//verify that
let ticketDb = await SlackTicket.findById(ticket._id).exec();
expect(ticketDb).not.toBe(null);

//test
const response = await request(app)
.post('/slack/v1/ticket/process')
Expand All @@ -820,6 +824,10 @@ describe('Slack Route - Process Ticket', () => {
}).expect(200);

expect(response.body.message).toBe(`Ticket ${ticket._id} processed`);

//check DB
ticketDb = await SlackTicket.findById(ticket._id).exec();
expect(ticketDb).toBe(null);
});

test('SLACK_SUITE - Should approve a ticket - Group Change Request', async () => {
Expand Down Expand Up @@ -865,6 +873,10 @@ describe('Slack Route - Process Ticket', () => {
//given
const { ticket } = await createTicket();

//verify that
let ticketDb = await SlackTicket.findById(ticket._id).exec();
expect(ticketDb).not.toBe(null);

//test
const response = await request(app)
.post('/slack/v1/ticket/process')
Expand All @@ -876,6 +888,10 @@ describe('Slack Route - Process Ticket', () => {
}).expect(200);

expect(response.body.message).toBe(`Ticket ${ticket._id} processed`);

//check DB
ticketDb = await SlackTicket.findById(ticket._id).exec();
expect(ticketDb).toBe(null);
});

test('SLACK_SUITE - Should reset installation tickets', async () => {
Expand Down