зеркало из https://github.com/mozilla/fxa.git
Merge pull request #13827 from mozilla/revert-13742-FXA-5555-add-logging-to-the-admin-tool
Revert "task(admin-panel): Add event logging for analytics"
This commit is contained in:
Коммит
66b10b6f5e
|
@ -7,7 +7,7 @@ import Chance from 'chance';
|
|||
import { render, fireEvent, act, screen } from '@testing-library/react';
|
||||
import { MockedProvider, MockedResponse } from '@apollo/client/testing';
|
||||
import { CLEAR_BOUNCES_BY_EMAIL } from './Account/index';
|
||||
import { GET_ACCOUNT_BY_EMAIL, AccountSearch, GET_EMAILS_LIKE } from './index';
|
||||
import { GET_ACCOUNT_BY_EMAIL, AccountSearch } from './index';
|
||||
|
||||
const chance = new Chance();
|
||||
let testEmail: string;
|
||||
|
@ -141,43 +141,11 @@ function exampleBounceMutationResponse(email: string): MockedResponse {
|
|||
};
|
||||
}
|
||||
|
||||
const MinimalAccountResponse = (testEmail: string) => ({
|
||||
data: {
|
||||
accountByEmail: {
|
||||
uid: '123',
|
||||
createdAt: 1658534643990,
|
||||
disabledAt: null,
|
||||
lockedAt: null,
|
||||
emails: [
|
||||
{
|
||||
email: testEmail,
|
||||
isVerified: true,
|
||||
isPrimary: true,
|
||||
createdAt: 1658534643990,
|
||||
},
|
||||
],
|
||||
emailBounces: [],
|
||||
securityEvents: [],
|
||||
totp: [],
|
||||
recoveryKeys: [],
|
||||
linkedAccounts: [],
|
||||
attachedClients: [],
|
||||
subscriptions: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const nextTick = (t?: number) => new Promise((r) => setTimeout(r, t || 0));
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(window, 'confirm').mockImplementation(() => true);
|
||||
testEmail = chance.email();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders without imploding', () => {
|
||||
const renderResult = render(<AccountSearch />);
|
||||
const getByTestId = renderResult.getByTestId;
|
||||
|
@ -185,114 +153,6 @@ it('renders without imploding', () => {
|
|||
expect(getByTestId('search-form')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls account search', async () => {
|
||||
let calledAccountSearch = false;
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: GET_ACCOUNT_BY_EMAIL,
|
||||
variables: {
|
||||
email: testEmail,
|
||||
autoCompleted: false,
|
||||
},
|
||||
},
|
||||
result: () => {
|
||||
calledAccountSearch = true;
|
||||
return MinimalAccountResponse(testEmail);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const renderResult = render(
|
||||
<MockedProvider mocks={mocks} addTypename={false}>
|
||||
<AccountSearch />
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.change(renderResult.getByTestId('email-input'), {
|
||||
target: { value: testEmail },
|
||||
});
|
||||
fireEvent.blur(renderResult.getByTestId('email-input'));
|
||||
});
|
||||
await nextTick();
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(renderResult.getByTestId('search-button'));
|
||||
});
|
||||
await nextTick();
|
||||
|
||||
expect(renderResult.getByTestId('account-section')).toBeInTheDocument();
|
||||
expect(calledAccountSearch).toBeTruthy();
|
||||
});
|
||||
|
||||
it('auto completes', async () => {
|
||||
let calledAccountSearch = false;
|
||||
let calledGetEmailsLike = false;
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: GET_EMAILS_LIKE,
|
||||
variables: {
|
||||
search: testEmail.substring(0, 6),
|
||||
},
|
||||
},
|
||||
result: () => {
|
||||
calledGetEmailsLike = true;
|
||||
return {
|
||||
data: {
|
||||
getEmailsLike: [{ email: testEmail }],
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
request: {
|
||||
query: GET_ACCOUNT_BY_EMAIL,
|
||||
variables: {
|
||||
email: testEmail,
|
||||
autoCompleted: true,
|
||||
},
|
||||
},
|
||||
result: () => {
|
||||
calledAccountSearch = true;
|
||||
return MinimalAccountResponse(testEmail);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const renderResult = render(
|
||||
<MockedProvider mocks={mocks} addTypename={false}>
|
||||
<AccountSearch />
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.change(renderResult.getByTestId('email-input'), {
|
||||
target: { value: testEmail.substring(0, 6) },
|
||||
});
|
||||
fireEvent.blur(renderResult.getByTestId('email-input'));
|
||||
});
|
||||
await nextTick();
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(
|
||||
renderResult.getByTestId('email-suggestions').getElementsByTagName('a')[0]
|
||||
);
|
||||
});
|
||||
await nextTick();
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(renderResult.getByTestId('search-button'));
|
||||
});
|
||||
await nextTick();
|
||||
|
||||
expect(calledGetEmailsLike).toBeTruthy();
|
||||
expect(calledAccountSearch).toBeTruthy();
|
||||
expect(renderResult.getByTestId('email-input')).toHaveValue(testEmail);
|
||||
expect(renderResult.getByTestId('account-section')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// FIXME: this test is flaky
|
||||
it.skip('displays the account email bounces, and can clear them', async () => {
|
||||
const hasResultsAccountResponse = exampleAccountResponse(testEmail);
|
||||
|
|
|
@ -84,8 +84,8 @@ const ACCOUNT_SCHEMA = `
|
|||
}
|
||||
`;
|
||||
export const GET_ACCOUNT_BY_EMAIL = gql`
|
||||
query getAccountByEmail($email: String!, $autoCompleted: Boolean!) {
|
||||
accountByEmail(email: $email, autoCompleted:$autoCompleted) {
|
||||
query getAccountByEmail($email: String!) {
|
||||
accountByEmail(email: $email) {
|
||||
${ACCOUNT_SCHEMA}
|
||||
}
|
||||
}
|
||||
|
@ -117,11 +117,9 @@ export const AccountSearch = () => {
|
|||
const [showResult, setShowResult] = useState<boolean>(false);
|
||||
const [showSuggestion, setShowSuggestion] = useState<boolean>(false);
|
||||
const [searchInput, setSearchInput] = useState<string>('');
|
||||
const [selectedSuggestion, setSelectedSuggestion] = useState<string>('');
|
||||
|
||||
// define two queries to search by either email or uid.
|
||||
const [getAccountByEmail, emailResults] = useLazyQuery(GET_ACCOUNT_BY_EMAIL);
|
||||
const [getAccountByUID, uidResults] = useLazyQuery(GET_ACCOUNT_BY_UID);
|
||||
const [getAccountbyEmail, emailResults] = useLazyQuery(GET_ACCOUNT_BY_EMAIL);
|
||||
const [getAccountbyUID, uidResults] = useLazyQuery(GET_ACCOUNT_BY_UID);
|
||||
// choose which query result to show based on type of query made
|
||||
const [isEmail, setIsEmail] = useState<boolean>(false);
|
||||
const queryResults = isEmail && showResult ? emailResults : uidResults;
|
||||
|
@ -132,13 +130,10 @@ export const AccountSearch = () => {
|
|||
const trimmedSearchInput = searchInput.trim();
|
||||
event.preventDefault();
|
||||
const isUID = validateUID(trimmedSearchInput);
|
||||
|
||||
// choose correct query if email or uid
|
||||
if (isUID) {
|
||||
// uid and non-empty
|
||||
getAccountByUID({
|
||||
variables: { uid: trimmedSearchInput, autoCompleted: false },
|
||||
});
|
||||
getAccountbyUID({ variables: { uid: trimmedSearchInput } });
|
||||
setIsEmail(false);
|
||||
setShowResult(true);
|
||||
} else if (
|
||||
|
@ -147,12 +142,7 @@ export const AccountSearch = () => {
|
|||
trimmedSearchInput !== ''
|
||||
) {
|
||||
// assume email if not uid and non-empty; must at least have '@'
|
||||
getAccountByEmail({
|
||||
variables: {
|
||||
email: trimmedSearchInput,
|
||||
autoCompleted: selectedSuggestion === trimmedSearchInput,
|
||||
},
|
||||
});
|
||||
getAccountbyEmail({ variables: { email: trimmedSearchInput } });
|
||||
setIsEmail(true);
|
||||
setShowResult(true);
|
||||
}
|
||||
|
@ -188,7 +178,6 @@ export const AccountSearch = () => {
|
|||
|
||||
const suggestionSelected = (value: string) => {
|
||||
setSearchInput(value);
|
||||
setSelectedSuggestion(value);
|
||||
setShowSuggestion(false);
|
||||
};
|
||||
|
||||
|
@ -262,10 +251,7 @@ export const AccountSearch = () => {
|
|||
/>
|
||||
</button>
|
||||
{showSuggestion && filteredList.length > 0 && (
|
||||
<div
|
||||
className="suggestions-list absolute top-full w-full bg-white border border-grey-100 mt-3 shadow-sm rounded overflow-hidden"
|
||||
data-testid="email-suggestions"
|
||||
>
|
||||
<div className="suggestions-list absolute top-full w-full bg-white border border-grey-100 mt-3 shadow-sm rounded overflow-hidden">
|
||||
{renderSuggestions()}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -20,7 +20,6 @@ import { UserGroupGuard } from './auth/user-group-header.guard';
|
|||
import Config, { AppConfig } from './config';
|
||||
import { DatabaseModule } from './database/database.module';
|
||||
import { DatabaseService } from './database/database.service';
|
||||
import { EventLoggingModule } from './event-logging/event-logging.module';
|
||||
import { GqlModule } from './gql/gql.module';
|
||||
import { SubscriptionModule } from './subscriptions/subscriptions.module';
|
||||
|
||||
|
@ -33,7 +32,6 @@ const version = getVersionInfo(__dirname);
|
|||
isGlobal: true,
|
||||
}),
|
||||
DatabaseModule,
|
||||
EventLoggingModule,
|
||||
SubscriptionModule,
|
||||
GqlModule,
|
||||
GraphQLModule.forRootAsync({
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"subscriptions": {
|
||||
"enabled": true,
|
||||
"sharedSecret": "devsecret",
|
||||
"paymentsServer": {
|
||||
"url": "http://localhost:3031/"
|
||||
},
|
||||
"stripeApiKey": "sk-test_123"
|
||||
},
|
||||
"featureFlags": {
|
||||
"subscriptions": {
|
||||
"playStore": true,
|
||||
"appStore": true,
|
||||
"stripe": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import { Module } from '@nestjs/common';
|
||||
import { EventLoggingService } from './event-logging.service';
|
||||
|
||||
@Module({
|
||||
providers: [EventLoggingService],
|
||||
exports: [EventLoggingService],
|
||||
})
|
||||
export class EventLoggingModule {}
|
|
@ -1,42 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { MockLogService, logger } from '../mocks';
|
||||
import { EventLoggingService, EventNames } from './event-logging.service';
|
||||
|
||||
describe('EventLogging', () => {
|
||||
let eventLogging: EventLoggingService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [EventLoggingService, MockLogService],
|
||||
}).compile();
|
||||
|
||||
eventLogging = module.get<EventLoggingService>(EventLoggingService);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
logger.info.mockClear();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(eventLogging).toBeDefined();
|
||||
});
|
||||
|
||||
it('should record event', () => {
|
||||
eventLogging.onEvent(EventNames.ClearBounces);
|
||||
expect(logger.info).lastCalledWith('admin-panel-events', {
|
||||
event: 'clear-bounces',
|
||||
});
|
||||
});
|
||||
|
||||
it('should record account search event with flag', () => {
|
||||
eventLogging.onAccountSearch('email', true);
|
||||
expect(logger.info).lastCalledWith('admin-panel-events', {
|
||||
event: 'account-search',
|
||||
'search-type': 'email',
|
||||
'auto-completed': true,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,50 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { MozLoggerService } from 'fxa-shared/nestjs/logger/logger.service';
|
||||
|
||||
/** Known event names */
|
||||
export enum EventNames {
|
||||
ClearBounces = 'clear-bounces',
|
||||
UnverifyEmail = 'unverify-email',
|
||||
DisableLogin = 'disable-login',
|
||||
AccountSearch = 'account-search',
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles logging of pertinent events.
|
||||
*/
|
||||
@Injectable()
|
||||
export class EventLoggingService {
|
||||
private readonly logType = 'admin-panel-events';
|
||||
|
||||
/**
|
||||
* Creates new event logger
|
||||
* @param log
|
||||
*/
|
||||
constructor(private readonly log: MozLoggerService) {}
|
||||
|
||||
/**
|
||||
* Logs an event occurrence
|
||||
* @param eventName - A known event name
|
||||
*/
|
||||
public onEvent(eventName: Omit<EventNames, EventNames.AccountSearch>) {
|
||||
this.log.info(this.logType, {
|
||||
event: eventName,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Records an AccountSearch event and indicates if the query was the result of an autocompletion.
|
||||
* @param autocompleted
|
||||
*/
|
||||
public onAccountSearch(searchType: 'email' | 'uid', autoCompleted: boolean) {
|
||||
this.log.info(this.logType, {
|
||||
event: EventNames.AccountSearch,
|
||||
'search-type': searchType,
|
||||
'auto-completed': autoCompleted,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -37,7 +37,6 @@ import {
|
|||
randomTotp,
|
||||
} from 'fxa-shared/test/db/models/auth/helpers';
|
||||
import { Knex } from 'knex';
|
||||
import { EventLoggingService } from '../../event-logging/event-logging.service';
|
||||
import { SubscriptionsService } from '../../subscriptions/subscriptions.service';
|
||||
import { AccountResolver } from './account.resolver';
|
||||
|
||||
|
@ -146,7 +145,6 @@ describe('AccountResolver', () => {
|
|||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
AccountResolver,
|
||||
EventLoggingService,
|
||||
MockMozLogger,
|
||||
MockConfig,
|
||||
MockMetricsFactory,
|
||||
|
@ -170,7 +168,7 @@ describe('AccountResolver', () => {
|
|||
const result = (await resolver.accountByUid(USER_1.uid, 'joe')) as Account;
|
||||
expect(result).toBeDefined();
|
||||
expect(result.email).toBe(USER_1.email);
|
||||
expect(logger.info).toBeCalledTimes(2);
|
||||
expect(logger.info).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('disables an account by uid', async () => {
|
||||
|
@ -182,7 +180,7 @@ describe('AccountResolver', () => {
|
|||
)) as Account;
|
||||
expect(updatedResult).toBeDefined();
|
||||
expect(updatedResult.disabledAt).not.toBeNull();
|
||||
expect(logger.info).toBeCalledTimes(3);
|
||||
expect(logger.info).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('enables an account by uid', async () => {
|
||||
|
@ -194,36 +192,34 @@ describe('AccountResolver', () => {
|
|||
)) as Account;
|
||||
expect(updatedResult).toBeDefined();
|
||||
expect(updatedResult.disabledAt).toBeNull();
|
||||
expect(logger.info).toBeCalledTimes(2);
|
||||
expect(logger.info).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not locate non-existent users by uid', async () => {
|
||||
const result = await resolver.accountByUid(USER_2.uid, 'joe');
|
||||
expect(result).toBeUndefined();
|
||||
expect(logger.info).toBeCalledTimes(2);
|
||||
expect(logger.info).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('locates the user by email', async () => {
|
||||
const result = (await resolver.accountByEmail(
|
||||
USER_1.email,
|
||||
true,
|
||||
'joe'
|
||||
)) as Account;
|
||||
expect(result).toBeDefined();
|
||||
expect(result.email).toBe(USER_1.email);
|
||||
expect(logger.info).toBeCalledTimes(2);
|
||||
expect(logger.info).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not locate non-existent users by email', async () => {
|
||||
const result = await resolver.accountByEmail(USER_2.email, true, 'joe');
|
||||
const result = await resolver.accountByEmail(USER_2.email, 'joe');
|
||||
expect(result).toBeUndefined();
|
||||
expect(logger.info).toBeCalledTimes(2);
|
||||
expect(logger.info).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('loads emailBounces', async () => {
|
||||
const user = (await resolver.accountByEmail(
|
||||
USER_1.email,
|
||||
true,
|
||||
'joe'
|
||||
)) as Account;
|
||||
const { emailType: templateName } = await db.emailTypes
|
||||
|
@ -241,7 +237,6 @@ describe('AccountResolver', () => {
|
|||
it('loads emails', async () => {
|
||||
const user = (await resolver.accountByEmail(
|
||||
USER_1.email,
|
||||
true,
|
||||
'joe'
|
||||
)) as Account;
|
||||
const result = await resolver.emails(user);
|
||||
|
@ -252,7 +247,6 @@ describe('AccountResolver', () => {
|
|||
it('loads totp', async () => {
|
||||
const user = (await resolver.accountByEmail(
|
||||
USER_1.email,
|
||||
true,
|
||||
'joe'
|
||||
)) as Account;
|
||||
const result = await resolver.totp(user);
|
||||
|
@ -264,7 +258,6 @@ describe('AccountResolver', () => {
|
|||
it('loads recoveryKeys', async () => {
|
||||
const user = (await resolver.accountByEmail(
|
||||
USER_1.email,
|
||||
true,
|
||||
'joe'
|
||||
)) as Account;
|
||||
const result = await resolver.recoveryKeys(user);
|
||||
|
@ -276,7 +269,6 @@ describe('AccountResolver', () => {
|
|||
it('loads attached clients', async () => {
|
||||
const user = (await resolver.accountByEmail(
|
||||
USER_1.email,
|
||||
true,
|
||||
'joe'
|
||||
)) as Account;
|
||||
const result = await resolver.attachedClients(user);
|
||||
|
@ -301,7 +293,6 @@ describe('AccountResolver', () => {
|
|||
it('loads linkedAccounts', async () => {
|
||||
const user = (await resolver.accountByEmail(
|
||||
USER_1.email,
|
||||
true,
|
||||
'joe'
|
||||
)) as Account;
|
||||
const result = await resolver.linkedAccounts(user);
|
||||
|
|
|
@ -28,10 +28,6 @@ import { Features } from '../../auth/user-group-header.decorator';
|
|||
import { AppConfig } from '../../config';
|
||||
import { DatabaseService } from '../../database/database.service';
|
||||
import { uuidTransformer } from '../../database/transformers';
|
||||
import {
|
||||
EventLoggingService,
|
||||
EventNames,
|
||||
} from '../../event-logging/event-logging.service';
|
||||
import { Account as AccountType } from '../../gql/model/account.model';
|
||||
import { AttachedClient } from '../../gql/model/attached-clients.model';
|
||||
import { Email as EmailType } from '../../gql/model/emails.model';
|
||||
|
@ -84,8 +80,7 @@ export class AccountResolver {
|
|||
private log: MozLoggerService,
|
||||
private db: DatabaseService,
|
||||
private subscriptionsService: SubscriptionsService,
|
||||
private configService: ConfigService<AppConfig>,
|
||||
private eventLogging: EventLoggingService
|
||||
private configService: ConfigService<AppConfig>
|
||||
) {}
|
||||
|
||||
@Features(AdminPanelFeature.AccountSearch)
|
||||
|
@ -94,7 +89,6 @@ export class AccountResolver {
|
|||
@Args('uid', { nullable: false }) uid: string,
|
||||
@CurrentUser() user: string
|
||||
) {
|
||||
this.eventLogging.onAccountSearch('uid', false);
|
||||
let uidBuffer;
|
||||
try {
|
||||
uidBuffer = uuidTransformer.to(uid);
|
||||
|
@ -112,10 +106,8 @@ export class AccountResolver {
|
|||
@Query((returns) => AccountType, { nullable: true })
|
||||
public accountByEmail(
|
||||
@Args('email', { nullable: false }) email: string,
|
||||
@Args('autoCompleted', { nullable: false }) autoCompleted: boolean,
|
||||
@CurrentUser() user: string
|
||||
) {
|
||||
this.eventLogging.onAccountSearch('email', autoCompleted);
|
||||
this.log.info('accountByEmail', { email, user });
|
||||
return this.db.account
|
||||
.query()
|
||||
|
@ -139,7 +131,6 @@ export class AccountResolver {
|
|||
@Features(AdminPanelFeature.UnverifyEmail)
|
||||
@Mutation((returns) => Boolean)
|
||||
public async unverifyEmail(@Args('email') email: string) {
|
||||
this.eventLogging.onEvent(EventNames.UnverifyEmail);
|
||||
const result = await this.db.emails
|
||||
.query()
|
||||
.where('normalizedEmail', 'like', `${email.toLowerCase()}%`)
|
||||
|
@ -153,7 +144,6 @@ export class AccountResolver {
|
|||
@Features(AdminPanelFeature.DisableAccount)
|
||||
@Mutation((returns) => Boolean)
|
||||
public async disableAccount(@Args('uid') uid: string) {
|
||||
this.eventLogging.onEvent(EventNames.DisableLogin);
|
||||
const uidBuffer = uuidTransformer.to(uid);
|
||||
const result = await this.db.account
|
||||
.query()
|
||||
|
|
|
@ -14,7 +14,6 @@ import {
|
|||
randomEmailBounce,
|
||||
} from 'fxa-shared/test/db/models/auth/helpers';
|
||||
import { Knex } from 'knex';
|
||||
import { EventLoggingService } from '../../event-logging/event-logging.service';
|
||||
|
||||
import { EmailBounceResolver } from './email-bounce.resolver';
|
||||
|
||||
|
@ -63,7 +62,6 @@ describe('EmailBounceResolver', () => {
|
|||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
EmailBounceResolver,
|
||||
EventLoggingService,
|
||||
MockMozLogger,
|
||||
MockConfig,
|
||||
MockMetricsFactory,
|
||||
|
@ -85,6 +83,6 @@ describe('EmailBounceResolver', () => {
|
|||
it('should clear email bounces', async () => {
|
||||
const result = await resolver.clearEmailBounce(USER_1.email, 'test');
|
||||
expect(result).toBeTruthy();
|
||||
expect(logger.info).toBeCalledTimes(2);
|
||||
expect(logger.info).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,19 +11,11 @@ import { GqlAuthHeaderGuard } from '../../auth/auth-header.guard';
|
|||
import { DatabaseService } from '../../database/database.service';
|
||||
import { EmailBounce as EmailBounceType } from '../../gql/model/email-bounces.model';
|
||||
import { AdminPanelFeature } from 'fxa-shared/guards';
|
||||
import {
|
||||
EventLoggingService,
|
||||
EventNames,
|
||||
} from '../../event-logging/event-logging.service';
|
||||
|
||||
@UseGuards(GqlAuthHeaderGuard)
|
||||
@Resolver((of: any) => EmailBounceType)
|
||||
export class EmailBounceResolver {
|
||||
constructor(
|
||||
private log: MozLoggerService,
|
||||
private db: DatabaseService,
|
||||
private eventLogging: EventLoggingService
|
||||
) {}
|
||||
constructor(private log: MozLoggerService, private db: DatabaseService) {}
|
||||
|
||||
@Features(AdminPanelFeature.ClearEmailBounces)
|
||||
@Mutation((returns) => Boolean)
|
||||
|
@ -31,7 +23,6 @@ export class EmailBounceResolver {
|
|||
@Args('email') email: string,
|
||||
@CurrentUser() user: string
|
||||
) {
|
||||
this.eventLogging.onEvent(EventNames.ClearBounces);
|
||||
const result = await this.db.emailBounces
|
||||
.query()
|
||||
.delete()
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DatabaseModule } from '../database/database.module';
|
||||
import { EventLoggingModule } from '../event-logging/event-logging.module';
|
||||
import { SubscriptionModule } from '../subscriptions/subscriptions.module';
|
||||
import { AccountResolver } from './account/account.resolver';
|
||||
import { EmailBounceResolver } from './email-bounce/email-bounce.resolver';
|
||||
import { RelyingPartyResolver } from './relying-party/relying-party.resolver';
|
||||
|
||||
@Module({
|
||||
imports: [DatabaseModule, SubscriptionModule, EventLoggingModule],
|
||||
imports: [DatabaseModule, SubscriptionModule],
|
||||
providers: [AccountResolver, EmailBounceResolver, RelyingPartyResolver],
|
||||
})
|
||||
export class GqlModule {}
|
||||
|
|
|
@ -159,7 +159,7 @@ export interface RelyingParty {
|
|||
|
||||
export interface IQuery {
|
||||
accountByUid(uid: string): Nullable<Account> | Promise<Nullable<Account>>;
|
||||
accountByEmail(autoCompleted: boolean, email: string): Nullable<Account> | Promise<Nullable<Account>>;
|
||||
accountByEmail(email: string): Nullable<Account> | Promise<Nullable<Account>>;
|
||||
getEmailsLike(search: string): Nullable<Email[]> | Promise<Nullable<Email[]>>;
|
||||
relyingParties(): RelyingParty[] | Promise<RelyingParty[]>;
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ type RelyingParty {
|
|||
|
||||
type Query {
|
||||
accountByUid(uid: String!): Account
|
||||
accountByEmail(autoCompleted: Boolean!, email: String!): Account
|
||||
accountByEmail(email: String!): Account
|
||||
getEmailsLike(search: String!): [Email!]
|
||||
relyingParties: [RelyingParty!]!
|
||||
}
|
||||
|
|
|
@ -36,8 +36,7 @@ describe('AppController (e2e)', () => {
|
|||
.send({
|
||||
operationName: null,
|
||||
variables: {},
|
||||
query:
|
||||
'{accountByEmail(email:"test@test.com", autoCompleted:true){uid}}',
|
||||
query: '{accountByEmail(email:"test@test.com"){uid}}',
|
||||
})
|
||||
.expect(200);
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче