Skip to content

Commit

Permalink
API functions for adding an add-on to a collection (#4119)
Browse files Browse the repository at this point in the history
  • Loading branch information
kumar303 committed Jan 11, 2018
1 parent a14d42c commit 172da90
Show file tree
Hide file tree
Showing 9 changed files with 362 additions and 20 deletions.
106 changes: 95 additions & 11 deletions src/amo/api/collections.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/* @flow */
import { callApi } from 'core/api';
import { callApi, allPages } from 'core/api';
import type {
ExternalCollectionAddon,
ExternalCollectionDetail,
} from 'amo/reducers/collections';
import type { ApiStateType } from 'core/reducers/api';
import type { PaginatedApiResponse } from 'core/types/api';


type GetCollectionParams = {|
Expand All @@ -11,7 +16,7 @@ type GetCollectionParams = {|

export const getCollectionDetail = (
{ api, slug, user }: GetCollectionParams
) => {
): Promise<ExternalCollectionDetail> => {
if (!slug) {
throw new Error('slug is required');
}
Expand All @@ -28,42 +33,121 @@ export const getCollectionDetail = (

type GetCollectionAddonsParams = {|
...GetCollectionParams,
nextURL?: string,
page?: number,
|};

export const getCollectionAddons = (
{ api, page, slug, user }: GetCollectionAddonsParams
) => {
{ api, nextURL, page, slug, user }: GetCollectionAddonsParams
): Promise<PaginatedApiResponse<ExternalCollectionAddon>> => {
if (!slug) {
throw new Error('slug is required');
}
if (!user) {
throw new Error('user is required');
}

return callApi({
const request = {
auth: true,
endpoint: `accounts/account/${user}/collections/${slug}/addons`,
params: { page },
endpoint:
nextURL || `accounts/account/${user}/collections/${slug}/addons`,
params: undefined,
state: api,
});
};
// If a page is requested explicitly, pass it to callApi().
// By default, this code does not define request.params because doing so
// would overwrite any query string params in nextURL.
if (page) {
request.params = { page };
}

return callApi(request);
};

type GetAllCollectionAddonsParams = {|
...GetCollectionParams,
_allPages?: typeof allPages,
_getCollectionAddons?: typeof getCollectionAddons,
|};

export const getAllCollectionAddons = async (
{
api,
slug,
user,
_allPages = allPages,
_getCollectionAddons = getCollectionAddons,
}: GetAllCollectionAddonsParams
): Promise<Array<ExternalCollectionAddon>> => {
const { results } = await _allPages(
(nextURL) => _getCollectionAddons({ api, nextURL, slug, user })
);
return results;
};

type ListCollectionsParams = {|
api: ApiStateType,
nextURL?: string,
user: string | number,
|};

export const listCollections = (
{ api, user }: ListCollectionsParams
) => {
{ api, nextURL, user }: ListCollectionsParams
): Promise<PaginatedApiResponse<ExternalCollectionDetail>> => {
if (!user) {
throw new Error('The user parameter is required');
}
const endpoint = nextURL || `accounts/account/${user}/collections`;

return callApi({ auth: true, endpoint, state: api });
};

type GetAllUserCollectionsParams = {|
...ListCollectionsParams,
_allPages?: typeof allPages,
_listCollections?: typeof listCollections,
|};

export const getAllUserCollections = async (
{
api,
user,
_allPages = allPages,
_listCollections = listCollections,
}: GetAllUserCollectionsParams
): Promise<Array<ExternalCollectionDetail>> => {
const { results } = await _allPages(
(nextURL) => _listCollections({ api, nextURL, user })
);
return results;
};

type AddAddonToCollectionParams = {|
addon: string | number,
api: ApiStateType,
collection: string | number,
notes?: string,
user: string | number,
|};

export const addAddonToCollection = (
{ addon, api, collection, notes, user }: AddAddonToCollectionParams
): Promise<void> => {
if (!addon) {
throw new Error('The addon parameter is required');
}
if (!collection) {
throw new Error('The collection parameter is required');
}
if (!user) {
throw new Error('The user parameter is required');
}

return callApi({
auth: true,
endpoint: `accounts/account/${user}/collections`,
body: { addon, notes },
endpoint: `accounts/account/${user}/collections/${collection}/addons`,
method: 'POST',
state: api,
});
};
8 changes: 5 additions & 3 deletions src/amo/reducers/collections.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,15 @@ export const fetchCurrentCollectionPage = ({
};
};

type ExternalCollectionAddons = Array<{|
export type ExternalCollectionAddon = {|
addon: ExternalAddonType,
downloads: number,
notes: string | null,
|}>;
|};

type ExternalCollectionAddons = Array<ExternalCollectionAddon>;

type ExternalCollectionDetail = {|
export type ExternalCollectionDetail = {|
addon_count: number,
author: {|
id: number,
Expand Down
40 changes: 40 additions & 0 deletions src/core/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from 'core/searchUtils';
import type { ErrorHandlerType } from 'core/errorHandler';
import type { ApiStateType } from 'core/reducers/api';
import type { PaginatedApiResponse } from 'core/types/api';
import type { ReactRouterLocation } from 'core/types/router';


Expand Down Expand Up @@ -265,3 +266,42 @@ export function autocomplete({ api, filters }: AutocompleteParams) {
state: api,
});
}

type GetNextResponseType =
(nextURL?: string) => Promise<PaginatedApiResponse<any>>;

type AllPagesOptions = {| pageLimit: number |};

export const allPages = async (
getNextResponse: GetNextResponseType,
{ pageLimit = 100 }: AllPagesOptions = {},
): Promise<PaginatedApiResponse<any>> => {
let results = [];
let nextURL;
let count = 0;
let pageSize = 0;

for (let page = 1; page <= pageLimit; page++) {
// eslint-disable-next-line no-await-in-loop
const response = await getNextResponse(nextURL);
if (!count) {
// Every response page returns a count for all results.
count = response.count;
}
if (!pageSize) {
pageSize = response.page_size;
}
results = results.concat(response.results);

if (response.next) {
nextURL = response.next;
log.debug(oneLine`Fetching next page "${nextURL}" of
${getNextResponse}`);
} else {
return { count, page_size: pageSize, results };
}
}

// If we get this far the callback may not be advancing pages correctly.
throw new Error(`Fetched too many pages (the limit is ${pageLimit})`);
};
3 changes: 1 addition & 2 deletions src/core/client/base.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* global document */

import 'babel-polyfill';
import 'raf/polyfill';
import 'core/polyfill';
import { oneLine } from 'common-tags';
import config from 'config';
import FastClick from 'fastclick';
Expand Down
2 changes: 2 additions & 0 deletions src/core/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import 'babel-polyfill';
import 'raf/polyfill';
3 changes: 1 addition & 2 deletions src/core/server/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import fs from 'fs';
import path from 'path';
import https from 'https';

import 'babel-polyfill';
import 'raf/polyfill';
import 'core/polyfill';
import { oneLine } from 'common-tags';
import defaultConfig from 'config';
import Express from 'express';
Expand Down
Loading

0 comments on commit 172da90

Please sign in to comment.