Compare commits

..

3 Commits

Author SHA1 Message Date
Balu Babu
bc562e547e Merge branch 'release/2024.3.2' into fix/sh-email-handlebar-issue 2024-04-29 11:52:33 +05:30
Joel Jacob Stephen
c2c4e620c2 fix(common): rest and graphql pages not being rendered when french is selected as app language (#4004)
Co-authored-by: nivedin <nivedinp@gmail.com>
2024-04-25 18:01:46 +05:30
Balu Babu
e9c9dc19bf fix: resolved mailer module email issue 2024-04-23 16:22:34 +05:30
6 changed files with 109 additions and 68 deletions

View File

@@ -3,9 +3,7 @@
"collection": "@nestjs/schematics", "collection": "@nestjs/schematics",
"sourceRoot": "src", "sourceRoot": "src",
"compilerOptions": { "compilerOptions": {
"assets": [ "assets": [{ "include": "mailer/templates/**/*", "outDir": "dist" }],
"**/*.hbs"
],
"watchAssets": true "watchAssets": true
} }
} }

View File

@@ -11,7 +11,6 @@ import {
EMAIL_FAILED, EMAIL_FAILED,
INVALID_EMAIL, INVALID_EMAIL,
ONLY_ONE_ADMIN_ACCOUNT, ONLY_ONE_ADMIN_ACCOUNT,
TEAM_INVALID_ID,
TEAM_INVITE_ALREADY_MEMBER, TEAM_INVITE_ALREADY_MEMBER,
TEAM_INVITE_NO_INVITE_FOUND, TEAM_INVITE_NO_INVITE_FOUND,
USERS_NOT_FOUND, USERS_NOT_FOUND,
@@ -319,11 +318,11 @@ export class AdminService {
const user = await this.userService.findUserByEmail(userEmail); const user = await this.userService.findUserByEmail(userEmail);
if (O.isNone(user)) return E.left(USER_NOT_FOUND); if (O.isNone(user)) return E.left(USER_NOT_FOUND);
const teamMember = await this.teamService.getTeamMember( const teamMember = await this.teamService.getTeamMemberTE(
teamID, teamID,
user.value.uid, user.value.uid,
); )();
if (!teamMember) { if (E.isLeft(teamMember)) {
const addedUser = await this.teamService.addMemberToTeamWithEmail( const addedUser = await this.teamService.addMemberToTeamWithEmail(
teamID, teamID,
userEmail, userEmail,
@@ -591,9 +590,9 @@ export class AdminService {
* @returns an Either of `Team` or error * @returns an Either of `Team` or error
*/ */
async getTeamInfo(teamID: string) { async getTeamInfo(teamID: string) {
const team = await this.teamService.getTeamWithID(teamID); const team = await this.teamService.getTeamWithIDTE(teamID)();
if (!team) return E.left(TEAM_INVALID_ID); if (E.isLeft(team)) return E.left(team.left);
return E.right(team); return E.right(team.right);
} }
/** /**

View File

@@ -15,11 +15,7 @@ import * as TE from 'fp-ts/TaskEither';
import * as E from 'fp-ts/Either'; import * as E from 'fp-ts/Either';
import * as O from 'fp-ts/Option'; import * as O from 'fp-ts/Option';
import { Team, TeamMember, TeamMemberRole } from 'src/team/team.model'; import { Team, TeamMember, TeamMemberRole } from 'src/team/team.model';
import { import { TEAM_INVITE_NO_INVITE_FOUND, USER_NOT_FOUND } from 'src/errors';
TEAM_INVALID_ID,
TEAM_INVITE_NO_INVITE_FOUND,
USER_NOT_FOUND,
} from 'src/errors';
import { GqlUser } from 'src/decorators/gql-user.decorator'; import { GqlUser } from 'src/decorators/gql-user.decorator';
import { User } from 'src/user/user.model'; import { User } from 'src/user/user.model';
import { UseGuards } from '@nestjs/common'; import { UseGuards } from '@nestjs/common';
@@ -54,9 +50,10 @@ export class TeamInvitationResolver {
description: 'Get the team associated to the invite', description: 'Get the team associated to the invite',
}) })
async team(@Parent() teamInvitation: TeamInvitation): Promise<Team> { async team(@Parent() teamInvitation: TeamInvitation): Promise<Team> {
const team = await this.teamService.getTeamWithID(teamInvitation.teamID); return pipe(
if (!team) throwErr(TEAM_INVALID_ID); this.teamService.getTeamWithIDTE(teamInvitation.teamID),
return team; TE.getOrElse(throwErr),
)();
} }
@ResolveField(() => User, { @ResolveField(() => User, {

View File

@@ -11,7 +11,6 @@ import {
} from '../errors'; } from '../errors';
import { mockDeep, mockReset } from 'jest-mock-extended'; import { mockDeep, mockReset } from 'jest-mock-extended';
import * as O from 'fp-ts/Option'; import * as O from 'fp-ts/Option';
import { skip } from 'rxjs';
const mockPrisma = mockDeep<PrismaService>(); const mockPrisma = mockDeep<PrismaService>();
@@ -756,8 +755,6 @@ describe('getMembersOfTeam', () => {
expect(mockPrisma.teamMember.findMany).toHaveBeenCalledWith({ expect(mockPrisma.teamMember.findMany).toHaveBeenCalledWith({
take: 10, take: 10,
skip: 0,
cursor: undefined,
where: { where: {
teamID: team.id, teamID: team.id,
}, },
@@ -809,8 +806,6 @@ describe('getTeamsOfUser', () => {
expect(mockPrisma.teamMember.findMany).toHaveBeenCalledWith({ expect(mockPrisma.teamMember.findMany).toHaveBeenCalledWith({
take: 10, take: 10,
skip: 0,
cursor: undefined,
where: { where: {
userUid: dbTeamMember.userUid, userUid: dbTeamMember.userUid,
}, },

View File

@@ -15,6 +15,7 @@ import {
} from '../errors'; } from '../errors';
import { PubSubService } from '../pubsub/pubsub.service'; import { PubSubService } from '../pubsub/pubsub.service';
import { flow, pipe } from 'fp-ts/function'; import { flow, pipe } from 'fp-ts/function';
import * as TE from 'fp-ts/TaskEither';
import * as TO from 'fp-ts/TaskOption'; import * as TO from 'fp-ts/TaskOption';
import * as O from 'fp-ts/Option'; import * as O from 'fp-ts/Option';
import * as E from 'fp-ts/Either'; import * as E from 'fp-ts/Either';
@@ -263,25 +264,37 @@ export class TeamService implements UserDataHandler, OnModuleInit {
} }
async getTeamsOfUser(uid: string, cursor: string | null): Promise<Team[]> { async getTeamsOfUser(uid: string, cursor: string | null): Promise<Team[]> {
const entries = await this.prisma.teamMember.findMany({ if (!cursor) {
take: 10, const entries = await this.prisma.teamMember.findMany({
skip: cursor ? 1 : 0, take: 10,
cursor: cursor where: {
? { userUid: uid,
teamID_userUid: { },
teamID: cursor, include: {
userUid: uid, team: true,
}, },
} });
: undefined,
where: { return entries.map((entry) => entry.team);
userUid: uid, } else {
}, const entries = await this.prisma.teamMember.findMany({
include: { take: 10,
team: true, skip: 1,
}, cursor: {
}); teamID_userUid: {
return entries.map((entry) => entry.team); teamID: cursor,
userUid: uid,
},
},
where: {
userUid: uid,
},
include: {
team: true,
},
});
return entries.map((entry) => entry.team);
}
} }
async getTeamWithID(teamID: string): Promise<Team | null> { async getTeamWithID(teamID: string): Promise<Team | null> {
@@ -298,6 +311,19 @@ export class TeamService implements UserDataHandler, OnModuleInit {
} }
} }
getTeamWithIDTE(teamID: string): TE.TaskEither<'team/invalid_id', Team> {
return pipe(
() => this.getTeamWithID(teamID),
TE.fromTask,
TE.chain(
TE.fromPredicate(
(x): x is Team => !!x,
() => TEAM_INVALID_ID,
),
),
);
}
/** /**
* Filters out team members that we weren't able to match * Filters out team members that we weren't able to match
* (also deletes the membership) * (also deletes the membership)
@@ -349,6 +375,19 @@ export class TeamService implements UserDataHandler, OnModuleInit {
} }
} }
getTeamMemberTE(teamID: string, userUid: string) {
return pipe(
() => this.getTeamMember(teamID, userUid),
TE.fromTask,
TE.chain(
TE.fromPredicate(
(x): x is TeamMember => !!x,
() => TEAM_MEMBER_NOT_FOUND,
),
),
);
}
async getRoleOfUserInTeam( async getRoleOfUserInTeam(
teamID: string, teamID: string,
userUid: string, userUid: string,
@@ -433,12 +472,25 @@ export class TeamService implements UserDataHandler, OnModuleInit {
): Promise<TeamMember[]> { ): Promise<TeamMember[]> {
let teamMembers: DbTeamMember[]; let teamMembers: DbTeamMember[];
teamMembers = await this.prisma.teamMember.findMany({ if (!cursor) {
take: 10, teamMembers = await this.prisma.teamMember.findMany({
skip: cursor ? 1 : 0, take: 10,
cursor: cursor ? { id: cursor } : undefined, where: {
where: { teamID }, teamID,
}); },
});
} else {
teamMembers = await this.prisma.teamMember.findMany({
take: 10,
skip: 1,
cursor: {
id: cursor,
},
where: {
teamID,
},
});
}
const members = teamMembers.map( const members = teamMembers.map(
(entry) => (entry) =>

View File

@@ -58,24 +58,6 @@
"new": "Ajouter un nouveau", "new": "Ajouter un nouveau",
"star": "Ajouter une étoile" "star": "Ajouter une étoile"
}, },
"cookies": {
"modal": {
"new_domain_name": "Nouveau nom de domaine",
"set": "Définir un cookie",
"cookie_string": "Chaîne de caractères de cookie",
"enter_cookie_string": "Saisir la chaîne de caractères du cookie",
"cookie_name": "Nom",
"cookie_value": "Valeur",
"cookie_path": "Chemin d'accès",
"cookie_expires": "Expiration",
"managed_tab": "Gestion",
"raw_tab": "Brut",
"interceptor_no_support": "L'intercepteur que vous avez sélectionné ne prend pas en charge les cookies. Sélectionnez un autre intercepteur et réessayez.",
"empty_domains": "La liste des domaines est vide",
"empty_domain": "Le domaine est vide",
"no_cookies_in_domain": "Aucun cookie n'est défini pour ce domaine"
}
},
"app": { "app": {
"chat_with_us": "Discuter avec nous", "chat_with_us": "Discuter avec nous",
"contact_us": "Nous contacter", "contact_us": "Nous contacter",
@@ -187,7 +169,7 @@
}, },
"confirm": { "confirm": {
"close_unsaved_tab": "Êtes-vous sûr de vouloir fermer cet onglet ?", "close_unsaved_tab": "Êtes-vous sûr de vouloir fermer cet onglet ?",
"close_unsaved_tabs": "Êtes-vous sûr de vouloir fermer tous les onglets ? {Les onglets non enregistrés seront perdus.", "close_unsaved_tabs": "Êtes-vous sûr de vouloir fermer tous les onglets ? {count} onglets non enregistrés seront perdus",
"exit_team": "Êtes-vous sûr de vouloir quitter cette équipe ?", "exit_team": "Êtes-vous sûr de vouloir quitter cette équipe ?",
"logout": "Êtes-vous sûr de vouloir vous déconnecter?", "logout": "Êtes-vous sûr de vouloir vous déconnecter?",
"remove_collection": "Voulez-vous vraiment supprimer définitivement cette collection ?", "remove_collection": "Voulez-vous vraiment supprimer définitivement cette collection ?",
@@ -207,6 +189,24 @@
"open_request_in_new_tab": "Ouvrir la demande dans un nouvel onglet", "open_request_in_new_tab": "Ouvrir la demande dans un nouvel onglet",
"set_environment_variable": "Définir comme variable" "set_environment_variable": "Définir comme variable"
}, },
"cookies": {
"modal": {
"new_domain_name": "Nouveau nom de domaine",
"set": "Définir un cookie",
"cookie_string": "Chaîne de caractères de cookie",
"enter_cookie_string": "Saisir la chaîne de caractères du cookie",
"cookie_name": "Nom",
"cookie_value": "Valeur",
"cookie_path": "Chemin d'accès",
"cookie_expires": "Expiration",
"managed_tab": "Gestion",
"raw_tab": "Brut",
"interceptor_no_support": "L'intercepteur que vous avez sélectionné ne prend pas en charge les cookies. Sélectionnez un autre intercepteur et réessayez.",
"empty_domains": "La liste des domaines est vide",
"empty_domain": "Le domaine est vide",
"no_cookies_in_domain": "Aucun cookie n'est défini pour ce domaine"
}
},
"count": { "count": {
"header": "En-tête {count}", "header": "En-tête {count}",
"message": "Message {compte}", "message": "Message {compte}",
@@ -410,7 +410,7 @@
"description": "Inspecter les erreurs possibles", "description": "Inspecter les erreurs possibles",
"environment": { "environment": {
"add_environment": "Ajouter à l'environnement", "add_environment": "Ajouter à l'environnement",
"not_found": "La variable d'environnement “{environnement}“ n'a pas été trouvée." "not_found": "La variable d'environnement “{environment}“ n'a pas été trouvée."
}, },
"header": { "header": {
"cookie": "Le navigateur ne permet pas à Hoppscotch de définir l'en-tête Cookie. Pendant que nous travaillons sur l'application de bureau Hoppscotch (bientôt disponible), veuillez utiliser l'en-tête d'autorisation à la place." "cookie": "Le navigateur ne permet pas à Hoppscotch de définir l'en-tête Cookie. Pendant que nous travaillons sur l'application de bureau Hoppscotch (bientôt disponible), veuillez utiliser l'en-tête d'autorisation à la place."