Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
silentsakky committed Oct 16, 2018
2 parents c25df11 + 63c24b5 commit f6b0002
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 31 deletions.
32 changes: 31 additions & 1 deletion src/apollo/zimbra-in-memory-cache.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
ApolloReducerConfig,
defaultDataIdFromObject,
InMemoryCache
InMemoryCache,
IntrospectionFragmentMatcher
} from 'apollo-cache-inmemory';
import get from 'lodash/get';

Expand Down Expand Up @@ -32,13 +33,42 @@ const dataIdFromObject = (object: any): string | null | undefined => {
}
};

function createFragmentMatcher(fragmentMatcherFactory = Object) {
return new IntrospectionFragmentMatcher(
fragmentMatcherFactory({
introspectionQueryResultData: {
__schema: {
types: [
{
kind: 'INTERFACE',
name: 'MailItem',
possibleTypes: [
{ name: 'Conversation' },
{ name: 'MessageInfo' },
{ name: 'MsgWithGroupInfo' }
]
}
]
}
}
})
);
}

/**
* Provide a light wrapper over Apollo's inmemory cache with
* special optimizations for identifying Zimbra object types via
* `dataIdFromObject`.
*/
export class ZimbraInMemoryCache extends InMemoryCache {
constructor(config: ApolloReducerConfig = {}) {
if (
!config.fragmentMatcher ||
typeof config.fragmentMatcher === 'function'
) {
config.fragmentMatcher = createFragmentMatcher(config.fragmentMatcher);
}

super({
dataIdFromObject,
...config
Expand Down
64 changes: 41 additions & 23 deletions src/batch-client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ import {
} from '../utils/coerce-boolean';
import { mapValuesDeep } from '../utils/map-values-deep';
import { normalizeEmailAddresses } from '../utils/normalize-email-addresses';
import { normalizeMimeParts } from '../utils/normalize-mime-parts';
import {
getAttachmentUrl,
normalizeMimeParts
} from '../utils/normalize-mime-parts';
import {
ActionOptions,
ActionType,
Expand Down Expand Up @@ -97,15 +100,15 @@ const DEBUG = false;

function normalizeMessage(
message: { [key: string]: any },
zimbraOrigin?: string
{ origin, jwtToken }: { jwtToken?: string; origin?: string }
) {
const normalizedMessage = normalize(MessageInfo)(message);
normalizedMessage.attributes =
normalizedMessage.attributes &&
mapValuesDeep(normalizedMessage.attributes, coerceStringToBoolean);

return normalizeEmailAddresses(
normalizeMimeParts(normalizedMessage, zimbraOrigin)
normalizeMimeParts(normalizedMessage, { origin, jwtToken })
);
}

Expand All @@ -115,9 +118,11 @@ export class ZimbraBatchClient {
public soapPathname: string;
private batchDataLoader: DataLoader<RequestOptions, RequestBody>;
private dataLoader: DataLoader<RequestOptions, RequestBody>;
private jwtToken?: string;
private notificationHandler?: NotificationHandler;

constructor(options: ZimbraClientOptions = {}) {
this.jwtToken = options.jwtToken;
this.origin = options.zimbraOrigin || DEFAULT_HOSTNAME;
this.soapPathname = options.soapPathname || DEFAULT_SOAP_PATHNAME;
this.notificationHandler = options.notificationHandler;
Expand Down Expand Up @@ -369,6 +374,12 @@ export class ZimbraBatchClient {
}
}).then(res => normalize(FreeBusy)(res.usr));

public getAttachmentUrl = (attachment: any) =>
getAttachmentUrl(attachment, {
origin: this.origin,
jwtToken: this.jwtToken
});

public getContact = ({ id }: GetContactOptions) =>
this.jsonRequest({
name: 'GetContacts',
Expand All @@ -391,7 +402,7 @@ export class ZimbraBatchClient {
}
}).then(res => {
const c = normalize(Conversation)(res.c[0]);
c.messages = c.messages.map((m: any) => normalizeMessage(m, this.origin));
c.messages = c.messages.map(this.normalizeMessage);
return c;
});

Expand Down Expand Up @@ -452,9 +463,7 @@ export class ZimbraBatchClient {
...(ridZ && { ridZ: ridZ })
}
}
}).then(
res => (res && res.m ? normalizeMessage(res.m[0], this.origin) : null)
);
}).then(res => (res && res.m ? this.normalizeMessage(res.m[0]) : null));

