add purchase_list

This commit is contained in:
Sean Yesmunt 2020-05-08 16:47:33 -04:00
parent 259317250a
commit 278e12dcbe
13 changed files with 421 additions and 34 deletions

171
dist/bundle.es.js vendored
View file

@ -149,6 +149,9 @@ const ADD_FILES_REFLECTING = 'ADD_FILES_REFLECTING';
const UPDATE_FILES_REFLECTING = 'UPDATE_FILES_REFLECTING'; const UPDATE_FILES_REFLECTING = 'UPDATE_FILES_REFLECTING';
const TOGGLE_CHECKING_REFLECTING = 'TOGGLE_CHECKING_REFLECTING'; const TOGGLE_CHECKING_REFLECTING = 'TOGGLE_CHECKING_REFLECTING';
const TOGGLE_CHECKING_PENDING = 'TOGGLE_CHECKING_PENDING'; const TOGGLE_CHECKING_PENDING = 'TOGGLE_CHECKING_PENDING';
const PURCHASE_LIST_STARTED = 'PURCHASE_LIST_STARTED';
const PURCHASE_LIST_COMPLETED = 'PURCHASE_LIST_COMPLETED';
const PURCHASE_LIST_FAILED = 'PURCHASE_LIST_FAILED';
// Comments // Comments
const COMMENT_LIST_STARTED = 'COMMENT_LIST_STARTED'; const COMMENT_LIST_STARTED = 'COMMENT_LIST_STARTED';
@ -429,6 +432,9 @@ var action_types = /*#__PURE__*/Object.freeze({
UPDATE_FILES_REFLECTING: UPDATE_FILES_REFLECTING, UPDATE_FILES_REFLECTING: UPDATE_FILES_REFLECTING,
TOGGLE_CHECKING_REFLECTING: TOGGLE_CHECKING_REFLECTING, TOGGLE_CHECKING_REFLECTING: TOGGLE_CHECKING_REFLECTING,
TOGGLE_CHECKING_PENDING: TOGGLE_CHECKING_PENDING, TOGGLE_CHECKING_PENDING: TOGGLE_CHECKING_PENDING,
PURCHASE_LIST_STARTED: PURCHASE_LIST_STARTED,
PURCHASE_LIST_COMPLETED: PURCHASE_LIST_COMPLETED,
PURCHASE_LIST_FAILED: PURCHASE_LIST_FAILED,
COMMENT_LIST_STARTED: COMMENT_LIST_STARTED, COMMENT_LIST_STARTED: COMMENT_LIST_STARTED,
COMMENT_LIST_COMPLETED: COMMENT_LIST_COMPLETED, COMMENT_LIST_COMPLETED: COMMENT_LIST_COMPLETED,
COMMENT_LIST_FAILED: COMMENT_LIST_FAILED, COMMENT_LIST_FAILED: COMMENT_LIST_FAILED,
@ -1090,6 +1096,7 @@ const Lbry = {
transaction_list: (params = {}) => daemonCallWithResult('transaction_list', params), transaction_list: (params = {}) => daemonCallWithResult('transaction_list', params),
utxo_release: (params = {}) => daemonCallWithResult('utxo_release', params), utxo_release: (params = {}) => daemonCallWithResult('utxo_release', params),
support_abandon: (params = {}) => daemonCallWithResult('support_abandon', params), support_abandon: (params = {}) => daemonCallWithResult('support_abandon', params),
purchase_list: (params = {}) => daemonCallWithResult('purchase_list', params),
sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params), sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params),
sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params), sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params),
@ -2136,7 +2143,21 @@ function createNormalizedClaimSearchKey(options) {
return query; return query;
} }
function filterClaims(claims, query) {
if (query) {
const queryMatchRegExp = new RegExp(query, 'i');
return claims.filter(claim => {
const { value } = claim;
return value.title && value.title.match(queryMatchRegExp) || claim.signing_channel && claim.signing_channel.name.match(queryMatchRegExp) || claim.name && claim.name.match(queryMatchRegExp);
});
}
return claims;
}
var _extends$4 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _extends$4 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const selectState$2 = state => state.claims || {}; const selectState$2 = state => state.claims || {};
const selectClaimsById = reselect.createSelector(selectState$2, state => state.byId || {}); const selectClaimsById = reselect.createSelector(selectState$2, state => state.byId || {});
@ -2277,6 +2298,30 @@ const makeSelectClaimIsMine = rawUri => {
}); });
}; };
const selectMyPurchases = reselect.createSelector(selectState$2, state => state.myPurchases);
const selectMyPurchasesCount = reselect.createSelector(selectState$2, state => state.myPurchasesPageTotalResults);
const selectIsFetchingMyPurchases = reselect.createSelector(selectState$2, state => state.fetchingMyPurchases);
const selectFetchingMyPurchasesError = reselect.createSelector(selectState$2, state => state.fetchingMyPurchasesError);
const makeSelectMyPurchasesForPage = (query, page = 1) => reselect.createSelector(selectMyPurchases, selectClaimsByUri, (myPurchases, claimsByUri) => {
if (!myPurchases) {
return undefined;
}
const fileInfos = myPurchases.map(uri => claimsByUri[uri]);
const matchingFileInfos = filterClaims(fileInfos, query);
const start = (Number(page) - 1) * Number(PAGE_SIZE);
const end = Number(page) * Number(PAGE_SIZE);
return matchingFileInfos && matchingFileInfos.length ? matchingFileInfos.slice(start, end).map(fileInfo => fileInfo.canonical_url || fileInfo.permanent_url) : [];
});
const makeSelectClaimWasPurchased = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => {
return claim && claim.purchase_receipt !== undefined;
});
const selectAllFetchingChannelClaims = reselect.createSelector(selectState$2, state => state.fetchingChannelClaims || {}); const selectAllFetchingChannelClaims = reselect.createSelector(selectState$2, state => state.fetchingChannelClaims || {});
const makeSelectFetchingChannelClaims = uri => reselect.createSelector(selectAllFetchingChannelClaims, fetching => fetching && fetching[uri]); const makeSelectFetchingChannelClaims = uri => reselect.createSelector(selectAllFetchingChannelClaims, fetching => fetching && fetching[uri]);
@ -2540,7 +2585,7 @@ const makeSelectCanonicalUrlForUri = uri => reselect.createSelector(makeSelectCl
const makeSelectPermanentUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.permanent_url); const makeSelectPermanentUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.permanent_url);
const makeSelectSupportsForUri = uri => reselect.createSelector(selectSupportsByOutpoint, makeSelectClaimForUri(uri), (byOutpoint, claim) => { const makeSelectSupportsForUri = uri => reselect.createSelector(selectSupportsByOutpoint, makeSelectClaimForUri(uri), (byOutpoint, claim) => {
if (!claim || !claim.is_mine) { if (!claim || !claim.is_my_output) {
return null; return null;
} }
@ -3180,7 +3225,9 @@ function doResolveUris(uris, returnCachedClaims = false) {
return; return;
} }
const options = {}; const options = {
include_purchase_receipt: true
};
if (urisToResolve.length === 1) { if (urisToResolve.length === 1) {
options.include_is_my_output = true; options.include_is_my_output = true;
@ -3427,7 +3474,8 @@ function doFetchClaimsByChannel(uri, page = 1) {
valid_channel_signature: true, valid_channel_signature: true,
page: page || 1, page: page || 1,
order_by: ['release_time'], order_by: ['release_time'],
include_is_my_output: true include_is_my_output: true,
include_purchase_receipt: true
}).then(result => { }).then(result => {
const { items: claims, total_items: claimsInChannel, page: returnedPage } = result; const { items: claims, total_items: claimsInChannel, page: returnedPage } = result;
@ -3630,7 +3678,9 @@ function doClaimSearch(options = {
}); });
}; };
lbryProxy.claim_search(options).then(success, failure); lbryProxy.claim_search(_extends$5({}, options, {
include_purchase_receipt: true
})).then(success, failure);
}; };
} }
@ -3700,6 +3750,38 @@ function doClearRepostError() {
}; };
} }
function doPurchaseList(page = 1, pageSize = 99999) {
return dispatch => {
dispatch({
type: PURCHASE_LIST_STARTED
});
const success = result => {
return dispatch({
type: PURCHASE_LIST_COMPLETED,
data: {
result
}
});
};
const failure = error => {
dispatch({
type: PURCHASE_LIST_FAILED,
data: {
error: error.message
}
});
};
lbryProxy.purchase_list({
page: page,
page_size: pageSize,
resolve: true
}).then(success, failure);
};
}
const selectState$3 = state => state.fileInfo || {}; const selectState$3 = state => state.fileInfo || {};
const selectFileInfosByOutpoint = reselect.createSelector(selectState$3, state => state.byOutpoint || {}); const selectFileInfosByOutpoint = reselect.createSelector(selectState$3, state => state.byOutpoint || {});
@ -3820,6 +3902,7 @@ function filterFileInfos(fileInfos, query) {
const queryMatchRegExp = new RegExp(query, 'i'); const queryMatchRegExp = new RegExp(query, 'i');
return fileInfos.filter(fileInfo => { return fileInfos.filter(fileInfo => {
const { metadata } = fileInfo; const { metadata } = fileInfo;
return metadata.title && metadata.title.match(queryMatchRegExp) || fileInfo.channel_name && fileInfo.channel_name.match(queryMatchRegExp) || fileInfo.claim_name && fileInfo.claim_name.match(queryMatchRegExp); return metadata.title && metadata.title.match(queryMatchRegExp) || fileInfo.channel_name && fileInfo.channel_name.match(queryMatchRegExp) || fileInfo.claim_name && fileInfo.claim_name.match(queryMatchRegExp);
}); });
} }
@ -5021,6 +5104,8 @@ const doToggleBlockChannel = uri => ({
var _extends$9 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _extends$9 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _objectWithoutProperties$3(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
const reducers = {}; const reducers = {};
const defaultState = { const defaultState = {
byId: {}, byId: {},
@ -5029,10 +5114,13 @@ const defaultState = {
channelClaimCounts: {}, channelClaimCounts: {},
fetchingChannelClaims: {}, fetchingChannelClaims: {},
resolvingUris: [], resolvingUris: [],
// This should not be a Set
// Storing sets in reducers can cause issues
myChannelClaims: undefined, myChannelClaims: undefined,
myClaims: undefined, myClaims: undefined,
myPurchases: undefined,
myPurchasesPageNumber: undefined,
myPurchasesPageTotalResults: undefined,
fetchingMyPurchases: false,
fetchingMyPurchasesError: undefined,
fetchingMyChannels: false, fetchingMyChannels: false,
abandoningById: {}, abandoningById: {},
pendingById: {}, pendingById: {},
@ -5053,6 +5141,7 @@ const defaultState = {
myClaimsPageNumber: undefined, myClaimsPageNumber: undefined,
myClaimsPageTotalResults: undefined, myClaimsPageTotalResults: undefined,
isFetchingClaimListMine: false, isFetchingClaimListMine: false,
isFetchingMyPurchases: false,
isCheckingNameForPublish: false, isCheckingNameForPublish: false,
checkingPending: false, checkingPending: false,
checkingReflecting: false checkingReflecting: false
@ -5150,13 +5239,13 @@ reducers[FETCH_CLAIM_LIST_MINE_COMPLETED] = (state, action) => {
const byUri = Object.assign({}, state.claimsByUri); const byUri = Object.assign({}, state.claimsByUri);
const pendingById = Object.assign({}, state.pendingById); const pendingById = Object.assign({}, state.pendingById);
let myClaimIds = new Set(state.myClaims); let myClaimIds = new Set(state.myClaims);
let urlPage = []; let urlsForCurrentPage = [];
claims.forEach(claim => { claims.forEach(claim => {
const uri = buildURI({ streamName: claim.name, streamClaimId: claim.claim_id }); const uri = buildURI({ streamName: claim.name, streamClaimId: claim.claim_id });
const { claim_id: claimId } = claim; const { claim_id: claimId } = claim;
if (claim.type && claim.type.match(/claim|update/)) { if (claim.type && claim.type.match(/claim|update/)) {
urlPage.push(uri); urlsForCurrentPage.push(uri);
if (claim.confirmations < 1) { if (claim.confirmations < 1) {
pendingById[claimId] = claim; pendingById[claimId] = claim;
delete byId[claimId]; delete byId[claimId];
@ -5188,7 +5277,7 @@ reducers[FETCH_CLAIM_LIST_MINE_COMPLETED] = (state, action) => {
byId, byId,
claimsByUri: byUri, claimsByUri: byUri,
pendingById, pendingById,
myClaimsPageResults: urlPage, myClaimsPageResults: urlsForCurrentPage,
myClaimsPageNumber: page, myClaimsPageNumber: page,
myClaimsPageTotalResults: totalItems myClaimsPageTotalResults: totalItems
}); });
@ -5325,6 +5414,7 @@ reducers[UPDATE_PENDING_CLAIMS] = (state, action) => {
const pendingById = Object.assign({}, state.pendingById); const pendingById = Object.assign({}, state.pendingById);
let myClaimIds = new Set(state.myClaims); let myClaimIds = new Set(state.myClaims);
// $FlowFixMe
claims.forEach(claim => { claims.forEach(claim => {
const uri = buildURI({ streamName: claim.name, streamClaimId: claim.claim_id }); const uri = buildURI({ streamName: claim.name, streamClaimId: claim.claim_id });
const { claim_id: claimId } = claim; const { claim_id: claimId } = claim;
@ -5570,6 +5660,58 @@ reducers[TOGGLE_CHECKING_PENDING] = (state, action) => {
})); }));
}; };
reducers[PURCHASE_LIST_STARTED] = state => {
return _extends$9({}, state, {
fetchingMyPurchases: true,
fetchingMyPurchasesError: null
});
};
reducers[PURCHASE_LIST_COMPLETED] = (state, action) => {
const { result } = action.data;
const page = result.page;
const totalItems = result.total_items;
let byId = Object.assign({}, state.byId);
let byUri = Object.assign({}, state.claimsByUri);
let urlsForCurrentPage = [];
result.items.forEach(item => {
if (!item.claim) {
// Abandoned claim
return;
}
const { claim } = item,
purchaseInfo = _objectWithoutProperties$3(item, ['claim']);
claim.purchase_receipt = purchaseInfo;
const claimId = claim.claim_id;
const uri = claim.canonical_url;
byId[claimId] = claim;
byUri[uri] = claimId;
urlsForCurrentPage.push(uri);
});
return Object.assign({}, state, {
byId,
claimsByUri: byUri,
myPurchases: urlsForCurrentPage,
myPurchasesPageNumber: page,
myPurchasesPageTotalResults: totalItems,
fetchingMyPurchases: false
});
};
reducers[PURCHASE_LIST_FAILED] = (state, action) => {
const { error } = action.data;
return _extends$9({}, state, {
fetchingMyPurchases: false,
fetchingMyPurchasesError: error
});
};
function claimsReducer(state = defaultState, action) { function claimsReducer(state = defaultState, action) {
const handler = reducers[action.type]; const handler = reducers[action.type];
if (handler) return handler(state, action); if (handler) return handler(state, action);
@ -6061,7 +6203,7 @@ const notificationsReducer = handleActions({
var _extends$e = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _extends$e = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _objectWithoutProperties$3(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } function _objectWithoutProperties$4(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
const defaultState$6 = { const defaultState$6 = {
editingURI: undefined, editingURI: undefined,
@ -6118,7 +6260,7 @@ const publishReducer = handleActions({
publishSuccess: true publishSuccess: true
}), }),
[DO_PREPARE_EDIT]: (state, action) => { [DO_PREPARE_EDIT]: (state, action) => {
const publishData = _objectWithoutProperties$3(action.data, []); const publishData = _objectWithoutProperties$4(action.data, []);
const { channel, name, uri } = publishData; const { channel, name, uri } = publishData;
// The short uri is what is presented to the user // The short uri is what is presented to the user
@ -6879,6 +7021,7 @@ exports.doPreferenceGet = doPreferenceGet;
exports.doPreferenceSet = doPreferenceSet; exports.doPreferenceSet = doPreferenceSet;
exports.doPrepareEdit = doPrepareEdit; exports.doPrepareEdit = doPrepareEdit;
exports.doPublish = doPublish; exports.doPublish = doPublish;
exports.doPurchaseList = doPurchaseList;
exports.doPurchaseUri = doPurchaseUri; exports.doPurchaseUri = doPurchaseUri;
exports.doRepost = doRepost; exports.doRepost = doRepost;
exports.doResetThumbnailStatus = doResetThumbnailStatus; exports.doResetThumbnailStatus = doResetThumbnailStatus;
@ -6924,6 +7067,7 @@ exports.makeSelectClaimForUri = makeSelectClaimForUri;
exports.makeSelectClaimIsMine = makeSelectClaimIsMine; exports.makeSelectClaimIsMine = makeSelectClaimIsMine;
exports.makeSelectClaimIsNsfw = makeSelectClaimIsNsfw; exports.makeSelectClaimIsNsfw = makeSelectClaimIsNsfw;
exports.makeSelectClaimIsPending = makeSelectClaimIsPending; exports.makeSelectClaimIsPending = makeSelectClaimIsPending;
exports.makeSelectClaimWasPurchased = makeSelectClaimWasPurchased;
exports.makeSelectClaimsInChannelForCurrentPageState = makeSelectClaimsInChannelForCurrentPageState; exports.makeSelectClaimsInChannelForCurrentPageState = makeSelectClaimsInChannelForCurrentPageState;
exports.makeSelectClaimsInChannelForPage = makeSelectClaimsInChannelForPage; exports.makeSelectClaimsInChannelForPage = makeSelectClaimsInChannelForPage;
exports.makeSelectCommentsForUri = makeSelectCommentsForUri; exports.makeSelectCommentsForUri = makeSelectCommentsForUri;
@ -6946,6 +7090,7 @@ exports.makeSelectLoadingForUri = makeSelectLoadingForUri;
exports.makeSelectMediaTypeForUri = makeSelectMediaTypeForUri; exports.makeSelectMediaTypeForUri = makeSelectMediaTypeForUri;
exports.makeSelectMetadataForUri = makeSelectMetadataForUri; exports.makeSelectMetadataForUri = makeSelectMetadataForUri;
exports.makeSelectMetadataItemForUri = makeSelectMetadataItemForUri; exports.makeSelectMetadataItemForUri = makeSelectMetadataItemForUri;
exports.makeSelectMyPurchasesForPage = makeSelectMyPurchasesForPage;
exports.makeSelectMyStreamUrlsForPage = makeSelectMyStreamUrlsForPage; exports.makeSelectMyStreamUrlsForPage = makeSelectMyStreamUrlsForPage;
exports.makeSelectNsfwCountForChannel = makeSelectNsfwCountForChannel; exports.makeSelectNsfwCountForChannel = makeSelectNsfwCountForChannel;
exports.makeSelectNsfwCountFromUris = makeSelectNsfwCountFromUris; exports.makeSelectNsfwCountFromUris = makeSelectNsfwCountFromUris;
@ -7018,6 +7163,7 @@ exports.selectFetchingClaimSearch = selectFetchingClaimSearch;
exports.selectFetchingClaimSearchByQuery = selectFetchingClaimSearchByQuery; exports.selectFetchingClaimSearchByQuery = selectFetchingClaimSearchByQuery;
exports.selectFetchingMyChannels = selectFetchingMyChannels; exports.selectFetchingMyChannels = selectFetchingMyChannels;
exports.selectFetchingMyClaimsPageError = selectFetchingMyClaimsPageError; exports.selectFetchingMyClaimsPageError = selectFetchingMyClaimsPageError;
exports.selectFetchingMyPurchasesError = selectFetchingMyPurchasesError;
exports.selectFetchingTxosError = selectFetchingTxosError; exports.selectFetchingTxosError = selectFetchingTxosError;
exports.selectFileInfosByOutpoint = selectFileInfosByOutpoint; exports.selectFileInfosByOutpoint = selectFileInfosByOutpoint;
exports.selectFileInfosDownloaded = selectFileInfosDownloaded; exports.selectFileInfosDownloaded = selectFileInfosDownloaded;
@ -7032,6 +7178,7 @@ exports.selectHasTransactions = selectHasTransactions;
exports.selectIsFetchingClaimListMine = selectIsFetchingClaimListMine; exports.selectIsFetchingClaimListMine = selectIsFetchingClaimListMine;
exports.selectIsFetchingFileList = selectIsFetchingFileList; exports.selectIsFetchingFileList = selectIsFetchingFileList;
exports.selectIsFetchingFileListDownloadedOrPublished = selectIsFetchingFileListDownloadedOrPublished; exports.selectIsFetchingFileListDownloadedOrPublished = selectIsFetchingFileListDownloadedOrPublished;
exports.selectIsFetchingMyPurchases = selectIsFetchingMyPurchases;
exports.selectIsFetchingTransactions = selectIsFetchingTransactions; exports.selectIsFetchingTransactions = selectIsFetchingTransactions;
exports.selectIsFetchingTxos = selectIsFetchingTxos; exports.selectIsFetchingTxos = selectIsFetchingTxos;
exports.selectIsResolvingPublishUris = selectIsResolvingPublishUris; exports.selectIsResolvingPublishUris = selectIsResolvingPublishUris;
@ -7051,6 +7198,8 @@ exports.selectMyClaimsPageItemCount = selectMyClaimsPageItemCount;
exports.selectMyClaimsPageNumber = selectMyClaimsPageNumber; exports.selectMyClaimsPageNumber = selectMyClaimsPageNumber;
exports.selectMyClaimsRaw = selectMyClaimsRaw; exports.selectMyClaimsRaw = selectMyClaimsRaw;
exports.selectMyClaimsWithoutChannels = selectMyClaimsWithoutChannels; exports.selectMyClaimsWithoutChannels = selectMyClaimsWithoutChannels;
exports.selectMyPurchases = selectMyPurchases;
exports.selectMyPurchasesCount = selectMyPurchasesCount;
exports.selectMyStreamUrlsCount = selectMyStreamUrlsCount; exports.selectMyStreamUrlsCount = selectMyStreamUrlsCount;
exports.selectPendingById = selectPendingById; exports.selectPendingById = selectPendingById;
exports.selectPendingClaims = selectPendingClaims; exports.selectPendingClaims = selectPendingClaims;

View file

@ -3,12 +3,10 @@
declare type Claim = StreamClaim | ChannelClaim; declare type Claim = StreamClaim | ChannelClaim;
declare type ChannelClaim = GenericClaim & { declare type ChannelClaim = GenericClaim & {
is_channel_signature_valid?: boolean, // we may have signed channels in the future
value: ChannelMetadata, value: ChannelMetadata,
}; };
declare type StreamClaim = GenericClaim & { declare type StreamClaim = GenericClaim & {
is_channel_signature_valid?: boolean,
value: StreamMetadata, value: StreamMetadata,
}; };
@ -23,7 +21,8 @@ declare type GenericClaim = {
decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044 decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044
timestamp?: number, // date of last transaction timestamp?: number, // date of last transaction
height: number, // block height the tx was confirmed height: number, // block height the tx was confirmed
is_mine: boolean, is_channel_signature_valid?: boolean,
is_my_output: true,
name: string, name: string,
normalized_name: string, // `name` normalized via unicode NFD spec, normalized_name: string, // `name` normalized via unicode NFD spec,
nout: number, // index number for an output of a tx nout: number, // index number for an output of a tx
@ -34,6 +33,7 @@ declare type GenericClaim = {
value_type: 'stream' | 'channel', value_type: 'stream' | 'channel',
signing_channel?: ChannelClaim, signing_channel?: ChannelClaim,
repost_channel_url?: string, repost_channel_url?: string,
purchase_receipt?: PurchaseReceipt,
meta: { meta: {
activation_height: number, activation_height: number,
claims_in_channel?: number, claims_in_channel?: number,
@ -121,3 +121,15 @@ declare type Fee = {
currency: string, currency: string,
address: string, address: string,
}; };
declare type PurchaseReceipt = {
address: string,
amount: string,
claim_id: string,
confirmations: number,
height: number,
nout: number,
timestamp: number,
txid: string,
type: 'purchase',
};

View file

@ -214,6 +214,22 @@ declare type StreamRepostOptions = {
declare type StreamRepostResponse = GenericTxResponse; declare type StreamRepostResponse = GenericTxResponse;
declare type PurchaseListResponse = {
items: Array<PurchaseReceipt & { claim: StreamClaim }>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
};
declare type PurchaseListOptions = {
page: number,
page_size: number,
resolve: boolean,
claim_id?: string,
channel_id?: string,
};
// //
// Types used in the generic Lbry object that is exported // Types used in the generic Lbry object that is exported
// //
@ -253,6 +269,7 @@ declare type LbryTypes = {
support_list: (params: {}) => Promise<SupportListResponse>, support_list: (params: {}) => Promise<SupportListResponse>,
support_abandon: (params: {}) => Promise<SupportAbandonResponse>, support_abandon: (params: {}) => Promise<SupportAbandonResponse>,
stream_repost: (params: StreamRepostOptions) => Promise<StreamRepostResponse>, stream_repost: (params: StreamRepostOptions) => Promise<StreamRepostResponse>,
purchase_list: (params: PurchaseListOptions) => Promise<PurchaseListResponse>,
// File fetching and manipulation // File fetching and manipulation
file_list: (params: {}) => Promise<FileListResponse>, file_list: (params: {}) => Promise<FileListResponse>,

18
flow-typed/Claim.js vendored
View file

@ -3,12 +3,10 @@
declare type Claim = StreamClaim | ChannelClaim; declare type Claim = StreamClaim | ChannelClaim;
declare type ChannelClaim = GenericClaim & { declare type ChannelClaim = GenericClaim & {
is_channel_signature_valid?: boolean, // we may have signed channels in the future
value: ChannelMetadata, value: ChannelMetadata,
}; };
declare type StreamClaim = GenericClaim & { declare type StreamClaim = GenericClaim & {
is_channel_signature_valid?: boolean,
value: StreamMetadata, value: StreamMetadata,
}; };
@ -23,7 +21,8 @@ declare type GenericClaim = {
decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044 decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044
timestamp?: number, // date of last transaction timestamp?: number, // date of last transaction
height: number, // block height the tx was confirmed height: number, // block height the tx was confirmed
is_mine: boolean, is_channel_signature_valid?: boolean,
is_my_output: true,
name: string, name: string,
normalized_name: string, // `name` normalized via unicode NFD spec, normalized_name: string, // `name` normalized via unicode NFD spec,
nout: number, // index number for an output of a tx nout: number, // index number for an output of a tx
@ -34,6 +33,7 @@ declare type GenericClaim = {
value_type: 'stream' | 'channel', value_type: 'stream' | 'channel',
signing_channel?: ChannelClaim, signing_channel?: ChannelClaim,
repost_channel_url?: string, repost_channel_url?: string,
purchase_receipt?: PurchaseReceipt,
meta: { meta: {
activation_height: number, activation_height: number,
claims_in_channel?: number, claims_in_channel?: number,
@ -121,3 +121,15 @@ declare type Fee = {
currency: string, currency: string,
address: string, address: string,
}; };
declare type PurchaseReceipt = {
address: string,
amount: string,
claim_id: string,
confirmations: number,
height: number,
nout: number,
timestamp: number,
txid: string,
type: 'purchase',
};

17
flow-typed/Lbry.js vendored
View file

@ -214,6 +214,22 @@ declare type StreamRepostOptions = {
declare type StreamRepostResponse = GenericTxResponse; declare type StreamRepostResponse = GenericTxResponse;
declare type PurchaseListResponse = {
items: Array<PurchaseReceipt & { claim: StreamClaim }>,
page: number,
page_size: number,
total_items: number,
total_pages: number,
};
declare type PurchaseListOptions = {
page: number,
page_size: number,
resolve: boolean,
claim_id?: string,
channel_id?: string,
};
// //
// Types used in the generic Lbry object that is exported // Types used in the generic Lbry object that is exported
// //
@ -253,6 +269,7 @@ declare type LbryTypes = {
support_list: (params: {}) => Promise<SupportListResponse>, support_list: (params: {}) => Promise<SupportListResponse>,
support_abandon: (params: {}) => Promise<SupportAbandonResponse>, support_abandon: (params: {}) => Promise<SupportAbandonResponse>,
stream_repost: (params: StreamRepostOptions) => Promise<StreamRepostResponse>, stream_repost: (params: StreamRepostOptions) => Promise<StreamRepostResponse>,
purchase_list: (params: PurchaseListOptions) => Promise<PurchaseListResponse>,
// File fetching and manipulation // File fetching and manipulation
file_list: (params: {}) => Promise<FileListResponse>, file_list: (params: {}) => Promise<FileListResponse>,

View file

@ -126,6 +126,9 @@ export const ADD_FILES_REFLECTING = 'ADD_FILES_REFLECTING';
export const UPDATE_FILES_REFLECTING = 'UPDATE_FILES_REFLECTING'; export const UPDATE_FILES_REFLECTING = 'UPDATE_FILES_REFLECTING';
export const TOGGLE_CHECKING_REFLECTING = 'TOGGLE_CHECKING_REFLECTING'; export const TOGGLE_CHECKING_REFLECTING = 'TOGGLE_CHECKING_REFLECTING';
export const TOGGLE_CHECKING_PENDING = 'TOGGLE_CHECKING_PENDING'; export const TOGGLE_CHECKING_PENDING = 'TOGGLE_CHECKING_PENDING';
export const PURCHASE_LIST_STARTED = 'PURCHASE_LIST_STARTED';
export const PURCHASE_LIST_COMPLETED = 'PURCHASE_LIST_COMPLETED';
export const PURCHASE_LIST_FAILED = 'PURCHASE_LIST_FAILED';
// Comments // Comments
export const COMMENT_LIST_STARTED = 'COMMENT_LIST_STARTED'; export const COMMENT_LIST_STARTED = 'COMMENT_LIST_STARTED';

View file

@ -75,6 +75,7 @@ export {
doRepost, doRepost,
doClearRepostError, doClearRepostError,
doCheckPublishNameAvailability, doCheckPublishNameAvailability,
doPurchaseList,
} from 'redux/actions/claims'; } from 'redux/actions/claims';
export { doDeletePurchasedUri, doPurchaseUri, doFileGet } from 'redux/actions/file'; export { doDeletePurchasedUri, doPurchaseUri, doFileGet } from 'redux/actions/file';
@ -213,6 +214,8 @@ export {
makeSelectCanonicalUrlForUri, makeSelectCanonicalUrlForUri,
makeSelectPermanentUrlForUri, makeSelectPermanentUrlForUri,
makeSelectSupportsForUri, makeSelectSupportsForUri,
makeSelectMyPurchasesForPage,
makeSelectClaimWasPurchased,
selectPendingById, selectPendingById,
selectReflectingById, selectReflectingById,
selectClaimsById, selectClaimsById,
@ -253,6 +256,10 @@ export {
selectMyClaimsPageNumber, selectMyClaimsPageNumber,
selectMyClaimsPageItemCount, selectMyClaimsPageItemCount,
selectFetchingMyClaimsPageError, selectFetchingMyClaimsPageError,
selectMyPurchases,
selectIsFetchingMyPurchases,
selectFetchingMyPurchasesError,
selectMyPurchasesCount,
} from 'redux/selectors/claims'; } from 'redux/selectors/claims';
export { makeSelectCommentsForUri } from 'redux/selectors/comments'; export { makeSelectCommentsForUri } from 'redux/selectors/comments';

View file

@ -111,6 +111,7 @@ const Lbry: LbryTypes = {
transaction_list: (params = {}) => daemonCallWithResult('transaction_list', params), transaction_list: (params = {}) => daemonCallWithResult('transaction_list', params),
utxo_release: (params = {}) => daemonCallWithResult('utxo_release', params), utxo_release: (params = {}) => daemonCallWithResult('utxo_release', params),
support_abandon: (params = {}) => daemonCallWithResult('support_abandon', params), support_abandon: (params = {}) => daemonCallWithResult('support_abandon', params),
purchase_list: (params = {}) => daemonCallWithResult('purchase_list', params),
sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params), sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params),
sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params), sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params),

View file

@ -35,7 +35,9 @@ export function doResolveUris(uris: Array<string>, returnCachedClaims: boolean =
return; return;
} }
const options: { include_is_my_output?: boolean } = {}; const options: { include_is_my_output?: boolean, include_purchase_receipt: boolean } = {
include_purchase_receipt: true,
};
if (urisToResolve.length === 1) { if (urisToResolve.length === 1) {
options.include_is_my_output = true; options.include_is_my_output = true;
@ -318,6 +320,7 @@ export function doFetchClaimsByChannel(uri: string, page: number = 1) {
page: page || 1, page: page || 1,
order_by: ['release_time'], order_by: ['release_time'],
include_is_my_output: true, include_is_my_output: true,
include_purchase_receipt: true,
}).then((result: ClaimSearchResponse) => { }).then((result: ClaimSearchResponse) => {
const { items: claims, total_items: claimsInChannel, page: returnedPage } = result; const { items: claims, total_items: claimsInChannel, page: returnedPage } = result;
@ -554,7 +557,10 @@ export function doClaimSearch(
}); });
}; };
Lbry.claim_search(options).then(success, failure); Lbry.claim_search({
...options,
include_purchase_receipt: true,
}).then(success, failure);
}; };
} }
@ -623,3 +629,35 @@ export function doClearRepostError() {
type: ACTIONS.CLEAR_REPOST_ERROR, type: ACTIONS.CLEAR_REPOST_ERROR,
}; };
} }
export function doPurchaseList(page: number = 1, pageSize: number = 99999) {
return (dispatch: Dispatch) => {
dispatch({
type: ACTIONS.PURCHASE_LIST_STARTED,
});
const success = (result: PurchaseListResponse) => {
return dispatch({
type: ACTIONS.PURCHASE_LIST_COMPLETED,
data: {
result,
},
});
};
const failure = error => {
dispatch({
type: ACTIONS.PURCHASE_LIST_FAILED,
data: {
error: error.message,
},
});
};
Lbry.purchase_list({
page: page,
page_size: pageSize,
resolve: true,
}).then(success, failure);
};
}

View file

@ -25,6 +25,11 @@ type State = {
fetchingChannelClaims: { [string]: number }, fetchingChannelClaims: { [string]: number },
fetchingMyChannels: boolean, fetchingMyChannels: boolean,
fetchingClaimSearchByQuery: { [string]: boolean }, fetchingClaimSearchByQuery: { [string]: boolean },
myPurchases: ?Array<string>,
myPurchasesPageNumber: ?number,
myPurchasesPageTotalResults: ?number,
fetchingMyPurchases: boolean,
fetchingMyPurchasesError: ?string,
claimSearchByQuery: { [string]: Array<string> }, claimSearchByQuery: { [string]: Array<string> },
claimSearchByQueryLastPageReached: { [string]: Array<boolean> }, claimSearchByQueryLastPageReached: { [string]: Array<boolean> },
creatingChannel: boolean, creatingChannel: boolean,
@ -59,10 +64,13 @@ const defaultState = {
channelClaimCounts: {}, channelClaimCounts: {},
fetchingChannelClaims: {}, fetchingChannelClaims: {},
resolvingUris: [], resolvingUris: [],
// This should not be a Set
// Storing sets in reducers can cause issues
myChannelClaims: undefined, myChannelClaims: undefined,
myClaims: undefined, myClaims: undefined,
myPurchases: undefined,
myPurchasesPageNumber: undefined,
myPurchasesPageTotalResults: undefined,
fetchingMyPurchases: false,
fetchingMyPurchasesError: undefined,
fetchingMyChannels: false, fetchingMyChannels: false,
abandoningById: {}, abandoningById: {},
pendingById: {}, pendingById: {},
@ -83,6 +91,7 @@ const defaultState = {
myClaimsPageNumber: undefined, myClaimsPageNumber: undefined,
myClaimsPageTotalResults: undefined, myClaimsPageTotalResults: undefined,
isFetchingClaimListMine: false, isFetchingClaimListMine: false,
isFetchingMyPurchases: false,
isCheckingNameForPublish: false, isCheckingNameForPublish: false,
checkingPending: false, checkingPending: false,
checkingReflecting: false, checkingReflecting: false,
@ -189,13 +198,13 @@ reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED] = (state: State, action: any):
const byUri = Object.assign({}, state.claimsByUri); const byUri = Object.assign({}, state.claimsByUri);
const pendingById: { [string]: Claim } = Object.assign({}, state.pendingById); const pendingById: { [string]: Claim } = Object.assign({}, state.pendingById);
let myClaimIds = new Set(state.myClaims); let myClaimIds = new Set(state.myClaims);
let urlPage = []; let urlsForCurrentPage = [];
claims.forEach((claim: Claim) => { claims.forEach((claim: Claim) => {
const uri = buildURI({ streamName: claim.name, streamClaimId: claim.claim_id }); const uri = buildURI({ streamName: claim.name, streamClaimId: claim.claim_id });
const { claim_id: claimId } = claim; const { claim_id: claimId } = claim;
if (claim.type && claim.type.match(/claim|update/)) { if (claim.type && claim.type.match(/claim|update/)) {
urlPage.push(uri); urlsForCurrentPage.push(uri);
if (claim.confirmations < 1) { if (claim.confirmations < 1) {
pendingById[claimId] = claim; pendingById[claimId] = claim;
delete byId[claimId]; delete byId[claimId];
@ -228,7 +237,7 @@ reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED] = (state: State, action: any):
byId, byId,
claimsByUri: byUri, claimsByUri: byUri,
pendingById, pendingById,
myClaimsPageResults: urlPage, myClaimsPageResults: urlsForCurrentPage,
myClaimsPageNumber: page, myClaimsPageNumber: page,
myClaimsPageTotalResults: totalItems, myClaimsPageTotalResults: totalItems,
}); });
@ -374,6 +383,7 @@ reducers[ACTIONS.UPDATE_PENDING_CLAIMS] = (state: State, action: any): State =>
const pendingById: { [string]: Claim } = Object.assign({}, state.pendingById); const pendingById: { [string]: Claim } = Object.assign({}, state.pendingById);
let myClaimIds = new Set(state.myClaims); let myClaimIds = new Set(state.myClaims);
// $FlowFixMe
claims.forEach((claim: Claim) => { claims.forEach((claim: Claim) => {
const uri = buildURI({ streamName: claim.name, streamClaimId: claim.claim_id }); const uri = buildURI({ streamName: claim.name, streamClaimId: claim.claim_id });
const { claim_id: claimId } = claim; const { claim_id: claimId } = claim;
@ -637,6 +647,59 @@ reducers[ACTIONS.TOGGLE_CHECKING_PENDING] = (state: State, action): State => {
}); });
}; };
reducers[ACTIONS.PURCHASE_LIST_STARTED] = (state: State): State => {
return {
...state,
fetchingMyPurchases: true,
fetchingMyPurchasesError: null,
};
};
reducers[ACTIONS.PURCHASE_LIST_COMPLETED] = (state: State, action: any): State => {
const { result }: { result: PurchaseListResponse, resolve: boolean } = action.data;
const page = result.page;
const totalItems = result.total_items;
let byId = Object.assign({}, state.byId);
let byUri = Object.assign({}, state.claimsByUri);
let urlsForCurrentPage = [];
result.items.forEach(item => {
if (!item.claim) {
// Abandoned claim
return;
}
const { claim, ...purchaseInfo } = item;
claim.purchase_receipt = purchaseInfo;
const claimId = claim.claim_id;
const uri = claim.canonical_url;
byId[claimId] = claim;
byUri[uri] = claimId;
urlsForCurrentPage.push(uri);
});
return Object.assign({}, state, {
byId,
claimsByUri: byUri,
myPurchases: urlsForCurrentPage,
myPurchasesPageNumber: page,
myPurchasesPageTotalResults: totalItems,
fetchingMyPurchases: false,
});
};
reducers[ACTIONS.PURCHASE_LIST_FAILED] = (state: State, action: any): State => {
const { error } = action.data;
return {
...state,
fetchingMyPurchases: false,
fetchingMyPurchasesError: error,
};
};
export function claimsReducer(state: State = defaultState, action: any) { export function claimsReducer(state: State = defaultState, action: any) {
const handler = reducers[action.type]; const handler = reducers[action.type];
if (handler) return handler(state, action); if (handler) return handler(state, action);

View file

@ -6,9 +6,10 @@ import {
} from 'redux/selectors/search'; } from 'redux/selectors/search';
import { selectSupportsByOutpoint } from 'redux/selectors/wallet'; import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { isClaimNsfw, createNormalizedClaimSearchKey } from 'util/claim'; import { isClaimNsfw, createNormalizedClaimSearchKey, filterClaims } from 'util/claim';
import { getSearchQueryString } from 'util/query-params'; import { getSearchQueryString } from 'util/query-params';
import { PAGE_SIZE } from 'constants/claim'; import { PAGE_SIZE } from 'constants/claim';
const selectState = state => state.claims || {}; const selectState = state => state.claims || {};
export const selectClaimsById = createSelector( export const selectClaimsById = createSelector(
@ -225,6 +226,55 @@ export const makeSelectClaimIsMine = (rawUri: string) => {
); );
}; };
export const selectMyPurchases = createSelector(
selectState,
state => state.myPurchases
);
export const selectMyPurchasesCount = createSelector(
selectState,
state => state.myPurchasesPageTotalResults
);
export const selectIsFetchingMyPurchases = createSelector(
selectState,
state => state.fetchingMyPurchases
);
export const selectFetchingMyPurchasesError = createSelector(
selectState,
state => state.fetchingMyPurchasesError
);
export const makeSelectMyPurchasesForPage = (query: ?string, page: number = 1) =>
createSelector(
selectMyPurchases,
selectClaimsByUri,
(myPurchases: Array<string>, claimsByUri: { [string]: Claim }) => {
if (!myPurchases) {
return undefined;
}
const fileInfos = myPurchases.map(uri => claimsByUri[uri]);
const matchingFileInfos = filterClaims(fileInfos, query);
const start = (Number(page) - 1) * Number(PAGE_SIZE);
const end = Number(page) * Number(PAGE_SIZE);
return matchingFileInfos && matchingFileInfos.length
? matchingFileInfos
.slice(start, end)
.map(fileInfo => fileInfo.canonical_url || fileInfo.permanent_url)
: [];
}
);
export const makeSelectClaimWasPurchased = (uri: string) =>
createSelector(
makeSelectClaimForUri(uri),
claim => {
return claim && claim.purchase_receipt !== undefined;
}
);
export const selectAllFetchingChannelClaims = createSelector( export const selectAllFetchingChannelClaims = createSelector(
selectState, selectState,
state => state.fetchingChannelClaims || {} state => state.fetchingChannelClaims || {}
@ -318,8 +368,8 @@ export const makeSelectDateForUri = (uri: string) =>
(claim.value.release_time (claim.value.release_time
? claim.value.release_time * 1000 ? claim.value.release_time * 1000
: claim.meta && claim.meta.creation_timestamp : claim.meta && claim.meta.creation_timestamp
? claim.meta.creation_timestamp * 1000 ? claim.meta.creation_timestamp * 1000
: null); : null);
if (!timestamp) { if (!timestamp) {
return undefined; return undefined;
} }
@ -694,7 +744,7 @@ export const makeSelectSupportsForUri = (uri: string) =>
selectSupportsByOutpoint, selectSupportsByOutpoint,
makeSelectClaimForUri(uri), makeSelectClaimForUri(uri),
(byOutpoint, claim: ?StreamClaim) => { (byOutpoint, claim: ?StreamClaim) => {
if (!claim || !claim.is_mine) { if (!claim || !claim.is_my_output) {
return null; return null;
} }

View file

@ -212,6 +212,7 @@ function filterFileInfos(fileInfos, query) {
const queryMatchRegExp = new RegExp(query, 'i'); const queryMatchRegExp = new RegExp(query, 'i');
return fileInfos.filter(fileInfo => { return fileInfos.filter(fileInfo => {
const { metadata } = fileInfo; const { metadata } = fileInfo;
return ( return (
(metadata.title && metadata.title.match(queryMatchRegExp)) || (metadata.title && metadata.title.match(queryMatchRegExp)) ||
(fileInfo.channel_name && fileInfo.channel_name.match(queryMatchRegExp)) || (fileInfo.channel_name && fileInfo.channel_name.match(queryMatchRegExp)) ||
@ -233,12 +234,12 @@ export const makeSelectSearchDownloadUrlsForPage = (query, page = 1) =>
return matchingFileInfos && matchingFileInfos.length return matchingFileInfos && matchingFileInfos.length
? matchingFileInfos.slice(start, end).map(fileInfo => ? matchingFileInfos.slice(start, end).map(fileInfo =>
buildURI({ buildURI({
streamName: fileInfo.claim_name, streamName: fileInfo.claim_name,
channelName: fileInfo.channel_name, channelName: fileInfo.channel_name,
channelClaimId: fileInfo.channel_claim_id, channelClaimId: fileInfo.channel_claim_id,
}) })
) )
: []; : [];
} }
); );

View file

@ -51,3 +51,20 @@ export function concatClaims(
return claims; return claims;
} }
export function filterClaims(claims: Array<Claim>, query: ?string): Array<Claim> {
if (query) {
const queryMatchRegExp = new RegExp(query, 'i');
return claims.filter(claim => {
const { value } = claim;
return (
(value.title && value.title.match(queryMatchRegExp)) ||
(claim.signing_channel && claim.signing_channel.name.match(queryMatchRegExp)) ||
(claim.name && claim.name.match(queryMatchRegExp))
);
});
}
return claims;
}