diff --git a/backend/.eslintrc.json b/backend/.eslintrc.json index 5f24a5b..9edbbb1 100644 --- a/backend/.eslintrc.json +++ b/backend/.eslintrc.json @@ -1,7 +1,8 @@ { "env": { "es2021": true, - "node": true + "node": true, + "jest": true }, "extends": [ "airbnb-base", diff --git a/backend/.gitignore b/backend/.gitignore index 15b445f..36e4483 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -3,6 +3,7 @@ public/* dist !public/.gitkeep .env +.env.test package-lock.json yarn.lock diff --git a/backend/coverage/lcov-report/AuthServices/RefreshTokenService.ts.html b/backend/coverage/lcov-report/AuthServices/RefreshTokenService.ts.html new file mode 100644 index 0000000..1c5845d --- /dev/null +++ b/backend/coverage/lcov-report/AuthServices/RefreshTokenService.ts.html @@ -0,0 +1,203 @@ + + + + + + Code coverage report for AuthServices/RefreshTokenService.ts + + + + + + + + + +
+
+

All files / AuthServices RefreshTokenService.ts

+
+ +
+ 0% + Statements + 0/41 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/41 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { verify } from "jsonwebtoken";
+import AppError from "../../errors/AppError";
+import ShowUserService from "../UserServices/ShowUserService";
+import authConfig from "../../config/auth";
+import {
+  createAccessToken,
+  createRefreshToken
+} from "../../helpers/CreateTokens";
+
+interface RefreshTokenPayload {
+  id: string;
+  tokenVersion: number;
+}
+
+interface Response {
+  newToken: string;
+  refreshToken: string;
+}
+
+export const RefreshTokenService = async (token: string): Promise<Response> => {
+  let decoded;
+
+  try {
+    decoded = verify(token, authConfig.refreshSecret);
+  } catch (err) {
+    throw new AppError("ERR_SESSION_EXPIRED", 401);
+  }
+
+  const { id, tokenVersion } = decoded as RefreshTokenPayload;
+
+  const user = await ShowUserService(id);
+
+  if (user.tokenVersion !== tokenVersion) {
+    throw new AppError("ERR_SESSION_EXPIRED", 401);
+  }
+
+  const newToken = createAccessToken(user);
+  const refreshToken = createRefreshToken(user);
+
+  return { newToken, refreshToken };
+};
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/AuthServices/index.html b/backend/coverage/lcov-report/AuthServices/index.html new file mode 100644 index 0000000..104244f --- /dev/null +++ b/backend/coverage/lcov-report/AuthServices/index.html @@ -0,0 +1,111 @@ + + + + + + Code coverage report for AuthServices + + + + + + + + + +
+
+

All files AuthServices

+
+ +
+ 0% + Statements + 0/41 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/41 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
RefreshTokenService.ts +
+
0%0/410%0/10%0/10%0/41
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/ContactServices/CreateContactService.ts.html b/backend/coverage/lcov-report/ContactServices/CreateContactService.ts.html new file mode 100644 index 0000000..3b7a777 --- /dev/null +++ b/backend/coverage/lcov-report/ContactServices/CreateContactService.ts.html @@ -0,0 +1,218 @@ + + + + + + Code coverage report for ContactServices/CreateContactService.ts + + + + + + + + + +
+
+

All files / ContactServices CreateContactService.ts

+
+ +
+ 0% + Statements + 0/46 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/46 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import AppError from "../../errors/AppError";
+import Contact from "../../models/Contact";
+
+interface ExtraInfo {
+  name: string;
+  value: string;
+}
+
+interface Request {
+  name: string;
+  number: string;
+  email?: string;
+  profilePicUrl?: string;
+  extraInfo?: ExtraInfo[];
+}
+
+const CreateContactService = async ({
+  name,
+  number,
+  email = "",
+  extraInfo = []
+}: Request): Promise<Contact> => {
+  const numberExists = await Contact.findOne({
+    where: { number }
+  });
+
+  if (numberExists) {
+    throw new AppError("ERR_DUPLICATED_CONTACT");
+  }
+
+  const contact = await Contact.create(
+    {
+      name,
+      number,
+      email,
+      extraInfo
+    },
+    {
+      include: ["extraInfo"]
+    }
+  );
+
+  return contact;
+};
+
+export default CreateContactService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/ContactServices/DeleteContactService.ts.html b/backend/coverage/lcov-report/ContactServices/DeleteContactService.ts.html new file mode 100644 index 0000000..f50f9ce --- /dev/null +++ b/backend/coverage/lcov-report/ContactServices/DeleteContactService.ts.html @@ -0,0 +1,128 @@ + + + + + + Code coverage report for ContactServices/DeleteContactService.ts + + + + + + + + + +
+
+

All files / ContactServices DeleteContactService.ts

+
+ +
+ 0% + Statements + 0/16 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/16 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import Contact from "../../models/Contact";
+import AppError from "../../errors/AppError";
+
+const DeleteContactService = async (id: string): Promise<void> => {
+  const contact = await Contact.findOne({
+    where: { id }
+  });
+
+  if (!contact) {
+    throw new AppError("ERR_NO_CONTACT_FOUND", 404);
+  }
+
+  await contact.destroy();
+};
+
+export default DeleteContactService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/ContactServices/ListContactsService.ts.html b/backend/coverage/lcov-report/ContactServices/ListContactsService.ts.html new file mode 100644 index 0000000..21dbff4 --- /dev/null +++ b/backend/coverage/lcov-report/ContactServices/ListContactsService.ts.html @@ -0,0 +1,230 @@ + + + + + + Code coverage report for ContactServices/ListContactsService.ts + + + + + + + + + +
+
+

All files / ContactServices ListContactsService.ts

+
+ +
+ 0% + Statements + 0/50 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/50 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Sequelize, Op } from "sequelize";
+import Contact from "../../models/Contact";
+
+interface Request {
+  searchParam?: string;
+  pageNumber?: string;
+}
+
+interface Response {
+  contacts: Contact[];
+  count: number;
+  hasMore: boolean;
+}
+
+const ListContactsService = async ({
+  searchParam = "",
+  pageNumber = "1"
+}: Request): Promise<Response> => {
+  const whereCondition = {
+    [Op.or]: [
+      {
+        name: Sequelize.where(
+          Sequelize.fn("LOWER", Sequelize.col("name")),
+          "LIKE",
+          `%${searchParam.toLowerCase().trim()}%`
+        )
+      },
+      { number: { [Op.like]: `%${searchParam.toLowerCase().trim()}%` } }
+    ]
+  };
+  const limit = 20;
+  const offset = limit * (+pageNumber - 1);
+
+  const { count, rows: contacts } = await Contact.findAndCountAll({
+    where: whereCondition,
+    limit,
+    offset,
+    order: [["name", "ASC"]]
+  });
+
+  const hasMore = count > offset + contacts.length;
+
+  return {
+    contacts,
+    count,
+    hasMore
+  };
+};
+
+export default ListContactsService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/ContactServices/ShowContactService.ts.html b/backend/coverage/lcov-report/ContactServices/ShowContactService.ts.html new file mode 100644 index 0000000..4c94b72 --- /dev/null +++ b/backend/coverage/lcov-report/ContactServices/ShowContactService.ts.html @@ -0,0 +1,122 @@ + + + + + + Code coverage report for ContactServices/ShowContactService.ts + + + + + + + + + +
+
+

All files / ContactServices ShowContactService.ts

+
+ +
+ 0% + Statements + 0/14 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/14 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import Contact from "../../models/Contact";
+import AppError from "../../errors/AppError";
+
+const ShowContactService = async (id: string | number): Promise<Contact> => {
+  const contact = await Contact.findByPk(id, { include: ["extraInfo"] });
+
+  if (!contact) {
+    throw new AppError("ERR_NO_CONTACT_FOUND", 404);
+  }
+
+  return contact;
+};
+
+export default ShowContactService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/ContactServices/UpdateContactService.ts.html b/backend/coverage/lcov-report/ContactServices/UpdateContactService.ts.html new file mode 100644 index 0000000..4976727 --- /dev/null +++ b/backend/coverage/lcov-report/ContactServices/UpdateContactService.ts.html @@ -0,0 +1,290 @@ + + + + + + Code coverage report for ContactServices/UpdateContactService.ts + + + + + + + + + +
+
+

All files / ContactServices UpdateContactService.ts

+
+ +
+ 0% + Statements + 0/70 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/70 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import AppError from "../../errors/AppError";
+import Contact from "../../models/Contact";
+import ContactCustomField from "../../models/ContactCustomField";
+
+interface ExtraInfo {
+  id?: number;
+  name: string;
+  value: string;
+}
+interface ContactData {
+  email?: string;
+  number?: string;
+  name?: string;
+  extraInfo?: ExtraInfo[];
+}
+
+interface Request {
+  contactData: ContactData;
+  contactId: string;
+}
+
+const UpdateContactService = async ({
+  contactData,
+  contactId
+}: Request): Promise<Contact> => {
+  const { email, name, number, extraInfo } = contactData;
+
+  const contact = await Contact.findOne({
+    where: { id: contactId },
+    attributes: ["id", "name", "number", "email", "profilePicUrl"],
+    include: ["extraInfo"]
+  });
+
+  if (!contact) {
+    throw new AppError("ERR_NO_CONTACT_FOUND", 404);
+  }
+
+  if (extraInfo) {
+    await Promise.all(
+      extraInfo.map(async info => {
+        await ContactCustomField.upsert({ ...info, contactId: contact.id });
+      })
+    );
+
+    await Promise.all(
+      contact.extraInfo.map(async oldInfo => {
+        const stillExists = extraInfo.findIndex(info => info.id === oldInfo.id);
+
+        if (stillExists === -1) {
+          await ContactCustomField.destroy({ where: { id: oldInfo.id } });
+        }
+      })
+    );
+  }
+
+  await contact.update({
+    name,
+    number,
+    email
+  });
+
+  await contact.reload({
+    attributes: ["id", "name", "number", "email", "profilePicUrl"],
+    include: ["extraInfo"]
+  });
+
+  return contact;
+};
+
+export default UpdateContactService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/ContactServices/index.html b/backend/coverage/lcov-report/ContactServices/index.html new file mode 100644 index 0000000..b9b178b --- /dev/null +++ b/backend/coverage/lcov-report/ContactServices/index.html @@ -0,0 +1,171 @@ + + + + + + Code coverage report for ContactServices + + + + + + + + + +
+
+

All files ContactServices

+
+ +
+ 0% + Statements + 0/196 +
+ + +
+ 0% + Branches + 0/5 +
+ + +
+ 0% + Functions + 0/5 +
+ + +
+ 0% + Lines + 0/196 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
CreateContactService.ts +
+
0%0/460%0/10%0/10%0/46
DeleteContactService.ts +
+
0%0/160%0/10%0/10%0/16
ListContactsService.ts +
+
0%0/500%0/10%0/10%0/50
ShowContactService.ts +
+
0%0/140%0/10%0/10%0/14
UpdateContactService.ts +
+
0%0/700%0/10%0/10%0/70
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/MessageServices/CreateMessageService.ts.html b/backend/coverage/lcov-report/MessageServices/CreateMessageService.ts.html new file mode 100644 index 0000000..c26b978 --- /dev/null +++ b/backend/coverage/lcov-report/MessageServices/CreateMessageService.ts.html @@ -0,0 +1,203 @@ + + + + + + Code coverage report for MessageServices/CreateMessageService.ts + + + + + + + + + +
+
+

All files / MessageServices CreateMessageService.ts

+
+ +
+ 0% + Statements + 0/41 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/41 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import AppError from "../../errors/AppError";
+import Message from "../../models/Message";
+import ShowTicketService from "../TicketServices/ShowTicketService";
+
+interface MessageData {
+  id: string;
+  ticketId: number;
+  body: string;
+  contactId?: number;
+  fromMe?: boolean;
+  read?: boolean;
+  mediaType?: string;
+  mediaUrl?: string;
+}
+interface Request {
+  messageData: MessageData;
+}
+
+const CreateMessageService = async ({
+  messageData
+}: Request): Promise<Message> => {
+  const ticket = await ShowTicketService(messageData.ticketId);
+
+  if (!ticket) {
+    throw new AppError("ERR_NO_TICKET_FOUND", 404);
+  }
+
+  await Message.upsert(messageData);
+
+  const message = await Message.findByPk(messageData.id, {
+    include: ["contact"]
+  });
+
+  if (!message) {
+    throw new AppError("ERR_CREATING_MESSAGE", 501);
+  }
+
+  return message;
+};
+
+export default CreateMessageService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/MessageServices/ListMessagesService.ts.html b/backend/coverage/lcov-report/MessageServices/ListMessagesService.ts.html new file mode 100644 index 0000000..e91f094 --- /dev/null +++ b/backend/coverage/lcov-report/MessageServices/ListMessagesService.ts.html @@ -0,0 +1,266 @@ + + + + + + Code coverage report for MessageServices/ListMessagesService.ts + + + + + + + + + +
+
+

All files / MessageServices ListMessagesService.ts

+
+ +
+ 0% + Statements + 0/62 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/62 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { where, fn, col } from "sequelize";
+import AppError from "../../errors/AppError";
+import Message from "../../models/Message";
+import Ticket from "../../models/Ticket";
+import ShowTicketService from "../TicketServices/ShowTicketService";
+
+interface Request {
+  ticketId: string;
+  searchParam?: string;
+  pageNumber?: string;
+}
+
+interface Response {
+  messages: Message[];
+  ticket: Ticket;
+  count: number;
+  hasMore: boolean;
+}
+
+const ListMessagesService = async ({
+  searchParam = "",
+  pageNumber = "1",
+  ticketId
+}: Request): Promise<Response> => {
+  const ticket = await ShowTicketService(ticketId);
+
+  if (!ticket) {
+    throw new AppError("ERR_NO_TICKET_FOUND", 404);
+  }
+
+  const whereCondition = {
+    body: where(
+      fn("LOWER", col("body")),
+      "LIKE",
+      `%${searchParam.toLowerCase()}%`
+    ),
+    ticketId
+  };
+
+  // await setMessagesAsRead(ticket);
+  const limit = 20;
+  const offset = limit * (+pageNumber - 1);
+
+  const { count, rows: messages } = await Message.findAndCountAll({
+    where: whereCondition,
+    limit,
+    include: ["contact"],
+    offset,
+    order: [["createdAt", "DESC"]]
+  });
+
+  const hasMore = count > offset + messages.length;
+
+  return {
+    messages: messages.reverse(),
+    ticket,
+    count,
+    hasMore
+  };
+};
+
+export default ListMessagesService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/MessageServices/index.html b/backend/coverage/lcov-report/MessageServices/index.html new file mode 100644 index 0000000..7815105 --- /dev/null +++ b/backend/coverage/lcov-report/MessageServices/index.html @@ -0,0 +1,126 @@ + + + + + + Code coverage report for MessageServices + + + + + + + + + +
+
+

All files MessageServices

+
+ +
+ 0% + Statements + 0/103 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/2 +
+ + +
+ 0% + Lines + 0/103 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
CreateMessageService.ts +
+
0%0/410%0/10%0/10%0/41
ListMessagesService.ts +
+
0%0/620%0/10%0/10%0/62
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/SettingServices/ListSettingsService.ts.html b/backend/coverage/lcov-report/SettingServices/ListSettingsService.ts.html new file mode 100644 index 0000000..0b2effd --- /dev/null +++ b/backend/coverage/lcov-report/SettingServices/ListSettingsService.ts.html @@ -0,0 +1,107 @@ + + + + + + Code coverage report for SettingServices/ListSettingsService.ts + + + + + + + + + +
+
+

All files / SettingServices ListSettingsService.ts

+
+ +
+ 0% + Statements + 0/9 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/9 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10  +  +  +  +  +  +  +  +  + 
import Setting from "../../models/Setting";
+
+const ListSettingsService = async (): Promise<Setting[] | undefined> => {
+  const settings = await Setting.findAll();
+
+  return settings;
+};
+
+export default ListSettingsService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/SettingServices/UpdateSettingService.ts.html b/backend/coverage/lcov-report/SettingServices/UpdateSettingService.ts.html new file mode 100644 index 0000000..7333233 --- /dev/null +++ b/backend/coverage/lcov-report/SettingServices/UpdateSettingService.ts.html @@ -0,0 +1,158 @@ + + + + + + Code coverage report for SettingServices/UpdateSettingService.ts + + + + + + + + + +
+
+

All files / SettingServices UpdateSettingService.ts

+
+ +
+ 0% + Statements + 0/26 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/26 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import AppError from "../../errors/AppError";
+import Setting from "../../models/Setting";
+
+interface Request {
+  key: string;
+  value: string;
+}
+
+const UpdateSettingService = async ({
+  key,
+  value
+}: Request): Promise<Setting | undefined> => {
+  const setting = await Setting.findOne({
+    where: { key }
+  });
+
+  if (!setting) {
+    throw new AppError("ERR_NO_SETTING_FOUND", 404);
+  }
+
+  await setting.update({ value });
+
+  return setting;
+};
+
+export default UpdateSettingService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/SettingServices/index.html b/backend/coverage/lcov-report/SettingServices/index.html new file mode 100644 index 0000000..3974171 --- /dev/null +++ b/backend/coverage/lcov-report/SettingServices/index.html @@ -0,0 +1,126 @@ + + + + + + Code coverage report for SettingServices + + + + + + + + + +
+
+

All files SettingServices

+
+ +
+ 0% + Statements + 0/35 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/2 +
+ + +
+ 0% + Lines + 0/35 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
ListSettingsService.ts +
+
0%0/90%0/10%0/10%0/9
UpdateSettingService.ts +
+
0%0/260%0/10%0/10%0/26
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/TicketServices/CreateTicketService.ts.html b/backend/coverage/lcov-report/TicketServices/CreateTicketService.ts.html new file mode 100644 index 0000000..5664852 --- /dev/null +++ b/backend/coverage/lcov-report/TicketServices/CreateTicketService.ts.html @@ -0,0 +1,200 @@ + + + + + + Code coverage report for TicketServices/CreateTicketService.ts + + + + + + + + + +
+
+

All files / TicketServices CreateTicketService.ts

+
+ +
+ 0% + Statements + 0/40 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/40 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import AppError from "../../errors/AppError";
+import CheckContactOpenTickets from "../../helpers/CheckContactOpenTickets";
+import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
+import Ticket from "../../models/Ticket";
+import ShowContactService from "../ContactServices/ShowContactService";
+
+interface Request {
+  contactId: number;
+  status: string;
+  userId: number;
+}
+
+const CreateTicketService = async ({
+  contactId,
+  status,
+  userId
+}: Request): Promise<Ticket> => {
+  const defaultWhatsapp = await GetDefaultWhatsApp();
+
+  await CheckContactOpenTickets(contactId);
+
+  const { isGroup } = await ShowContactService(contactId);
+
+  const { id }: Ticket = await defaultWhatsapp.$create("ticket", {
+    contactId,
+    status,
+    isGroup,
+    userId
+  });
+
+  const ticket = await Ticket.findByPk(id, { include: ["contact"] });
+
+  if (!ticket) {
+    throw new AppError("ERR_CREATING_TICKET");
+  }
+
+  return ticket;
+};
+
+export default CreateTicketService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/TicketServices/DeleteTicketService.ts.html b/backend/coverage/lcov-report/TicketServices/DeleteTicketService.ts.html new file mode 100644 index 0000000..8f93a7d --- /dev/null +++ b/backend/coverage/lcov-report/TicketServices/DeleteTicketService.ts.html @@ -0,0 +1,134 @@ + + + + + + Code coverage report for TicketServices/DeleteTicketService.ts + + + + + + + + + +
+
+

All files / TicketServices DeleteTicketService.ts

+
+ +
+ 0% + Statements + 0/18 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/18 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import Ticket from "../../models/Ticket";
+import AppError from "../../errors/AppError";
+
+const DeleteTicketService = async (id: string): Promise<Ticket> => {
+  const ticket = await Ticket.findOne({
+    where: { id }
+  });
+
+  if (!ticket) {
+    throw new AppError("ERR_NO_TICKET_FOUND", 404);
+  }
+
+  await ticket.destroy();
+
+  return ticket;
+};
+
+export default DeleteTicketService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/TicketServices/ListTicketsService.ts.html b/backend/coverage/lcov-report/TicketServices/ListTicketsService.ts.html new file mode 100644 index 0000000..6634ab9 --- /dev/null +++ b/backend/coverage/lcov-report/TicketServices/ListTicketsService.ts.html @@ -0,0 +1,512 @@ + + + + + + Code coverage report for TicketServices/ListTicketsService.ts + + + + + + + + + +
+
+

All files / TicketServices ListTicketsService.ts

+
+ +
+ 0% + Statements + 0/144 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/144 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Op, fn, where, col, Filterable, Includeable } from "sequelize";
+import { startOfDay, endOfDay, parseISO } from "date-fns";
+
+import Ticket from "../../models/Ticket";
+import Contact from "../../models/Contact";
+import Message from "../../models/Message";
+
+interface Request {
+  searchParam?: string;
+  pageNumber?: string;
+  status?: string;
+  date?: string;
+  showAll?: string;
+  userId: string;
+  withUnreadMessages?: string;
+}
+
+interface Response {
+  tickets: Ticket[];
+  count: number;
+  hasMore: boolean;
+}
+
+const ListTicketsService = async ({
+  searchParam = "",
+  pageNumber = "1",
+  status,
+  date,
+  showAll,
+  userId,
+  withUnreadMessages
+}: Request): Promise<Response> => {
+  let whereCondition: Filterable["where"] = {
+    [Op.or]: [{ userId }, { status: "pending" }]
+  };
+  let includeCondition: Includeable[];
+
+  includeCondition = [
+    {
+      model: Contact,
+      as: "contact",
+      attributes: ["id", "name", "number", "profilePicUrl"]
+    }
+  ];
+
+  if (showAll === "true") {
+    whereCondition = {};
+  }
+
+  if (status) {
+    whereCondition = {
+      ...whereCondition,
+      status
+    };
+  }
+
+  if (searchParam) {
+    const sanitizedSearchParam = searchParam.toLocaleLowerCase().trim();
+
+    includeCondition = [
+      ...includeCondition,
+      {
+        model: Message,
+        as: "messages",
+        attributes: ["id", "body"],
+        where: {
+          body: where(
+            fn("LOWER", col("body")),
+            "LIKE",
+            `%${sanitizedSearchParam}%`
+          )
+        },
+        required: false,
+        duplicating: false
+      }
+    ];
+
+    whereCondition = {
+      [Op.or]: [
+        {
+          "$contact.name$": where(
+            fn("LOWER", col("name")),
+            "LIKE",
+            `%${sanitizedSearchParam}%`
+          )
+        },
+        { "$contact.number$": { [Op.like]: `%${sanitizedSearchParam}%` } },
+        {
+          "$message.body$": where(
+            fn("LOWER", col("body")),
+            "LIKE",
+            `%${sanitizedSearchParam}%`
+          )
+        }
+      ]
+    };
+  }
+
+  if (date) {
+    whereCondition = {
+      ...whereCondition,
+      createdAt: {
+        [Op.between]: [+startOfDay(parseISO(date)), +endOfDay(parseISO(date))]
+      }
+    };
+  }
+
+  if (withUnreadMessages === "true") {
+    includeCondition = [
+      ...includeCondition,
+      {
+        model: Message,
+        as: "messages",
+        attributes: [],
+        where: {
+          read: false,
+          fromMe: false
+        }
+      }
+    ];
+  }
+
+  const limit = 20;
+  const offset = limit * (+pageNumber - 1);
+
+  const { count, rows: tickets } = await Ticket.findAndCountAll({
+    where: whereCondition,
+    include: includeCondition,
+    distinct: true,
+    limit,
+    offset,
+    order: [["updatedAt", "DESC"]]
+  });
+
+  const hasMore = count > offset + tickets.length;
+
+  return {
+    tickets,
+    count,
+    hasMore
+  };
+};
+
+export default ListTicketsService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/TicketServices/ShowTicketService.ts.html b/backend/coverage/lcov-report/TicketServices/ShowTicketService.ts.html new file mode 100644 index 0000000..90682db --- /dev/null +++ b/backend/coverage/lcov-report/TicketServices/ShowTicketService.ts.html @@ -0,0 +1,170 @@ + + + + + + Code coverage report for TicketServices/ShowTicketService.ts + + + + + + + + + +
+
+

All files / TicketServices ShowTicketService.ts

+
+ +
+ 0% + Statements + 0/30 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/30 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import Ticket from "../../models/Ticket";
+import AppError from "../../errors/AppError";
+import Contact from "../../models/Contact";
+import User from "../../models/User";
+
+const ShowTicketService = async (id: string | number): Promise<Ticket> => {
+  const ticket = await Ticket.findByPk(id, {
+    include: [
+      {
+        model: Contact,
+        as: "contact",
+        attributes: ["id", "name", "number", "profilePicUrl"],
+        include: ["extraInfo"]
+      },
+      {
+        model: User,
+        as: "user",
+        attributes: ["id", "name"]
+      }
+    ]
+  });
+
+  if (!ticket) {
+    throw new AppError("ERR_NO_TICKET_FOUND", 404);
+  }
+
+  return ticket;
+};
+
+export default ShowTicketService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/TicketServices/UpdateTicketService.ts.html b/backend/coverage/lcov-report/TicketServices/UpdateTicketService.ts.html new file mode 100644 index 0000000..7a19f4a --- /dev/null +++ b/backend/coverage/lcov-report/TicketServices/UpdateTicketService.ts.html @@ -0,0 +1,266 @@ + + + + + + Code coverage report for TicketServices/UpdateTicketService.ts + + + + + + + + + +
+
+

All files / TicketServices UpdateTicketService.ts

+
+ +
+ 0% + Statements + 0/62 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/62 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import AppError from "../../errors/AppError";
+import CheckContactOpenTickets from "../../helpers/CheckContactOpenTickets";
+import SetTicketMessagesAsRead from "../../helpers/SetTicketMessagesAsRead";
+import Contact from "../../models/Contact";
+import Ticket from "../../models/Ticket";
+import User from "../../models/User";
+
+interface TicketData {
+  status?: string;
+  userId?: number;
+}
+
+interface Request {
+  ticketData: TicketData;
+  ticketId: string;
+}
+
+interface Response {
+  ticket: Ticket;
+  ticketUser: User | null;
+  oldStatus: string;
+}
+
+const UpdateTicketService = async ({
+  ticketData,
+  ticketId
+}: Request): Promise<Response> => {
+  const { status, userId } = ticketData;
+
+  const ticket = await Ticket.findOne({
+    where: { id: ticketId },
+    include: [
+      {
+        model: Contact,
+        as: "contact",
+        attributes: ["id", "name", "number", "profilePicUrl"]
+      }
+    ]
+  });
+
+  if (!ticket) {
+    throw new AppError("ERR_NO_TICKET_FOUND", 404);
+  }
+
+  await SetTicketMessagesAsRead(ticket);
+
+  const oldStatus = ticket.status;
+
+  if (oldStatus === "closed") {
+    await CheckContactOpenTickets(ticket.contact.id);
+  }
+
+  await ticket.update({
+    status,
+    userId
+  });
+  const ticketUser = await ticket.$get("user", { attributes: ["id", "name"] });
+
+  return { ticket, oldStatus, ticketUser };
+};
+
+export default UpdateTicketService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/TicketServices/index.html b/backend/coverage/lcov-report/TicketServices/index.html new file mode 100644 index 0000000..e72a4f4 --- /dev/null +++ b/backend/coverage/lcov-report/TicketServices/index.html @@ -0,0 +1,171 @@ + + + + + + Code coverage report for TicketServices + + + + + + + + + +
+
+

All files TicketServices

+
+ +
+ 0% + Statements + 0/294 +
+ + +
+ 0% + Branches + 0/5 +
+ + +
+ 0% + Functions + 0/5 +
+ + +
+ 0% + Lines + 0/294 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
CreateTicketService.ts +
+
0%0/400%0/10%0/10%0/40
DeleteTicketService.ts +
+
0%0/180%0/10%0/10%0/18
ListTicketsService.ts +
+
0%0/1440%0/10%0/10%0/144
ShowTicketService.ts +
+
0%0/300%0/10%0/10%0/30
UpdateTicketService.ts +
+
0%0/620%0/10%0/10%0/62
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/UserServices/AuthUserSerice.ts.html b/backend/coverage/lcov-report/UserServices/AuthUserSerice.ts.html new file mode 100644 index 0000000..a4153ef --- /dev/null +++ b/backend/coverage/lcov-report/UserServices/AuthUserSerice.ts.html @@ -0,0 +1,215 @@ + + + + + + Code coverage report for UserServices/AuthUserSerice.ts + + + + + + + + + +
+
+

All files / UserServices AuthUserSerice.ts

+
+ +
+ 0% + Statements + 0/45 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/45 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import User from "../../models/User";
+import AppError from "../../errors/AppError";
+import {
+  createAccessToken,
+  createRefreshToken
+} from "../../helpers/CreateTokens";
+
+interface Request {
+  email: string;
+  password: string;
+}
+
+interface Response {
+  user: User;
+  token: string;
+  refreshToken: string;
+}
+
+const AuthUserService = async ({
+  email,
+  password
+}: Request): Promise<Response> => {
+  const user = await User.findOne({
+    where: { email }
+  });
+
+  if (!user) {
+    throw new AppError("ERR_INVALID_CREDENTIALS", 401);
+  }
+
+  if (!(await user.checkPassword(password))) {
+    throw new AppError("ERR_INVALID_CREDENTIALS", 401);
+  }
+
+  const token = createAccessToken(user);
+  const refreshToken = createRefreshToken(user);
+
+  return {
+    user,
+    token,
+    refreshToken
+  };
+};
+
+export default AuthUserService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/UserServices/CreateUserService.ts.html b/backend/coverage/lcov-report/UserServices/CreateUserService.ts.html new file mode 100644 index 0000000..07d89be --- /dev/null +++ b/backend/coverage/lcov-report/UserServices/CreateUserService.ts.html @@ -0,0 +1,290 @@ + + + + + + Code coverage report for UserServices/CreateUserService.ts + + + + + + + + + +
+
+

All files / UserServices CreateUserService.ts

+
+ +
+ 0% + Statements + 0/70 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/70 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as Yup from "yup";
+
+import AppError from "../../errors/AppError";
+import User from "../../models/User";
+
+interface Request {
+  email: string;
+  password: string;
+  name: string;
+  profile?: string;
+}
+
+interface Response {
+  email: string;
+  name: string;
+  id: number;
+  profile: string;
+}
+
+const CreateUserService = async ({
+  email,
+  password,
+  name,
+  profile = "admin"
+}: Request): Promise<Response> => {
+  const schema = Yup.object().shape({
+    name: Yup.string().required().min(2),
+    email: Yup.string()
+      .email()
+      .required()
+      .test(
+        "Check-email",
+        "An user with this email already exists.",
+        async value => {
+          if (value) {
+            const emailExists = await User.findOne({
+              where: { email: value }
+            });
+            return !emailExists;
+          }
+          return false;
+        }
+      ),
+    password: Yup.string().required().min(5)
+  });
+
+  try {
+    await schema.validate({ email, password, name });
+  } catch (err) {
+    throw new AppError(err.message);
+  }
+
+  const user = await User.create({
+    email,
+    password,
+    name,
+    profile
+  });
+
+  const serializedUser = {
+    id: user.id,
+    name: user.name,
+    email: user.email,
+    profile: user.profile
+  };
+
+  return serializedUser;
+};
+
+export default CreateUserService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/UserServices/DeleteUserService.ts.html b/backend/coverage/lcov-report/UserServices/DeleteUserService.ts.html new file mode 100644 index 0000000..3f75955 --- /dev/null +++ b/backend/coverage/lcov-report/UserServices/DeleteUserService.ts.html @@ -0,0 +1,158 @@ + + + + + + Code coverage report for UserServices/DeleteUserService.ts + + + + + + + + + +
+
+

All files / UserServices DeleteUserService.ts

+
+ +
+ 0% + Statements + 0/26 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/26 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import User from "../../models/User";
+import AppError from "../../errors/AppError";
+import Ticket from "../../models/Ticket";
+import UpdateDeletedUserOpenTicketsStatus from "../../helpers/UpdateDeletedUserOpenTicketsStatus";
+
+const DeleteUserService = async (id: string): Promise<void> => {
+  const user = await User.findOne({
+    where: { id }
+  });
+
+  if (!user) {
+    throw new AppError("ERR_NO_USER_FOUND", 404);
+  }
+
+  const userOpenTickets: Ticket[] = await user.$get("tickets", {
+    where: { status: "open" }
+  });
+
+  if (userOpenTickets.length > 0) {
+    UpdateDeletedUserOpenTicketsStatus(userOpenTickets);
+  }
+
+  await user.destroy();
+};
+
+export default DeleteUserService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/UserServices/ListUsersService.ts.html b/backend/coverage/lcov-report/UserServices/ListUsersService.ts.html new file mode 100644 index 0000000..eb6a0e5 --- /dev/null +++ b/backend/coverage/lcov-report/UserServices/ListUsersService.ts.html @@ -0,0 +1,233 @@ + + + + + + Code coverage report for UserServices/ListUsersService.ts + + + + + + + + + +
+
+

All files / UserServices ListUsersService.ts

+
+ +
+ 0% + Statements + 0/51 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/51 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Sequelize, Op } from "sequelize";
+import User from "../../models/User";
+
+interface Request {
+  searchParam?: string;
+  pageNumber?: string;
+}
+
+interface Response {
+  users: User[];
+  count: number;
+  hasMore: boolean;
+}
+
+const ListUsersService = async ({
+  searchParam = "",
+  pageNumber = "1"
+}: Request): Promise<Response> => {
+  const whereCondition = {
+    [Op.or]: [
+      {
+        name: Sequelize.where(
+          Sequelize.fn("LOWER", Sequelize.col("name")),
+          "LIKE",
+          `%${searchParam.toLowerCase()}%`
+        )
+      },
+      { email: { [Op.like]: `%${searchParam.toLowerCase()}%` } }
+    ]
+  };
+  const limit = 20;
+  const offset = limit * (+pageNumber - 1);
+
+  const { count, rows: users } = await User.findAndCountAll({
+    where: whereCondition,
+    attributes: ["name", "id", "email", "profile"],
+    limit,
+    offset,
+    order: [["createdAt", "DESC"]]
+  });
+
+  const hasMore = count > offset + users.length;
+
+  return {
+    users,
+    count,
+    hasMore
+  };
+};
+
+export default ListUsersService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/UserServices/ShowUserService.ts.html b/backend/coverage/lcov-report/UserServices/ShowUserService.ts.html new file mode 100644 index 0000000..a128fb0 --- /dev/null +++ b/backend/coverage/lcov-report/UserServices/ShowUserService.ts.html @@ -0,0 +1,128 @@ + + + + + + Code coverage report for UserServices/ShowUserService.ts + + + + + + + + + +
+
+

All files / UserServices ShowUserService.ts

+
+ +
+ 0% + Statements + 0/16 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/16 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import User from "../../models/User";
+import AppError from "../../errors/AppError";
+
+const ShowUserService = async (id: string | number): Promise<User> => {
+  const user = await User.findByPk(id, {
+    attributes: ["name", "id", "email", "profile", "tokenVersion"]
+  });
+
+  if (!user) {
+    throw new AppError("ERR_NO_USER_FOUND", 404);
+  }
+
+  return user;
+};
+
+export default ShowUserService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/UserServices/UpdateUserService.ts.html b/backend/coverage/lcov-report/UserServices/UpdateUserService.ts.html new file mode 100644 index 0000000..7b3c3ee --- /dev/null +++ b/backend/coverage/lcov-report/UserServices/UpdateUserService.ts.html @@ -0,0 +1,284 @@ + + + + + + Code coverage report for UserServices/UpdateUserService.ts + + + + + + + + + +
+
+

All files / UserServices UpdateUserService.ts

+
+ +
+ 0% + Statements + 0/68 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/68 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as Yup from "yup";
+
+import AppError from "../../errors/AppError";
+import User from "../../models/User";
+
+interface UserData {
+  email?: string;
+  password?: string;
+  name?: string;
+  profile?: string;
+}
+
+interface Request {
+  userData: UserData;
+  userId: string;
+}
+
+interface Response {
+  id: number;
+  name: string;
+  email: string;
+  profile: string;
+}
+
+const UpdateUserService = async ({
+  userData,
+  userId
+}: Request): Promise<Response | undefined> => {
+  const user = await User.findOne({
+    where: { id: userId },
+    attributes: ["name", "id", "email", "profile"]
+  });
+
+  if (!user) {
+    throw new AppError("ERR_NO_USER_FOUND", 404);
+  }
+
+  const schema = Yup.object().shape({
+    name: Yup.string().min(2),
+    email: Yup.string().email(),
+    password: Yup.string()
+  });
+
+  const { email, password, name } = userData;
+
+  try {
+    await schema.validate({ email, password, name });
+  } catch (err) {
+    throw new AppError(err.message);
+  }
+
+  await user.update({
+    email,
+    password,
+    name
+  });
+
+  const serializedUser = {
+    id: user.id,
+    name: user.name,
+    email: user.email,
+    profile: user.profile
+  };
+
+  return serializedUser;
+};
+
+export default UpdateUserService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/UserServices/index.html b/backend/coverage/lcov-report/UserServices/index.html new file mode 100644 index 0000000..b6e59a8 --- /dev/null +++ b/backend/coverage/lcov-report/UserServices/index.html @@ -0,0 +1,186 @@ + + + + + + Code coverage report for UserServices + + + + + + + + + +
+
+

All files UserServices

+
+ +
+ 0% + Statements + 0/276 +
+ + +
+ 0% + Branches + 0/6 +
+ + +
+ 0% + Functions + 0/6 +
+ + +
+ 0% + Lines + 0/276 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
AuthUserSerice.ts +
+
0%0/450%0/10%0/10%0/45
CreateUserService.ts +
+
0%0/700%0/10%0/10%0/70
DeleteUserService.ts +
+
0%0/260%0/10%0/10%0/26
ListUsersService.ts +
+
0%0/510%0/10%0/10%0/51
ShowUserService.ts +
+
0%0/160%0/10%0/10%0/16
UpdateUserService.ts +
+
0%0/680%0/10%0/10%0/68
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WbotServices/CheckIsValidContact.ts.html b/backend/coverage/lcov-report/WbotServices/CheckIsValidContact.ts.html new file mode 100644 index 0000000..87ab9e5 --- /dev/null +++ b/backend/coverage/lcov-report/WbotServices/CheckIsValidContact.ts.html @@ -0,0 +1,152 @@ + + + + + + Code coverage report for WbotServices/CheckIsValidContact.ts + + + + + + + + + +
+
+

All files / WbotServices CheckIsValidContact.ts

+
+ +
+ 0% + Statements + 0/24 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/24 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import AppError from "../../errors/AppError";
+import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
+import { getWbot } from "../../libs/wbot";
+
+const CheckIsValidContact = async (number: string): Promise<void> => {
+  const defaultWhatsapp = await GetDefaultWhatsApp();
+
+  const wbot = getWbot(defaultWhatsapp.id);
+
+  try {
+    const isValidNumber = await wbot.isRegisteredUser(`${number}@c.us`);
+    if (!isValidNumber) {
+      throw new AppError("invalidNumber");
+    }
+  } catch (err) {
+    console.log(err);
+    if (err.message === "invalidNumber") {
+      throw new AppError("ERR_WAPP_INVALID_CONTACT");
+    }
+    throw new AppError("ERR_WAPP_CHECK_CONTACT");
+  }
+};
+
+export default CheckIsValidContact;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WbotServices/DeleteWhatsAppMessage.ts.html b/backend/coverage/lcov-report/WbotServices/DeleteWhatsAppMessage.ts.html new file mode 100644 index 0000000..79b1993 --- /dev/null +++ b/backend/coverage/lcov-report/WbotServices/DeleteWhatsAppMessage.ts.html @@ -0,0 +1,188 @@ + + + + + + Code coverage report for WbotServices/DeleteWhatsAppMessage.ts + + + + + + + + + +
+
+

All files / WbotServices DeleteWhatsAppMessage.ts

+
+ +
+ 0% + Statements + 0/36 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/36 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import AppError from "../../errors/AppError";
+import GetWbotMessage from "../../helpers/GetWbotMessage";
+import Message from "../../models/Message";
+import Ticket from "../../models/Ticket";
+
+const DeleteWhatsAppMessage = async (messageId: string): Promise<Message> => {
+  const message = await Message.findByPk(messageId, {
+    include: [
+      {
+        model: Ticket,
+        as: "ticket",
+        include: ["contact"]
+      }
+    ]
+  });
+
+  if (!message) {
+    throw new AppError("No message found with this ID.");
+  }
+
+  const { ticket } = message;
+
+  const messageToDelete = await GetWbotMessage(ticket, messageId);
+
+  try {
+    await messageToDelete.delete(true);
+  } catch (err) {
+    throw new AppError("ERR_DELETE_WAPP_MSG");
+  }
+
+  await message.update({ isDeleted: true });
+
+  return message;
+};
+
+export default DeleteWhatsAppMessage;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WbotServices/GetProfilePicUrl.ts.html b/backend/coverage/lcov-report/WbotServices/GetProfilePicUrl.ts.html new file mode 100644 index 0000000..e85e944 --- /dev/null +++ b/backend/coverage/lcov-report/WbotServices/GetProfilePicUrl.ts.html @@ -0,0 +1,122 @@ + + + + + + Code coverage report for WbotServices/GetProfilePicUrl.ts + + + + + + + + + +
+
+

All files / WbotServices GetProfilePicUrl.ts

+
+ +
+ 0% + Statements + 0/14 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/14 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
+import { getWbot } from "../../libs/wbot";
+
+const GetProfilePicUrl = async (number: string): Promise<string> => {
+  const defaultWhatsapp = await GetDefaultWhatsApp();
+
+  const wbot = getWbot(defaultWhatsapp.id);
+
+  const profilePicUrl = await wbot.getProfilePicUrl(`${number}@c.us`);
+
+  return profilePicUrl;
+};
+
+export default GetProfilePicUrl;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WbotServices/ImportContactsService.ts.html b/backend/coverage/lcov-report/WbotServices/ImportContactsService.ts.html new file mode 100644 index 0000000..b62f234 --- /dev/null +++ b/backend/coverage/lcov-report/WbotServices/ImportContactsService.ts.html @@ -0,0 +1,209 @@ + + + + + + Code coverage report for WbotServices/ImportContactsService.ts + + + + + + + + + +
+
+

All files / WbotServices ImportContactsService.ts

+
+ +
+ 0% + Statements + 0/43 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/43 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
+import { getWbot } from "../../libs/wbot";
+import Contact from "../../models/Contact";
+
+const ImportContactsService = async (): Promise<void> => {
+  const defaultWhatsapp = await GetDefaultWhatsApp();
+
+  const wbot = getWbot(defaultWhatsapp.id);
+
+  let phoneContacts;
+
+  try {
+    phoneContacts = await wbot.getContacts();
+  } catch (err) {
+    console.log(
+      "Could not get whatsapp contacts from phone. Check connection page.",
+      err
+    );
+  }
+
+  if (phoneContacts) {
+    await Promise.all(
+      phoneContacts.map(async ({ number, name }) => {
+        if (!number) {
+          return null;
+        }
+        if (!name) {
+          name = number;
+        }
+
+        const numberExists = await Contact.findOne({
+          where: { number }
+        });
+
+        if (numberExists) return null;
+
+        return Contact.create({ number, name });
+      })
+    );
+  }
+};
+
+export default ImportContactsService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WbotServices/SendWhatsAppMedia.ts.html b/backend/coverage/lcov-report/WbotServices/SendWhatsAppMedia.ts.html new file mode 100644 index 0000000..7df6d3a --- /dev/null +++ b/backend/coverage/lcov-report/WbotServices/SendWhatsAppMedia.ts.html @@ -0,0 +1,194 @@ + + + + + + Code coverage report for WbotServices/SendWhatsAppMedia.ts + + + + + + + + + +
+
+

All files / WbotServices SendWhatsAppMedia.ts

+
+ +
+ 0% + Statements + 0/38 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/38 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import fs from "fs";
+import { MessageMedia, Message as WbotMessage } from "whatsapp-web.js";
+import AppError from "../../errors/AppError";
+import GetTicketWbot from "../../helpers/GetTicketWbot";
+import Ticket from "../../models/Ticket";
+
+interface Request {
+  media: Express.Multer.File;
+  ticket: Ticket;
+}
+
+const SendWhatsAppMedia = async ({
+  media,
+  ticket
+}: Request): Promise<WbotMessage> => {
+  try {
+    const wbot = await GetTicketWbot(ticket);
+
+    const newMedia = MessageMedia.fromFilePath(media.path);
+
+    const sentMessage = await wbot.sendMessage(
+      `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
+      newMedia,
+      { sendAudioAsVoice: true }
+    );
+
+    await ticket.update({ lastMessage: media.filename });
+
+    fs.unlinkSync(media.path);
+
+    return sentMessage;
+  } catch (err) {
+    console.log(err);
+    throw new AppError("ERR_SENDING_WAPP_MSG");
+  }
+};
+
+export default SendWhatsAppMedia;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WbotServices/SendWhatsAppMessage.ts.html b/backend/coverage/lcov-report/WbotServices/SendWhatsAppMessage.ts.html new file mode 100644 index 0000000..15a7777 --- /dev/null +++ b/backend/coverage/lcov-report/WbotServices/SendWhatsAppMessage.ts.html @@ -0,0 +1,173 @@ + + + + + + Code coverage report for WbotServices/SendWhatsAppMessage.ts + + + + + + + + + +
+
+

All files / WbotServices SendWhatsAppMessage.ts

+
+ +
+ 0% + Statements + 0/31 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/31 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Message as WbotMessage } from "whatsapp-web.js";
+import AppError from "../../errors/AppError";
+import GetTicketWbot from "../../helpers/GetTicketWbot";
+import Ticket from "../../models/Ticket";
+
+interface Request {
+  body: string;
+  ticket: Ticket;
+}
+
+const SendWhatsAppMessage = async ({
+  body,
+  ticket
+}: Request): Promise<WbotMessage> => {
+  try {
+    const wbot = await GetTicketWbot(ticket);
+
+    const sentMessage = await wbot.sendMessage(
+      `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
+      body
+    );
+
+    await ticket.update({ lastMessage: body });
+    return sentMessage;
+  } catch (err) {
+    console.log(err);
+    throw new AppError("ERR_SENDING_WAPP_MSG");
+  }
+};
+
+export default SendWhatsAppMessage;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WbotServices/StartWhatsAppSessions.ts.html b/backend/coverage/lcov-report/WbotServices/StartWhatsAppSessions.ts.html new file mode 100644 index 0000000..fc3ed8a --- /dev/null +++ b/backend/coverage/lcov-report/WbotServices/StartWhatsAppSessions.ts.html @@ -0,0 +1,134 @@ + + + + + + Code coverage report for WbotServices/StartWhatsAppSessions.ts + + + + + + + + + +
+
+

All files / WbotServices StartWhatsAppSessions.ts

+
+ +
+ 0% + Statements + 0/18 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/18 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { initWbot } from "../../libs/wbot";
+import Whatsapp from "../../models/Whatsapp";
+import wbotMessageListener from "./wbotMessageListener";
+import wbotMonitor from "./wbotMonitor";
+
+export const StartWhatsAppSessions = async (): Promise<void> => {
+  const whatsapps = await Whatsapp.findAll();
+  if (whatsapps.length > 0) {
+    whatsapps.forEach(whatsapp => {
+      initWbot(whatsapp)
+        .then(() => {
+          wbotMessageListener(whatsapp);
+          wbotMonitor(whatsapp);
+        })
+        .catch(err => console.log(err));
+    });
+  }
+};
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WbotServices/index.html b/backend/coverage/lcov-report/WbotServices/index.html new file mode 100644 index 0000000..2596043 --- /dev/null +++ b/backend/coverage/lcov-report/WbotServices/index.html @@ -0,0 +1,231 @@ + + + + + + Code coverage report for WbotServices + + + + + + + + + +
+
+

All files WbotServices

+
+ +
+ 0% + Statements + 0/624 +
+ + +
+ 0% + Branches + 0/9 +
+ + +
+ 0% + Functions + 0/9 +
+ + +
+ 0% + Lines + 0/624 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
CheckIsValidContact.ts +
+
0%0/240%0/10%0/10%0/24
DeleteWhatsAppMessage.ts +
+
0%0/360%0/10%0/10%0/36
GetProfilePicUrl.ts +
+
0%0/140%0/10%0/10%0/14
ImportContactsService.ts +
+
0%0/430%0/10%0/10%0/43
SendWhatsAppMedia.ts +
+
0%0/380%0/10%0/10%0/38
SendWhatsAppMessage.ts +
+
0%0/310%0/10%0/10%0/31
StartWhatsAppSessions.ts +
+
0%0/180%0/10%0/10%0/18
wbotMessageListener.ts +
+
0%0/3330%0/10%0/10%0/333
wbotMonitor.ts +
+
0%0/870%0/10%0/10%0/87
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WbotServices/wbotMessageListener.ts.html b/backend/coverage/lcov-report/WbotServices/wbotMessageListener.ts.html new file mode 100644 index 0000000..30a16f0 --- /dev/null +++ b/backend/coverage/lcov-report/WbotServices/wbotMessageListener.ts.html @@ -0,0 +1,1079 @@ + + + + + + Code coverage report for WbotServices/wbotMessageListener.ts + + + + + + + + + +
+
+

All files / WbotServices wbotMessageListener.ts

+
+ +
+ 0% + Statements + 0/333 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/333 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { join } from "path";
+import { promisify } from "util";
+import { writeFile } from "fs";
+import { Op } from "sequelize";
+import { subHours } from "date-fns";
+import * as Sentry from "@sentry/node";
+
+import {
+  Contact as WbotContact,
+  Message as WbotMessage
+} from "whatsapp-web.js";
+
+import Contact from "../../models/Contact";
+import Ticket from "../../models/Ticket";
+import Message from "../../models/Message";
+import Whatsapp from "../../models/Whatsapp";
+
+import { getIO } from "../../libs/socket";
+import { getWbot } from "../../libs/wbot";
+import AppError from "../../errors/AppError";
+import ShowTicketService from "../TicketServices/ShowTicketService";
+import CreateMessageService from "../MessageServices/CreateMessageService";
+
+const writeFileAsync = promisify(writeFile);
+
+const verifyContact = async (
+  msgContact: WbotContact,
+  profilePicUrl: string
+): Promise<Contact> => {
+  const io = getIO();
+
+  let contact = await Contact.findOne({
+    where: { number: msgContact.id.user }
+  });
+
+  if (contact) {
+    await contact.update({ profilePicUrl });
+
+    io.emit("contact", {
+      action: "update",
+      contact
+    });
+  } else {
+    contact = await Contact.create({
+      name: msgContact.name || msgContact.pushname || msgContact.id.user,
+      number: msgContact.id.user,
+      profilePicUrl
+    });
+
+    io.emit("contact", {
+      action: "create",
+      contact
+    });
+  }
+
+  return contact;
+};
+
+const verifyGroup = async (msgGroupContact: WbotContact) => {
+  const profilePicUrl = await msgGroupContact.getProfilePicUrl();
+
+  let groupContact = await Contact.findOne({
+    where: { number: msgGroupContact.id.user }
+  });
+  if (groupContact) {
+    await groupContact.update({ profilePicUrl });
+  } else {
+    groupContact = await Contact.create({
+      name: msgGroupContact.name,
+      number: msgGroupContact.id.user,
+      isGroup: msgGroupContact.isGroup,
+      profilePicUrl
+    });
+    const io = getIO();
+    io.emit("contact", {
+      action: "create",
+      contact: groupContact
+    });
+  }
+
+  return groupContact;
+};
+
+const verifyTicket = async (
+  contact: Contact,
+  whatsappId: number,
+  groupContact?: Contact
+): Promise<Ticket> => {
+  let ticket = await Ticket.findOne({
+    where: {
+      status: {
+        [Op.or]: ["open", "pending"]
+      },
+      contactId: groupContact ? groupContact.id : contact.id
+    },
+    include: ["contact"]
+  });
+
+  if (!ticket && groupContact) {
+    ticket = await Ticket.findOne({
+      where: {
+        contactId: groupContact.id
+      },
+      order: [["createdAt", "DESC"]],
+      include: ["contact"]
+    });
+
+    if (ticket) {
+      await ticket.update({ status: "pending", userId: null });
+    }
+  }
+
+  if (!ticket) {
+    ticket = await Ticket.findOne({
+      where: {
+        createdAt: {
+          [Op.between]: [+subHours(new Date(), 2), +new Date()]
+        },
+        contactId: groupContact ? groupContact.id : contact.id
+      },
+      order: [["updatedAt", "DESC"]],
+      include: ["contact"]
+    });
+
+    if (ticket) {
+      await ticket.update({ status: "pending", userId: null });
+    }
+  }
+
+  if (!ticket) {
+    const { id } = await Ticket.create({
+      contactId: groupContact ? groupContact.id : contact.id,
+      status: "pending",
+      isGroup: !!groupContact,
+      whatsappId
+    });
+
+    ticket = await ShowTicketService(id);
+  }
+
+  return ticket;
+};
+
+const handlMedia = async (
+  msg: WbotMessage,
+  ticket: Ticket,
+  contact: Contact
+): Promise<Message> => {
+  const media = await msg.downloadMedia();
+
+  if (!media) {
+    throw new AppError("ERR_WAPP_DOWNLOAD_MEDIA");
+  }
+
+  if (!media.filename) {
+    const ext = media.mimetype.split("/")[1].split(";")[0];
+    media.filename = `${new Date().getTime()}.${ext}`;
+  }
+
+  try {
+    await writeFileAsync(
+      join(__dirname, "..", "..", "..", "public", media.filename),
+      media.data,
+      "base64"
+    );
+  } catch (err) {
+    console.log(err);
+  }
+
+  const messageData = {
+    id: msg.id.id,
+    ticketId: ticket.id,
+    contactId: msg.fromMe ? undefined : contact.id,
+    body: msg.body || media.filename,
+    fromMe: msg.fromMe,
+    read: msg.fromMe,
+    mediaUrl: media.filename,
+    mediaType: media.mimetype.split("/")[0]
+  };
+
+  const newMessage = await CreateMessageService({ messageData });
+
+  await ticket.update({ lastMessage: msg.body || media.filename });
+  return newMessage;
+};
+
+const handleMessage = async (
+  msg: WbotMessage,
+  ticket: Ticket,
+  contact: Contact
+) => {
+  let newMessage: Message | null;
+
+  if (msg.hasMedia) {
+    newMessage = await handlMedia(msg, ticket, contact);
+  } else {
+    const messageData = {
+      id: msg.id.id,
+      ticketId: ticket.id,
+      contactId: msg.fromMe ? undefined : contact.id,
+      body: msg.body,
+      fromMe: msg.fromMe,
+      mediaType: msg.type,
+      read: msg.fromMe
+    };
+
+    newMessage = await CreateMessageService({ messageData });
+    await ticket.update({ lastMessage: msg.body });
+  }
+
+  const io = getIO();
+  io.to(ticket.id.toString())
+    .to(ticket.status)
+    .to("notification")
+    .emit("appMessage", {
+      action: "create",
+      message: newMessage,
+      ticket,
+      contact
+    });
+};
+
+const isValidMsg = (msg: WbotMessage): boolean => {
+  if (msg.from === "status@broadcast") return false;
+  if (
+    msg.type === "chat" ||
+    msg.type === "audio" ||
+    msg.type === "ptt" ||
+    msg.type === "video" ||
+    msg.type === "image" ||
+    msg.type === "document" ||
+    msg.type === "vcard" ||
+    msg.type === "sticker"
+  )
+    return true;
+  return false;
+};
+
+const wbotMessageListener = (whatsapp: Whatsapp): void => {
+  const whatsappId = whatsapp.id;
+  const wbot = getWbot(whatsappId);
+  const io = getIO();
+
+  wbot.on("message_create", async msg => {
+    // console.log(msg);
+    if (!isValidMsg(msg)) {
+      return;
+    }
+
+    try {
+      let msgContact: WbotContact;
+      let groupContact: Contact | undefined;
+
+      if (msg.fromMe) {
+        msgContact = await wbot.getContactById(msg.to);
+
+        // return if it's a media message, it will be handled by media_uploaded event
+
+        if (!msg.hasMedia && msg.type !== "chat" && msg.type !== "vcard")
+          return;
+      } else {
+        msgContact = await msg.getContact();
+      }
+
+      const chat = await msg.getChat();
+
+      if (chat.isGroup) {
+        let msgGroupContact;
+
+        if (msg.fromMe) {
+          msgGroupContact = await wbot.getContactById(msg.to);
+        } else {
+          msgGroupContact = await wbot.getContactById(msg.from);
+        }
+
+        groupContact = await verifyGroup(msgGroupContact);
+      }
+
+      const profilePicUrl = await msgContact.getProfilePicUrl();
+      const contact = await verifyContact(msgContact, profilePicUrl);
+      const ticket = await verifyTicket(contact, whatsappId, groupContact);
+
+      await handleMessage(msg, ticket, contact);
+    } catch (err) {
+      Sentry.captureException(err);
+      console.log(err);
+    }
+  });
+
+  wbot.on("media_uploaded", async msg => {
+    try {
+      let groupContact: Contact | undefined;
+      const msgContact = await wbot.getContactById(msg.to);
+      if (msg.author) {
+        const msgGroupContact = await wbot.getContactById(msg.from);
+        groupContact = await verifyGroup(msgGroupContact);
+      }
+
+      const profilePicUrl = await msgContact.getProfilePicUrl();
+      const contact = await verifyContact(msgContact, profilePicUrl);
+      const ticket = await verifyTicket(contact, whatsappId, groupContact);
+
+      await handleMessage(msg, ticket, contact);
+    } catch (err) {
+      Sentry.captureException(err);
+      console.log(err);
+    }
+  });
+
+  wbot.on("message_ack", async (msg, ack) => {
+    await new Promise(r => setTimeout(r, 500));
+
+    try {
+      const messageToUpdate = await Message.findByPk(msg.id.id, {
+        include: ["contact"]
+      });
+      if (!messageToUpdate) {
+        return;
+      }
+      await messageToUpdate.update({ ack });
+
+      io.to(messageToUpdate.ticketId.toString()).emit("appMessage", {
+        action: "update",
+        message: messageToUpdate
+      });
+    } catch (err) {
+      Sentry.captureException(err);
+      console.log(err);
+    }
+  });
+};
+
+export default wbotMessageListener;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WbotServices/wbotMonitor.ts.html b/backend/coverage/lcov-report/WbotServices/wbotMonitor.ts.html new file mode 100644 index 0000000..72601d9 --- /dev/null +++ b/backend/coverage/lcov-report/WbotServices/wbotMonitor.ts.html @@ -0,0 +1,341 @@ + + + + + + Code coverage report for WbotServices/wbotMonitor.ts + + + + + + + + + +
+
+

All files / WbotServices wbotMonitor.ts

+
+ +
+ 0% + Statements + 0/87 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/87 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as Sentry from "@sentry/node";
+
+import wbotMessageListener from "./wbotMessageListener";
+
+import { getIO } from "../../libs/socket";
+import { getWbot, initWbot } from "../../libs/wbot";
+import Whatsapp from "../../models/Whatsapp";
+
+const wbotMonitor = (whatsapp: Whatsapp): void => {
+  const io = getIO();
+  const sessionName = whatsapp.name;
+  const wbot = getWbot(whatsapp.id);
+
+  try {
+    wbot.on("change_state", async newState => {
+      console.log("Monitor session:", sessionName, newState);
+      try {
+        await whatsapp.update({ status: newState });
+      } catch (err) {
+        Sentry.captureException(err);
+        console.log(err);
+      }
+
+      io.emit("whatsappSession", {
+        action: "update",
+        session: whatsapp
+      });
+    });
+
+    wbot.on("change_battery", async batteryInfo => {
+      const { battery, plugged } = batteryInfo;
+      console.log(
+        `Battery session: ${sessionName} ${battery}% - Charging? ${plugged}`
+      );
+
+      try {
+        await whatsapp.update({ battery, plugged });
+      } catch (err) {
+        Sentry.captureException(err);
+        console.log(err);
+      }
+
+      io.emit("whatsappSession", {
+        action: "update",
+        session: whatsapp
+      });
+    });
+
+    wbot.on("disconnected", async reason => {
+      console.log("Disconnected session:", sessionName, reason);
+      try {
+        await whatsapp.update({ status: "disconnected" });
+      } catch (err) {
+        Sentry.captureException(err);
+        console.log(err);
+      }
+
+      io.emit("whatsappSession", {
+        action: "update",
+        session: whatsapp
+      });
+
+      setTimeout(
+        () =>
+          initWbot(whatsapp)
+            .then(() => {
+              wbotMessageListener(whatsapp);
+              wbotMonitor(whatsapp);
+            })
+            .catch(err => {
+              Sentry.captureException(err);
+              console.log(err);
+            }),
+        2000
+      );
+    });
+
+    // setInterval(() => {
+    // 	wbot.resetState();
+    // }, 20000);
+  } catch (err) {
+    Sentry.captureException(err);
+    console.log(err);
+  }
+};
+
+export default wbotMonitor;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WhatsappService/CreateWhatsAppService.ts.html b/backend/coverage/lcov-report/WhatsappService/CreateWhatsAppService.ts.html new file mode 100644 index 0000000..28109ff --- /dev/null +++ b/backend/coverage/lcov-report/WhatsappService/CreateWhatsAppService.ts.html @@ -0,0 +1,278 @@ + + + + + + Code coverage report for WhatsappService/CreateWhatsAppService.ts + + + + + + + + + +
+
+

All files / WhatsappService CreateWhatsAppService.ts

+
+ +
+ 0% + Statements + 0/66 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/66 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as Yup from "yup";
+
+import AppError from "../../errors/AppError";
+import Whatsapp from "../../models/Whatsapp";
+
+interface Request {
+  name: string;
+  status?: string;
+  isDefault?: boolean;
+}
+
+const CreateWhatsAppService = async ({
+  name,
+  status = "INITIALIZING",
+  isDefault = false
+}: Request): Promise<Whatsapp> => {
+  const schema = Yup.object().shape({
+    name: Yup.string()
+      .required()
+      .min(2)
+      .test(
+        "Check-name",
+        "This whatsapp name is already used.",
+        async value => {
+          if (value) {
+            const whatsappFound = await Whatsapp.findOne({
+              where: { name: value }
+            });
+            return !whatsappFound;
+          }
+          return true;
+        }
+      ),
+    isDefault: Yup.boolean()
+      .required()
+      .test(
+        "Check-default",
+        "Only one default whatsapp is permitted",
+        async value => {
+          if (value === true) {
+            const whatsappFound = await Whatsapp.findOne({
+              where: { isDefault: true }
+            });
+            return !whatsappFound;
+          }
+          return true;
+        }
+      )
+  });
+
+  try {
+    await schema.validate({ name, status, isDefault });
+  } catch (err) {
+    throw new AppError(err.message);
+  }
+
+  const whatsapp = await Whatsapp.create({
+    name,
+    status,
+    isDefault
+  });
+
+  return whatsapp;
+};
+
+export default CreateWhatsAppService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WhatsappService/DeleteWhatsAppService.ts.html b/backend/coverage/lcov-report/WhatsappService/DeleteWhatsAppService.ts.html new file mode 100644 index 0000000..bf32354 --- /dev/null +++ b/backend/coverage/lcov-report/WhatsappService/DeleteWhatsAppService.ts.html @@ -0,0 +1,128 @@ + + + + + + Code coverage report for WhatsappService/DeleteWhatsAppService.ts + + + + + + + + + +
+
+

All files / WhatsappService DeleteWhatsAppService.ts

+
+ +
+ 0% + Statements + 0/16 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/16 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import Whatsapp from "../../models/Whatsapp";
+import AppError from "../../errors/AppError";
+
+const DeleteWhatsApprService = async (id: string): Promise<void> => {
+  const whatsapp = await Whatsapp.findOne({
+    where: { id }
+  });
+
+  if (!whatsapp) {
+    throw new AppError("ERR_NO_WAPP_FOUND", 404);
+  }
+
+  await whatsapp.destroy();
+};
+
+export default DeleteWhatsApprService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WhatsappService/ListWhatsAppsService.ts.html b/backend/coverage/lcov-report/WhatsappService/ListWhatsAppsService.ts.html new file mode 100644 index 0000000..e89130a --- /dev/null +++ b/backend/coverage/lcov-report/WhatsappService/ListWhatsAppsService.ts.html @@ -0,0 +1,107 @@ + + + + + + Code coverage report for WhatsappService/ListWhatsAppsService.ts + + + + + + + + + +
+
+

All files / WhatsappService ListWhatsAppsService.ts

+
+ +
+ 0% + Statements + 0/9 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/9 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10  +  +  +  +  +  +  +  +  + 
import Whatsapp from "../../models/Whatsapp";
+
+const ListWhatsAppsService = async (): Promise<Whatsapp[]> => {
+  const whatsapps = await Whatsapp.findAll();
+
+  return whatsapps;
+};
+
+export default ListWhatsAppsService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WhatsappService/ShowWhatsAppService.ts.html b/backend/coverage/lcov-report/WhatsappService/ShowWhatsAppService.ts.html new file mode 100644 index 0000000..f3acd55 --- /dev/null +++ b/backend/coverage/lcov-report/WhatsappService/ShowWhatsAppService.ts.html @@ -0,0 +1,128 @@ + + + + + + Code coverage report for WhatsappService/ShowWhatsAppService.ts + + + + + + + + + +
+
+

All files / WhatsappService ShowWhatsAppService.ts

+
+ +
+ 0% + Statements + 0/16 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/16 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import Whatsapp from "../../models/Whatsapp";
+import AppError from "../../errors/AppError";
+
+const ShowWhatsAppService = async (
+  id: string | number
+): Promise<Whatsapp | undefined> => {
+  const whatsapp = await Whatsapp.findByPk(id);
+
+  if (!whatsapp) {
+    throw new AppError("ERR_NO_WAPP_FOUND", 404);
+  }
+
+  return whatsapp;
+};
+
+export default ShowWhatsAppService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WhatsappService/UpdateWhatsAppService.ts.html b/backend/coverage/lcov-report/WhatsappService/UpdateWhatsAppService.ts.html new file mode 100644 index 0000000..30738d0 --- /dev/null +++ b/backend/coverage/lcov-report/WhatsappService/UpdateWhatsAppService.ts.html @@ -0,0 +1,278 @@ + + + + + + Code coverage report for WhatsappService/UpdateWhatsAppService.ts + + + + + + + + + +
+
+

All files / WhatsappService UpdateWhatsAppService.ts

+
+ +
+ 0% + Statements + 0/66 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/66 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as Yup from "yup";
+
+import AppError from "../../errors/AppError";
+import Whatsapp from "../../models/Whatsapp";
+
+interface WhatsappData {
+  name?: string;
+  status?: string;
+  isDefault?: boolean;
+}
+
+interface Request {
+  whatsappData: WhatsappData;
+  whatsappId: string;
+}
+
+const UpdateWhatsAppService = async ({
+  whatsappData,
+  whatsappId
+}: Request): Promise<Whatsapp> => {
+  const schema = Yup.object().shape({
+    name: Yup.string().min(2),
+    default: Yup.boolean().test(
+      "Check-default",
+      "Only one default whatsapp is permited",
+      async value => {
+        if (value === true) {
+          const whatsappFound = await Whatsapp.findOne({
+            where: { default: true }
+          });
+          if (whatsappFound) {
+            return !(whatsappFound.id !== +whatsappId);
+          }
+          return true;
+        }
+        return true;
+      }
+    )
+  });
+
+  const { name, status, isDefault } = whatsappData;
+
+  try {
+    await schema.validate({ name, status, isDefault });
+  } catch (err) {
+    throw new AppError(err.message);
+  }
+
+  const whatsapp = await Whatsapp.findOne({
+    where: { id: whatsappId }
+  });
+
+  if (!whatsapp) {
+    throw new AppError("ERR_NO_WAPP_FOUND", 404);
+  }
+
+  await whatsapp.update({
+    name,
+    status,
+    isDefault
+  });
+
+  return whatsapp;
+};
+
+export default UpdateWhatsAppService;
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/WhatsappService/index.html b/backend/coverage/lcov-report/WhatsappService/index.html new file mode 100644 index 0000000..7aa1e65 --- /dev/null +++ b/backend/coverage/lcov-report/WhatsappService/index.html @@ -0,0 +1,171 @@ + + + + + + Code coverage report for WhatsappService + + + + + + + + + +
+
+

All files WhatsappService

+
+ +
+ 0% + Statements + 0/173 +
+ + +
+ 0% + Branches + 0/5 +
+ + +
+ 0% + Functions + 0/5 +
+ + +
+ 0% + Lines + 0/173 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
CreateWhatsAppService.ts +
+
0%0/660%0/10%0/10%0/66
DeleteWhatsAppService.ts +
+
0%0/160%0/10%0/10%0/16
ListWhatsAppsService.ts +
+
0%0/90%0/10%0/10%0/9
ShowWhatsAppService.ts +
+
0%0/160%0/10%0/10%0/16
UpdateWhatsAppService.ts +
+
0%0/660%0/10%0/10%0/66
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/base.css b/backend/coverage/lcov-report/base.css new file mode 100644 index 0000000..f418035 --- /dev/null +++ b/backend/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/backend/coverage/lcov-report/block-navigation.js b/backend/coverage/lcov-report/block-navigation.js new file mode 100644 index 0000000..c7ff5a5 --- /dev/null +++ b/backend/coverage/lcov-report/block-navigation.js @@ -0,0 +1,79 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selecter that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/backend/coverage/lcov-report/favicon.png b/backend/coverage/lcov-report/favicon.png new file mode 100644 index 0000000..6691817 Binary files /dev/null and b/backend/coverage/lcov-report/favicon.png differ diff --git a/backend/coverage/lcov-report/index.html b/backend/coverage/lcov-report/index.html new file mode 100644 index 0000000..e176f4d --- /dev/null +++ b/backend/coverage/lcov-report/index.html @@ -0,0 +1,216 @@ + + + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 0% + Statements + 0/1742 +
+ + +
+ 0% + Branches + 0/35 +
+ + +
+ 0% + Functions + 0/35 +
+ + +
+ 0% + Lines + 0/1742 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
AuthServices +
+
0%0/410%0/10%0/10%0/41
ContactServices +
+
0%0/1960%0/50%0/50%0/196
MessageServices +
+
0%0/1030%0/20%0/20%0/103
SettingServices +
+
0%0/350%0/20%0/20%0/35
TicketServices +
+
0%0/2940%0/50%0/50%0/294
UserServices +
+
0%0/2760%0/60%0/60%0/276
WbotServices +
+
0%0/6240%0/90%0/90%0/624
WhatsappService +
+
0%0/1730%0/50%0/50%0/173
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/backend/coverage/lcov-report/prettify.css b/backend/coverage/lcov-report/prettify.css new file mode 100644 index 0000000..b317a7c --- /dev/null +++ b/backend/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/backend/coverage/lcov-report/prettify.js b/backend/coverage/lcov-report/prettify.js new file mode 100644 index 0000000..b322523 --- /dev/null +++ b/backend/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/backend/coverage/lcov-report/sort-arrow-sprite.png b/backend/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 0000000..03f704a Binary files /dev/null and b/backend/coverage/lcov-report/sort-arrow-sprite.png differ diff --git a/backend/coverage/lcov-report/sorter.js b/backend/coverage/lcov-report/sorter.js new file mode 100644 index 0000000..16de10c --- /dev/null +++ b/backend/coverage/lcov-report/sorter.js @@ -0,0 +1,170 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/backend/coverage/lcov.info b/backend/coverage/lcov.info new file mode 100644 index 0000000..6eb2e70 --- /dev/null +++ b/backend/coverage/lcov.info @@ -0,0 +1,2162 @@ +TN: +SF:src/services/AuthServices/RefreshTokenService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +LF:41 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/ContactServices/CreateContactService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +LF:46 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/ContactServices/DeleteContactService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +LF:16 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/ContactServices/ListContactsService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +LF:50 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/ContactServices/ShowContactService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +LF:14 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/ContactServices/UpdateContactService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:70,0 +LF:70 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/MessageServices/CreateMessageService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +LF:41 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/MessageServices/ListMessagesService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +LF:62 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/SettingServices/ListSettingsService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +LF:9 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/SettingServices/UpdateSettingService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +LF:26 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/TicketServices/CreateTicketService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +LF:40 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/TicketServices/DeleteTicketService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +LF:18 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/TicketServices/ListTicketsService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:93,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:99,0 +DA:100,0 +DA:101,0 +DA:102,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:106,0 +DA:107,0 +DA:108,0 +DA:109,0 +DA:110,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:116,0 +DA:117,0 +DA:118,0 +DA:119,0 +DA:120,0 +DA:121,0 +DA:122,0 +DA:123,0 +DA:124,0 +DA:125,0 +DA:126,0 +DA:127,0 +DA:128,0 +DA:129,0 +DA:130,0 +DA:131,0 +DA:132,0 +DA:133,0 +DA:134,0 +DA:135,0 +DA:136,0 +DA:137,0 +DA:138,0 +DA:139,0 +DA:140,0 +DA:141,0 +DA:142,0 +DA:143,0 +DA:144,0 +LF:144 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/TicketServices/ShowTicketService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +LF:30 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/TicketServices/UpdateTicketService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +LF:62 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/UserServices/AuthUserSerice.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +LF:45 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/UserServices/CreateUserService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:70,0 +LF:70 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/UserServices/DeleteUserService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +LF:26 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/UserServices/ListUsersService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +LF:51 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/UserServices/ShowUserService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +LF:16 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/UserServices/UpdateUserService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +LF:68 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WbotServices/CheckIsValidContact.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +LF:24 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WbotServices/DeleteWhatsAppMessage.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +LF:36 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WbotServices/GetProfilePicUrl.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +LF:14 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WbotServices/ImportContactsService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +LF:43 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WbotServices/SendWhatsAppMedia.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +LF:38 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WbotServices/SendWhatsAppMessage.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +LF:31 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WbotServices/StartWhatsAppSessions.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +LF:18 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WbotServices/wbotMessageListener.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:93,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:99,0 +DA:100,0 +DA:101,0 +DA:102,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:106,0 +DA:107,0 +DA:108,0 +DA:109,0 +DA:110,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:116,0 +DA:117,0 +DA:118,0 +DA:119,0 +DA:120,0 +DA:121,0 +DA:122,0 +DA:123,0 +DA:124,0 +DA:125,0 +DA:126,0 +DA:127,0 +DA:128,0 +DA:129,0 +DA:130,0 +DA:131,0 +DA:132,0 +DA:133,0 +DA:134,0 +DA:135,0 +DA:136,0 +DA:137,0 +DA:138,0 +DA:139,0 +DA:140,0 +DA:141,0 +DA:142,0 +DA:143,0 +DA:144,0 +DA:145,0 +DA:146,0 +DA:147,0 +DA:148,0 +DA:149,0 +DA:150,0 +DA:151,0 +DA:152,0 +DA:153,0 +DA:154,0 +DA:155,0 +DA:156,0 +DA:157,0 +DA:158,0 +DA:159,0 +DA:160,0 +DA:161,0 +DA:162,0 +DA:163,0 +DA:164,0 +DA:165,0 +DA:166,0 +DA:167,0 +DA:168,0 +DA:169,0 +DA:170,0 +DA:171,0 +DA:172,0 +DA:173,0 +DA:174,0 +DA:175,0 +DA:176,0 +DA:177,0 +DA:178,0 +DA:179,0 +DA:180,0 +DA:181,0 +DA:182,0 +DA:183,0 +DA:184,0 +DA:185,0 +DA:186,0 +DA:187,0 +DA:188,0 +DA:189,0 +DA:190,0 +DA:191,0 +DA:192,0 +DA:193,0 +DA:194,0 +DA:195,0 +DA:196,0 +DA:197,0 +DA:198,0 +DA:199,0 +DA:200,0 +DA:201,0 +DA:202,0 +DA:203,0 +DA:204,0 +DA:205,0 +DA:206,0 +DA:207,0 +DA:208,0 +DA:209,0 +DA:210,0 +DA:211,0 +DA:212,0 +DA:213,0 +DA:214,0 +DA:215,0 +DA:216,0 +DA:217,0 +DA:218,0 +DA:219,0 +DA:220,0 +DA:221,0 +DA:222,0 +DA:223,0 +DA:224,0 +DA:225,0 +DA:226,0 +DA:227,0 +DA:228,0 +DA:229,0 +DA:230,0 +DA:231,0 +DA:232,0 +DA:233,0 +DA:234,0 +DA:235,0 +DA:236,0 +DA:237,0 +DA:238,0 +DA:239,0 +DA:240,0 +DA:241,0 +DA:242,0 +DA:243,0 +DA:244,0 +DA:245,0 +DA:246,0 +DA:247,0 +DA:248,0 +DA:249,0 +DA:250,0 +DA:251,0 +DA:252,0 +DA:253,0 +DA:254,0 +DA:255,0 +DA:256,0 +DA:257,0 +DA:258,0 +DA:259,0 +DA:260,0 +DA:261,0 +DA:262,0 +DA:263,0 +DA:264,0 +DA:265,0 +DA:266,0 +DA:267,0 +DA:268,0 +DA:269,0 +DA:270,0 +DA:271,0 +DA:272,0 +DA:273,0 +DA:274,0 +DA:275,0 +DA:276,0 +DA:277,0 +DA:278,0 +DA:279,0 +DA:280,0 +DA:281,0 +DA:282,0 +DA:283,0 +DA:284,0 +DA:285,0 +DA:286,0 +DA:287,0 +DA:288,0 +DA:289,0 +DA:290,0 +DA:291,0 +DA:292,0 +DA:293,0 +DA:294,0 +DA:295,0 +DA:296,0 +DA:297,0 +DA:298,0 +DA:299,0 +DA:300,0 +DA:301,0 +DA:302,0 +DA:303,0 +DA:304,0 +DA:305,0 +DA:306,0 +DA:307,0 +DA:308,0 +DA:309,0 +DA:310,0 +DA:311,0 +DA:312,0 +DA:313,0 +DA:314,0 +DA:315,0 +DA:316,0 +DA:317,0 +DA:318,0 +DA:319,0 +DA:320,0 +DA:321,0 +DA:322,0 +DA:323,0 +DA:324,0 +DA:325,0 +DA:326,0 +DA:327,0 +DA:328,0 +DA:329,0 +DA:330,0 +DA:331,0 +DA:332,0 +DA:333,0 +LF:333 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WbotServices/wbotMonitor.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +LF:87 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WhatsappService/CreateWhatsAppService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +LF:66 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WhatsappService/DeleteWhatsAppService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +LF:16 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WhatsappService/ListWhatsAppsService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +LF:9 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WhatsappService/ShowWhatsAppService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +LF:16 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/services/WhatsappService/UpdateWhatsAppService.ts +FN:1,(empty-report) +FNF:1 +FNH:0 +FNDA:0,(empty-report) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +LF:66 +LH:0 +BRDA:1,0,0,0 +BRF:1 +BRH:0 +end_of_record diff --git a/backend/jest.config.js b/backend/jest.config.js new file mode 100644 index 0000000..76c1b57 --- /dev/null +++ b/backend/jest.config.js @@ -0,0 +1,186 @@ +/* + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/en/configuration.html + */ + +module.exports = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + bail: 1, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/tmp/jest_rs", + + // Automatically clear mock calls and instances between every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + collectCoverageFrom: ["/src/services/**/*.ts"], + + // The directory where Jest should output its coverage files + coverageDirectory: "coverage", + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: "v8", + + // A list of reporter names that Jest uses when writing coverage reports + coverageReporters: ["text", "lcov"], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "json", + // "jsx", + // "ts", + // "tsx", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + preset: "ts-jest", + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state between every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state between every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: "node", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + testMatch: ["**/__tests__/**/*.spec.ts"] + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jasmine2", + + // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href + // testURL: "http://localhost", + + // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" + // timers: "real", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; diff --git a/backend/package.json b/backend/package.json index edf2cf6..58ce482 100644 --- a/backend/package.json +++ b/backend/package.json @@ -7,7 +7,10 @@ "build": "tsc", "watch": "tsc -w", "start": "nodemon dist/server.js", - "dev:server": "ts-node-dev --respawn --transpile-only --ignore node_modules src/server.ts" + "dev:server": "ts-node-dev --respawn --transpile-only --ignore node_modules src/server.ts", + "pretest": "NODE_ENV=test sequelize db:migrate", + "test": "NODE_ENV=test jest", + "posttest": "NODE_ENV=test sequelize db:migrate:undo:all" }, "author": "", "license": "MIT", @@ -39,6 +42,7 @@ "@types/cookie-parser": "^1.4.2", "@types/cors": "^2.8.7", "@types/express": "^4.17.8", + "@types/jest": "^26.0.15", "@types/jsonwebtoken": "^8.5.0", "@types/multer": "^1.4.4", "@types/node": "^14.11.8", @@ -53,8 +57,10 @@ "eslint-import-resolver-typescript": "^2.3.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-prettier": "^3.1.4", + "jest": "^26.6.0", "nodemon": "^2.0.4", "prettier": "^2.1.2", + "ts-jest": "^26.4.1", "ts-node-dev": "^1.0.0-pre.63", "typescript": "^4.0.3" } diff --git a/backend/src/__tests__/CreateUserService.spec.ts b/backend/src/__tests__/CreateUserService.spec.ts new file mode 100644 index 0000000..55a66bc --- /dev/null +++ b/backend/src/__tests__/CreateUserService.spec.ts @@ -0,0 +1,3 @@ +test("sum two number", () => { + expect(1 + 2).toBe(3); +}); diff --git a/backend/src/bootstrap.ts b/backend/src/bootstrap.ts new file mode 100644 index 0000000..03fffb5 --- /dev/null +++ b/backend/src/bootstrap.ts @@ -0,0 +1,5 @@ +import dotenv from "dotenv"; + +dotenv.config({ + path: process.env.NODE_ENV === "test" ? ".env.test" : ".env" +}); diff --git a/backend/src/config/database.ts b/backend/src/config/database.ts index 9e4d184..58a1c26 100644 --- a/backend/src/config/database.ts +++ b/backend/src/config/database.ts @@ -1,4 +1,4 @@ -require("dotenv/config"); +require("../bootstrap"); module.exports = { define: { @@ -11,5 +11,6 @@ module.exports = { database: process.env.DB_NAME, username: process.env.DB_USER, password: process.env.DB_PASS, + storage: "./src/__tests__/database.sqlite", logging: false }; diff --git a/backend/src/server.ts b/backend/src/server.ts index 1225df6..e090f7f 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -1,5 +1,5 @@ +import "./bootstrap"; import "reflect-metadata"; -import "dotenv/config"; import "express-async-errors"; import express, { Request, Response, NextFunction } from "express"; import cors from "cors"; diff --git a/backend/tsconfig.json b/backend/tsconfig.json index dcfe622..95db251 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -1,69 +1,14 @@ { "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, - "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - // "lib": [], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./dist" /* Redirect output structure to the directory. */, - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - "strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */, - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - - /* Module Resolution Options */ - // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, - "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, - - /* Advanced Options */ - "skipLibCheck": true /* Skip type checking of declaration files. */, - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + "target": "es6", + "module": "commonjs", + "outDir": "./dist", + "strict": true, + "strictPropertyInitialization": false, + "esModuleInterop": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true } }