public getSearchFolder = () =>
this.jsonRequest({
Expand Down Expand Up @@ -499,14 +508,9 @@ export class ZimbraBatchClient {
public itemAction = (options: ActionOptions) =>
this.action(ActionType.item, options);

public jsonRequest = (options: JsonRequestOptions) => {
const { accountName } = options;

public jsonRequest = (options: JsonRequestOptions) =>
// If account name is present that means we will not be able to batch requests
return accountName
? this.dataLoader.load(options)
: this.batchDataLoader.load(options);
};
this[options.accountName ? 'dataLoader' : 'batchDataLoader'].load(options);

public login = ({
username,
Expand Down Expand Up @@ -691,8 +695,7 @@ export class ZimbraBatchClient {
name: 'SaveDraft',
body: denormalize(SendMessageInfo)(options)
}).then(({ m: messages }) => ({
message:
messages && messages.map((m: any) => normalizeMessage(m, this.origin))
message: messages && messages.map(this.normalizeMessage)
}));

public search = (options: SearchOptions) =>
Expand All @@ -705,9 +708,7 @@ export class ZimbraBatchClient {
}).then(res => {
const normalized = normalize(SearchResponse)(res);
if (normalized.messages) {
normalized.messages = normalized.messages.map((m: any) =>
normalizeMessage(m, this.origin)
);
normalized.messages = normalized.messages.map(this.normalizeMessage);
}
return normalized;
});
Expand All @@ -734,6 +735,10 @@ export class ZimbraBatchClient {
}
});

public setJwtToken = (jwtToken: string) => {
this.jwtToken = jwtToken;
};

public setRecoveryAccount = (options: SetRecoveryAccountOptions) =>
this.jsonRequest({
name: 'SetRecoveryAccount',
Expand Down Expand Up @@ -827,8 +832,7 @@ export class ZimbraBatchClient {
private batchDataHandler = (requests: Array<RequestOptions>) =>
batchJsonRequest({
requests,
sessionId: this.sessionId,
origin: this.origin
...this.getAdditionalRequestOptions()
}).then(response => {
const sessionId = get(response, 'header.context.session.id');
const notifications = get(response, 'header.context.notify.0');
Expand Down Expand Up @@ -856,8 +860,7 @@ export class ZimbraBatchClient {
private dataHandler = (requests: Array<JsonRequestOptions>) =>
jsonRequest({
...requests[0],
sessionId: this.sessionId,
origin: this.origin
...this.getAdditionalRequestOptions()
}).then(response => {
const sessionId = get(response, 'header.context.session.id');
const notifications = get(response, 'header.context.notify.0');
Expand All @@ -872,4 +875,19 @@ export class ZimbraBatchClient {

return isError(response) ? [response] : [response.body];
});

/**
* These options are included on every request.
*/
private getAdditionalRequestOptions = () => ({
jwtToken: this.jwtToken,
sessionId: this.sessionId,
origin: this.origin
});

private normalizeMessage = (message: any) =>
normalizeMessage(message, {
origin: this.origin,
jwtToken: this.jwtToken
});
}
1 change: 1 addition & 0 deletions src/batch-client/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export interface Notification {
export type NotificationHandler = (notificaton: Notification) => void;

export interface ZimbraClientOptions {
jwtToken?: string;
notificationHandler?: NotificationHandler;
soapPathname?: string;
zimbraOrigin?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/normalize/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,14 +171,14 @@ const commonMailItemFields = {
mp: ['mimeParts', MimePart],
shr: 'share',
su: 'subject',
origid: 'origId',
attach: ['attachments', AttachmentsInfo],
rt: 'replyType'
};

const SendMessageFields = new Entity({
...commonMailItemFields,
id: 'id',
origid: 'origId',
aid: 'attachmentId',
irt: 'inReplyTo',
rt: 'replyType',
Expand Down
6 changes: 6 additions & 0 deletions src/request/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ export function jsonRequest(
};
}

if (requestOptions.jwtToken) {
header.context.jwtToken = {
_content: requestOptions.jwtToken
};
}

const body = {
[soapRequestName]: soapCommandBody(options)
};
Expand Down
4 changes: 4 additions & 0 deletions src/request/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface BaseRequestOptions {
accountName?: string | null;
credentials?: RequestCredentials;
headers?: any;
jwtToken?: string | null;
origin?: string;
sessionId?: SessionId;
sessionSeq?: SessionSeq;
Expand Down Expand Up @@ -82,6 +83,9 @@ export interface SOAPHeader {
by: 'name' | 'id'; // name is the account's email address
};
csrfToken?: string;
jwtToken?: {
_content: string;
};
notify?: {
seq: SessionSeq;
};
Expand Down
1 change: 1 addition & 0 deletions src/schema/generated-schema-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ export interface MessageInfo extends MailItem {
size?: number | null;
date?: number | null;
folderId?: string | null;
origId?: string | null;
subject?: string | null;
emailAddresses?: EmailAddress[] | null;
excerpt?: string | null;
Expand Down
1 change: 1 addition & 0 deletions src/schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ type MessageInfo implements MailItem {
size: Float # s
date: Float # d
folderId: ID # l
origId: ID #origid
subject: String # su
emailAddresses: [EmailAddress]
excerpt: String # fr
Expand Down
17 changes: 11 additions & 6 deletions src/utils/normalize-mime-parts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,25 @@ function reduceMimeParts(
return accumulator;
}

function getUrl(attachment: { [key: string]: any }, origin: string = '') {
export function getAttachmentUrl(
attachment: { [key: string]: any },
{ origin = '', jwtToken }: { jwtToken?: string; origin?: string }
) {
let { messageId, mid, part } = attachment;
return `${origin}/service/home/~/?auth=co&id=${encodeURIComponent(
messageId || mid
)}&part=${encodeURIComponent(part)}`;
return `${origin}/service/home/~/?auth=${
jwtToken ? 'jwt' : 'co'
}&id=${encodeURIComponent(messageId || mid)}&part=${encodeURIComponent(
part
)}${jwtToken ? `&zjwt=${jwtToken}` : ''}`;
}

export function normalizeMimeParts(
message: { [key: string]: any },
origin?: string
{ origin, jwtToken }: { jwtToken?: string; origin?: string }
) {
const processAttachment = ({ ...attachment }) => {
attachment.messageId = attachment.messageId || message.id;
attachment.url = getUrl(attachment, origin);
attachment.url = getAttachmentUrl(attachment, { origin, jwtToken });
if (attachment.contentId) {
attachment.contentId = normalizeCid(attachment.contentId);
}
Expand Down

0 comments on commit f6b0002

Please sign in to comment.