Compare commits
4 commits
develop
...
importer-r
Author | SHA1 | Date | |
---|---|---|---|
827cea7417 | |||
71398364a7 | |||
80155746d5 | |||
66ed5ac58f |
|
@ -1,11 +1,5 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import openDB from '../storage/db';
|
||||
import {
|
||||
importAccount,
|
||||
importFetchedAccount,
|
||||
importFetchedAccounts,
|
||||
importErrorWhileFetchingAccountByUsername,
|
||||
} from './importer';
|
||||
import { importErrorWhileFetchingAccountByUsername } from './importer';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
export const ACCOUNT_CREATE_REQUEST = 'ACCOUNT_CREATE_REQUEST';
|
||||
|
@ -96,24 +90,6 @@ export const NOTIFICATION_SETTINGS_REQUEST = 'NOTIFICATION_SETTINGS_REQUEST';
|
|||
export const NOTIFICATION_SETTINGS_SUCCESS = 'NOTIFICATION_SETTINGS_SUCCESS';
|
||||
export const NOTIFICATION_SETTINGS_FAIL = 'NOTIFICATION_SETTINGS_FAIL';
|
||||
|
||||
function getFromDB(dispatch, getState, index, id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = index.get(id);
|
||||
|
||||
request.onerror = reject;
|
||||
|
||||
request.onsuccess = () => {
|
||||
if (!request.result) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(importAccount(request.result));
|
||||
resolve(request.result.moved && getFromDB(dispatch, getState, index, request.result.moved));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function createAccount(params) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: ACCOUNT_CREATE_REQUEST, params });
|
||||
|
@ -138,18 +114,8 @@ export function fetchAccount(id) {
|
|||
|
||||
dispatch(fetchAccountRequest(id));
|
||||
|
||||
openDB().then(db => getFromDB(
|
||||
dispatch,
|
||||
getState,
|
||||
db.transaction('accounts', 'read').objectStore('accounts').index('id'),
|
||||
id,
|
||||
).then(() => db.close(), error => {
|
||||
db.close();
|
||||
throw error;
|
||||
})).catch(() => api(getState).get(`/api/v1/accounts/${id}`).then(response => {
|
||||
dispatch(importFetchedAccount(response.data));
|
||||
})).then(() => {
|
||||
dispatch(fetchAccountSuccess());
|
||||
api(getState).get(`/api/v1/accounts/${id}`).then(response => {
|
||||
dispatch(fetchAccountSuccess(response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchAccountFail(id, error));
|
||||
});
|
||||
|
@ -167,9 +133,7 @@ export function fetchAccountByUsername(username) {
|
|||
|
||||
api(getState).get(`/api/v1/accounts/${username}`).then(response => {
|
||||
dispatch(fetchRelationships([response.data.id]));
|
||||
dispatch(importFetchedAccount(response.data));
|
||||
}).then(() => {
|
||||
dispatch(fetchAccountSuccess());
|
||||
dispatch(fetchAccountSuccess(response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchAccountFail(null, error));
|
||||
dispatch(importErrorWhileFetchingAccountByUsername(username));
|
||||
|
@ -184,9 +148,10 @@ export function fetchAccountRequest(id) {
|
|||
};
|
||||
};
|
||||
|
||||
export function fetchAccountSuccess() {
|
||||
export function fetchAccountSuccess(account) {
|
||||
return {
|
||||
type: ACCOUNT_FETCH_SUCCESS,
|
||||
account,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -507,7 +472,6 @@ export function fetchFollowers(id) {
|
|||
api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchFollowersSuccess(id, response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => {
|
||||
|
@ -555,7 +519,6 @@ export function expandFollowers(id) {
|
|||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandFollowersSuccess(id, response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => {
|
||||
|
@ -597,7 +560,6 @@ export function fetchFollowing(id) {
|
|||
api(getState).get(`/api/v1/accounts/${id}/following`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchFollowingSuccess(id, response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => {
|
||||
|
@ -645,7 +607,6 @@ export function expandFollowing(id) {
|
|||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandFollowingSuccess(id, response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => {
|
||||
|
@ -731,7 +692,6 @@ export function fetchFollowRequests() {
|
|||
|
||||
api(getState).get('/api/v1/follow_requests').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => dispatch(fetchFollowRequestsFail(error)));
|
||||
};
|
||||
|
@ -772,7 +732,6 @@ export function expandFollowRequests() {
|
|||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => dispatch(expandFollowRequestsFail(error)));
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import api from '../api';
|
||||
import { importFetchedAccount, importFetchedStatuses } from 'soapbox/actions/importer';
|
||||
import { importFetchedStatuses } from 'soapbox/actions/importer';
|
||||
import { fetchRelationships } from 'soapbox/actions/accounts';
|
||||
|
||||
export const ADMIN_CONFIG_FETCH_REQUEST = 'ADMIN_CONFIG_FETCH_REQUEST';
|
||||
|
@ -97,8 +97,6 @@ export function fetchReports(params) {
|
|||
.get('/api/pleroma/admin/reports', { params })
|
||||
.then(({ data: { reports } }) => {
|
||||
reports.forEach(report => {
|
||||
dispatch(importFetchedAccount(report.account));
|
||||
dispatch(importFetchedAccount(report.actor));
|
||||
dispatch(importFetchedStatuses(report.statuses));
|
||||
});
|
||||
dispatch({ type: ADMIN_REPORTS_FETCH_SUCCESS, reports, params });
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { defineMessages } from 'react-intl';
|
||||
import api, { baseClient } from '../api';
|
||||
import { importFetchedAccount } from './importer';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { createAccount } from 'soapbox/actions/accounts';
|
||||
import { fetchMeSuccess, fetchMeFail } from 'soapbox/actions/me';
|
||||
|
@ -145,7 +144,6 @@ export function verifyCredentials(token) {
|
|||
dispatch({ type: VERIFY_CREDENTIALS_REQUEST });
|
||||
|
||||
return baseClient(token).get('/api/v1/accounts/verify_credentials').then(({ data: account }) => {
|
||||
dispatch(importFetchedAccount(account));
|
||||
dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account });
|
||||
if (account.id === getState().get('me')) dispatch(fetchMeSuccess(account));
|
||||
return account;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { getNextLinkName } from 'soapbox/utils/quirks';
|
||||
|
||||
|
@ -21,7 +20,6 @@ export function fetchBlocks() {
|
|||
|
||||
api(getState).get('/api/v1/blocks').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === nextLinkName);
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => dispatch(fetchBlocksFail(error)));
|
||||
|
@ -64,7 +62,6 @@ export function expandBlocks() {
|
|||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === nextLinkName);
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandBlocksSuccess(response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => dispatch(expandBlocksFail(error)));
|
||||
|
|
|
@ -5,7 +5,6 @@ import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light
|
|||
import { tagHistory } from '../settings';
|
||||
import { useEmoji } from './emojis';
|
||||
import resizeImage from '../utils/resize_image';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { updateTimeline, dequeueTimeline } from './timelines';
|
||||
import { showAlert, showAlertForError } from './alerts';
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
@ -388,7 +387,6 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) =>
|
|||
limit: 4,
|
||||
},
|
||||
}).then(response => {
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(readyComposeSuggestionsAccounts(token, response.data));
|
||||
}).catch(error => {
|
||||
if (!isCancel(error)) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import {
|
||||
importFetchedAccounts,
|
||||
importFetchedStatuses,
|
||||
importFetchedStatus,
|
||||
} from './importer';
|
||||
|
@ -52,7 +51,6 @@ export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => {
|
|||
.then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(importFetchedAccounts(response.data.reduce((aggr, item) => aggr.concat(item.accounts), [])));
|
||||
dispatch(importFetchedStatuses(response.data.map(item => item.last_status).filter(x => !!x)));
|
||||
dispatch(expandConversationsSuccess(response.data, next ? next.uri : null, isLoadingRecent));
|
||||
})
|
||||
|
@ -76,8 +74,6 @@ export const expandConversationsFail = error => ({
|
|||
});
|
||||
|
||||
export const updateConversations = conversation => dispatch => {
|
||||
dispatch(importFetchedAccounts(conversation.accounts));
|
||||
|
||||
if (conversation.last_status) {
|
||||
dispatch(importFetchedStatus(conversation.last_status));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import api from '../api';
|
||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
import { importFetchedStatus } from './importer';
|
||||
import { favourite, unfavourite } from './interactions';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
|
@ -54,9 +54,6 @@ export function fetchEmojiReacts(id, emoji) {
|
|||
: `/api/v1/pleroma/statuses/${id}/reactions`;
|
||||
|
||||
return api(getState).get(url).then(response => {
|
||||
response.data.forEach(emojiReact => {
|
||||
dispatch(importFetchedAccounts(emojiReact.accounts));
|
||||
});
|
||||
dispatch(fetchEmojiReactsSuccess(id, response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchEmojiReactsFail(id, error));
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
|
@ -235,7 +234,6 @@ export function fetchMembers(id) {
|
|||
api(getState).get(`/api/v1/groups/${id}/accounts`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchMembersSuccess(id, response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => {
|
||||
|
@ -283,7 +281,6 @@ export function expandMembers(id) {
|
|||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandMembersSuccess(id, response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => {
|
||||
|
@ -325,7 +322,6 @@ export function fetchRemovedAccounts(id) {
|
|||
api(getState).get(`/api/v1/groups/${id}/removed_accounts`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchRemovedAccountsSuccess(id, response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => {
|
||||
|
@ -373,7 +369,6 @@ export function expandRemovedAccounts(id) {
|
|||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandRemovedAccountsSuccess(id, response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => {
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
import { getSettings } from '../settings';
|
||||
import {
|
||||
normalizeAccount,
|
||||
normalizeStatus,
|
||||
normalizePoll,
|
||||
} from './normalizer';
|
||||
|
||||
export const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT';
|
||||
export const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT';
|
||||
export const STATUS_IMPORT = 'STATUS_IMPORT';
|
||||
export const STATUSES_IMPORT = 'STATUSES_IMPORT';
|
||||
export const POLLS_IMPORT = 'POLLS_IMPORT';
|
||||
|
@ -18,14 +15,6 @@ function pushUnique(array, object) {
|
|||
}
|
||||
}
|
||||
|
||||
export function importAccount(account) {
|
||||
return { type: ACCOUNT_IMPORT, account };
|
||||
}
|
||||
|
||||
export function importAccounts(accounts) {
|
||||
return { type: ACCOUNTS_IMPORT, accounts };
|
||||
}
|
||||
|
||||
export function importStatus(status) {
|
||||
return { type: STATUS_IMPORT, status };
|
||||
}
|
||||
|
@ -38,28 +27,6 @@ export function importPolls(polls) {
|
|||
return { type: POLLS_IMPORT, polls };
|
||||
}
|
||||
|
||||
export function importFetchedAccount(account) {
|
||||
return importFetchedAccounts([account]);
|
||||
}
|
||||
|
||||
export function importFetchedAccounts(accounts) {
|
||||
const normalAccounts = [];
|
||||
|
||||
function processAccount(account) {
|
||||
if (!account.id) return;
|
||||
|
||||
pushUnique(normalAccounts, normalizeAccount(account));
|
||||
|
||||
if (account.moved) {
|
||||
processAccount(account.moved);
|
||||
}
|
||||
}
|
||||
|
||||
accounts.forEach(processAccount);
|
||||
|
||||
return importAccounts(normalAccounts);
|
||||
}
|
||||
|
||||
export function importFetchedStatus(status) {
|
||||
return importFetchedStatuses([status]);
|
||||
}
|
||||
|
@ -108,7 +75,6 @@ export function importFetchedStatuses(statuses) {
|
|||
statuses.forEach(processStatus);
|
||||
|
||||
dispatch(importPolls(polls));
|
||||
dispatch(importFetchedAccounts(accounts));
|
||||
dispatch(importStatuses(normalStatuses));
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import emojify from '../../features/emoji/emoji';
|
||||
import { unescapeHTML } from '../../utils/html';
|
||||
|
||||
const domParser = new DOMParser();
|
||||
|
||||
|
@ -9,31 +8,6 @@ const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {
|
|||
return obj;
|
||||
}, {});
|
||||
|
||||
export function normalizeAccount(account) {
|
||||
account = { ...account };
|
||||
|
||||
const emojiMap = makeEmojiMap(account);
|
||||
const displayName = account.display_name.trim().length === 0 ? account.username : account.display_name;
|
||||
|
||||
account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap);
|
||||
account.note_emojified = emojify(account.note, emojiMap);
|
||||
|
||||
if (account.fields) {
|
||||
account.fields = account.fields.map(pair => ({
|
||||
...pair,
|
||||
name_emojified: emojify(escapeTextContentForBrowser(pair.name)),
|
||||
value_emojified: emojify(pair.value, emojiMap),
|
||||
value_plain: unescapeHTML(pair.value),
|
||||
}));
|
||||
}
|
||||
|
||||
if (account.moved) {
|
||||
account.moved = account.moved.id;
|
||||
}
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
export function normalizeStatus(status, normalOldStatus, expandSpoilers) {
|
||||
const normalStatus = { ...status };
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { defineMessages } from 'react-intl';
|
||||
import api from '../api';
|
||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
import { importFetchedStatus } from './importer';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
|
@ -139,7 +139,7 @@ export function favourite(status) {
|
|||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function(response) {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(favouriteSuccess(status));
|
||||
dispatch(favouriteSuccess(response.data));
|
||||
}).catch(function(error) {
|
||||
dispatch(favouriteFail(status, error));
|
||||
});
|
||||
|
@ -154,7 +154,7 @@ export function unfavourite(status) {
|
|||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unfavouriteSuccess(status));
|
||||
dispatch(unfavouriteSuccess(response.data));
|
||||
}).catch(error => {
|
||||
dispatch(unfavouriteFail(status, error));
|
||||
});
|
||||
|
@ -217,7 +217,7 @@ export function bookmark(intl, status) {
|
|||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function(response) {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(bookmarkSuccess(status, response.data));
|
||||
dispatch(bookmarkSuccess(response.data));
|
||||
dispatch(snackbar.success(intl.formatMessage(messages.bookmarkAdded)));
|
||||
}).catch(function(error) {
|
||||
dispatch(bookmarkFail(status, error));
|
||||
|
@ -231,7 +231,7 @@ export function unbookmark(intl, status) {
|
|||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unbookmarkSuccess(status, response.data));
|
||||
dispatch(unbookmarkSuccess(response.data));
|
||||
dispatch(snackbar.success(intl.formatMessage(messages.bookmarkRemoved)));
|
||||
}).catch(error => {
|
||||
dispatch(unbookmarkFail(status, error));
|
||||
|
@ -246,11 +246,10 @@ export function bookmarkRequest(status) {
|
|||
};
|
||||
};
|
||||
|
||||
export function bookmarkSuccess(status, response) {
|
||||
export function bookmarkSuccess(status) {
|
||||
return {
|
||||
type: BOOKMARK_SUCCESS,
|
||||
status: status,
|
||||
response: response,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -269,11 +268,10 @@ export function unbookmarkRequest(status) {
|
|||
};
|
||||
};
|
||||
|
||||
export function unbookmarkSuccess(status, response) {
|
||||
export function unbookmarkSuccess(status) {
|
||||
return {
|
||||
type: UNBOOKMARK_SUCCESS,
|
||||
status: status,
|
||||
response: response,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -292,7 +290,6 @@ export function fetchReblogs(id) {
|
|||
dispatch(fetchReblogsRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then(response => {
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchReblogsSuccess(id, response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchReblogsFail(id, error));
|
||||
|
@ -329,7 +326,6 @@ export function fetchFavourites(id) {
|
|||
dispatch(fetchFavouritesRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then(response => {
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchFavouritesSuccess(id, response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchFavouritesFail(id, error));
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import api from '../api';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { showAlertForError } from './alerts';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
|
@ -223,7 +222,6 @@ export const fetchListAccounts = listId => (dispatch, getState) => {
|
|||
dispatch(fetchListAccountsRequest(listId));
|
||||
|
||||
api(getState).get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchListAccountsSuccess(listId, data));
|
||||
}).catch(err => dispatch(fetchListAccountsFail(listId, err)));
|
||||
};
|
||||
|
@ -257,7 +255,6 @@ export const fetchListSuggestions = q => (dispatch, getState) => {
|
|||
};
|
||||
|
||||
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchListSuggestionsReady(q, data));
|
||||
}).catch(error => dispatch(showAlertForError(error)));
|
||||
};
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import api from '../api';
|
||||
import { importFetchedAccount } from './importer';
|
||||
import { verifyCredentials } from './auth';
|
||||
|
||||
export const ME_FETCH_REQUEST = 'ME_FETCH_REQUEST';
|
||||
|
@ -52,7 +51,6 @@ export function fetchMeRequest() {
|
|||
|
||||
export function fetchMeSuccess(me) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(importFetchedAccount(me));
|
||||
dispatch({
|
||||
type: ME_FETCH_SUCCESS,
|
||||
me,
|
||||
|
@ -76,7 +74,6 @@ export function patchMeRequest() {
|
|||
|
||||
export function patchMeSuccess(me) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(importFetchedAccount(me));
|
||||
dispatch({
|
||||
type: ME_PATCH_SUCCESS,
|
||||
me,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { openModal } from './modal';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { getNextLinkName } from 'soapbox/utils/quirks';
|
||||
|
@ -25,7 +24,6 @@ export function fetchMutes() {
|
|||
|
||||
api(getState).get('/api/v1/mutes').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === nextLinkName);
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchMutesSuccess(response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => dispatch(fetchMutesFail(error)));
|
||||
|
@ -68,7 +66,6 @@ export function expandMutes() {
|
|||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === nextLinkName);
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandMutesSuccess(response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => dispatch(expandMutesFail(error)));
|
||||
|
|
|
@ -3,8 +3,6 @@ import IntlMessageFormat from 'intl-messageformat';
|
|||
import 'intl-pluralrules';
|
||||
import { fetchRelationships } from './accounts';
|
||||
import {
|
||||
importFetchedAccount,
|
||||
importFetchedAccounts,
|
||||
importFetchedStatus,
|
||||
importFetchedStatuses,
|
||||
} from './importer';
|
||||
|
@ -52,19 +50,10 @@ const fetchRelatedRelationships = (dispatch, notifications) => {
|
|||
}
|
||||
};
|
||||
|
||||
export function updateNotifications(notification, intlMessages, intlLocale) {
|
||||
function updateNotifications(notification, intlMessages, intlLocale) {
|
||||
return (dispatch, getState) => {
|
||||
const showInColumn = getSettings(getState()).getIn(['notifications', 'shows', notification.type], true);
|
||||
|
||||
if (notification.account) {
|
||||
dispatch(importFetchedAccount(notification.account));
|
||||
}
|
||||
|
||||
// Used by Move notification
|
||||
if (notification.target) {
|
||||
dispatch(importFetchedAccount(notification.target));
|
||||
}
|
||||
|
||||
if (notification.status) {
|
||||
dispatch(importFetchedStatus(notification.status));
|
||||
}
|
||||
|
@ -196,15 +185,6 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
|
|||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
const entries = response.data.reduce((acc, item) => {
|
||||
if (item.account && item.account.id) {
|
||||
acc.accounts[item.account.id] = item.account;
|
||||
}
|
||||
|
||||
// Used by Move notification
|
||||
if (item.target && item.target.id) {
|
||||
acc.accounts[item.target.id] = item.target;
|
||||
}
|
||||
|
||||
if (item.status && item.status.id) {
|
||||
acc.statuses[item.status.id] = item.status;
|
||||
}
|
||||
|
@ -212,7 +192,6 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
|
|||
return acc;
|
||||
}, { accounts: {}, statuses: {} });
|
||||
|
||||
dispatch(importFetchedAccounts(Object.values(entries.accounts)));
|
||||
dispatch(importFetchedStatuses(Object.values(entries.statuses)));
|
||||
|
||||
dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import api from '../api';
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts, importFetchedStatuses } from './importer';
|
||||
import { importFetchedStatuses } from './importer';
|
||||
|
||||
export const SEARCH_CHANGE = 'SEARCH_CHANGE';
|
||||
export const SEARCH_CLEAR = 'SEARCH_CLEAR';
|
||||
|
@ -40,10 +40,6 @@ export function submitSearch() {
|
|||
limit: 20,
|
||||
},
|
||||
}).then(response => {
|
||||
if (response.data.accounts) {
|
||||
dispatch(importFetchedAccounts(response.data.accounts));
|
||||
}
|
||||
|
||||
if (response.data.statuses) {
|
||||
dispatch(importFetchedStatuses(response.data.statuses));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import api from '../api';
|
||||
import openDB from '../storage/db';
|
||||
import { evictStatus } from '../storage/modifier';
|
||||
import { deleteFromTimelines } from './timelines';
|
||||
import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer';
|
||||
import { openModal } from './modal';
|
||||
|
@ -59,48 +57,6 @@ export function createStatus(params, idempotencyKey) {
|
|||
};
|
||||
};
|
||||
|
||||
function getFromDB(dispatch, getState, accountIndex, index, id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = index.get(id);
|
||||
|
||||
request.onerror = reject;
|
||||
|
||||
request.onsuccess = () => {
|
||||
const promises = [];
|
||||
|
||||
if (!request.result) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(importStatus(request.result));
|
||||
|
||||
if (getState().getIn(['accounts', request.result.account], null) === null) {
|
||||
promises.push(new Promise((accountResolve, accountReject) => {
|
||||
const accountRequest = accountIndex.get(request.result.account);
|
||||
|
||||
accountRequest.onerror = accountReject;
|
||||
accountRequest.onsuccess = () => {
|
||||
if (!request.result) {
|
||||
accountReject();
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(importAccount(accountRequest.result));
|
||||
accountResolve();
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
if (request.result.reblog && getState().getIn(['statuses', request.result.reblog], null) === null) {
|
||||
promises.push(getFromDB(dispatch, getState, accountIndex, index, request.result.reblog));
|
||||
}
|
||||
|
||||
resolve(Promise.all(promises));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchStatus(id) {
|
||||
return (dispatch, getState) => {
|
||||
const skipLoading = getState().getIn(['statuses', id], null) !== null;
|
||||
|
@ -113,31 +69,19 @@ export function fetchStatus(id) {
|
|||
|
||||
dispatch(fetchStatusRequest(id, skipLoading));
|
||||
|
||||
openDB().then(db => {
|
||||
const transaction = db.transaction(['accounts', 'statuses'], 'read');
|
||||
const accountIndex = transaction.objectStore('accounts').index('id');
|
||||
const index = transaction.objectStore('statuses').index('id');
|
||||
|
||||
return getFromDB(dispatch, getState, accountIndex, index, id).then(() => {
|
||||
db.close();
|
||||
}, error => {
|
||||
db.close();
|
||||
throw error;
|
||||
});
|
||||
}).then(() => {
|
||||
dispatch(fetchStatusSuccess(skipLoading));
|
||||
}, () => api(getState).get(`/api/v1/statuses/${id}`).then(response => {
|
||||
api(getState).get(`/api/v1/statuses/${id}`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(fetchStatusSuccess(skipLoading));
|
||||
})).catch(error => {
|
||||
dispatch(fetchStatusSuccess(response.data, skipLoading));
|
||||
}).catch(error => {
|
||||
dispatch(fetchStatusFail(id, error, skipLoading));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchStatusSuccess(skipLoading) {
|
||||
export function fetchStatusSuccess(status, skipLoading) {
|
||||
return {
|
||||
type: STATUS_FETCH_SUCCESS,
|
||||
status,
|
||||
skipLoading,
|
||||
};
|
||||
};
|
||||
|
@ -173,7 +117,6 @@ export function deleteStatus(id, routerHistory, withRedraft = false) {
|
|||
dispatch(deleteStatusRequest(id));
|
||||
|
||||
api(getState).delete(`/api/v1/statuses/${id}`).then(response => {
|
||||
evictStatus(id);
|
||||
dispatch(deleteStatusSuccess(id));
|
||||
dispatch(deleteFromTimelines(id));
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ import messages from 'soapbox/locales/messages';
|
|||
|
||||
export const STREAMING_CHAT_UPDATE = 'STREAMING_CHAT_UPDATE';
|
||||
export const STREAMING_FOLLOW_RELATIONSHIPS_UPDATE = 'STREAMING_FOLLOW_RELATIONSHIPS_UPDATE';
|
||||
export const STREAMING_NOTIFICATION_UPDATE = 'STREAMING_NOTIFICATION_UPDATE';
|
||||
export const STREAMING_TIMELINE_UPDATE = 'STREAMING_TIMELINE_UPDATE';
|
||||
|
||||
const validLocale = locale => Object.keys(messages).includes(locale);
|
||||
|
||||
|
@ -33,10 +35,81 @@ function updateFollowRelationships(relationships) {
|
|||
};
|
||||
}
|
||||
|
||||
function updateChat(chat) {
|
||||
return (dispatch, getState) => {
|
||||
const me = getState().get('me');
|
||||
const messageOwned = !(chat.last_message && chat.last_message.account_id !== me);
|
||||
|
||||
dispatch({
|
||||
type: STREAMING_CHAT_UPDATE,
|
||||
chat,
|
||||
me,
|
||||
// Only play sounds for recipient messages
|
||||
meta: !messageOwned && getSettings(getState()).getIn(['chats', 'sound']) && { sound: 'chat' },
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
function updateNotification(notification) {
|
||||
return (dispatch, getState) => {
|
||||
const locale = getLocale(getState());
|
||||
|
||||
dispatch({
|
||||
type: STREAMING_NOTIFICATION_UPDATE,
|
||||
notification,
|
||||
});
|
||||
|
||||
messages[locale]().then(messages => {
|
||||
dispatch(updateNotificationsQueue(notification, messages, locale, window.location.pathname));
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
function updateTimeline(timelineId, status, accept) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: STREAMING_TIMELINE_UPDATE,
|
||||
timelineId,
|
||||
status,
|
||||
});
|
||||
|
||||
dispatch(processTimelineUpdate(timelineId, status, accept));
|
||||
};
|
||||
};
|
||||
|
||||
function handleEvent(timelineId, { event, payload }, accept) {
|
||||
return (dispatch, getState) => {
|
||||
switch(event) {
|
||||
case 'update':
|
||||
dispatch(updateTimeline(timelineId, JSON.parse(payload), accept));
|
||||
break;
|
||||
case 'delete':
|
||||
dispatch(deleteFromTimelines(payload));
|
||||
break;
|
||||
case 'notification':
|
||||
dispatch(updateNotification(JSON.parse(payload)));
|
||||
break;
|
||||
case 'conversation':
|
||||
dispatch(updateConversations(JSON.parse(payload)));
|
||||
break;
|
||||
case 'filters_changed':
|
||||
dispatch(fetchFilters());
|
||||
break;
|
||||
case 'pleroma:chat_update':
|
||||
dispatch(updateChat(JSON.parse(payload)));
|
||||
break;
|
||||
case 'pleroma:follow_relationships_update':
|
||||
dispatch(updateFollowRelationships(JSON.parse(payload)));
|
||||
break;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export function connectTimelineStream(timelineId, path, pollingRefresh = null, accept = null) {
|
||||
|
||||
return connectStream (path, pollingRefresh, (dispatch, getState) => {
|
||||
const locale = getLocale(getState());
|
||||
|
||||
return {
|
||||
onConnect() {
|
||||
|
@ -48,45 +121,7 @@ export function connectTimelineStream(timelineId, path, pollingRefresh = null, a
|
|||
},
|
||||
|
||||
onReceive(data) {
|
||||
switch(data.event) {
|
||||
case 'update':
|
||||
dispatch(processTimelineUpdate(timelineId, JSON.parse(data.payload), accept));
|
||||
break;
|
||||
case 'delete':
|
||||
dispatch(deleteFromTimelines(data.payload));
|
||||
break;
|
||||
case 'notification':
|
||||
messages[locale]().then(messages => {
|
||||
dispatch(updateNotificationsQueue(JSON.parse(data.payload), messages, locale, window.location.pathname));
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
break;
|
||||
case 'conversation':
|
||||
dispatch(updateConversations(JSON.parse(data.payload)));
|
||||
break;
|
||||
case 'filters_changed':
|
||||
dispatch(fetchFilters());
|
||||
break;
|
||||
case 'pleroma:chat_update':
|
||||
dispatch((dispatch, getState) => {
|
||||
const chat = JSON.parse(data.payload);
|
||||
const me = getState().get('me');
|
||||
const messageOwned = !(chat.last_message && chat.last_message.account_id !== me);
|
||||
|
||||
dispatch({
|
||||
type: STREAMING_CHAT_UPDATE,
|
||||
chat,
|
||||
me,
|
||||
// Only play sounds for recipient messages
|
||||
meta: !messageOwned && getSettings(getState()).getIn(['chats', 'sound']) && { sound: 'chat' },
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 'pleroma:follow_relationships_update':
|
||||
dispatch(updateFollowRelationships(JSON.parse(data.payload)));
|
||||
break;
|
||||
}
|
||||
dispatch(handleEvent(timelineId, data, accept));
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import api from '../api';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
export const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST';
|
||||
|
@ -13,7 +12,6 @@ export function fetchSuggestions() {
|
|||
dispatch(fetchSuggestionsRequest());
|
||||
|
||||
api(getState).get('/api/v1/suggestions').then(response => {
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchSuggestionsSuccess(response.data));
|
||||
}).catch(error => dispatch(fetchSuggestionsFail(error)));
|
||||
};
|
||||
|
|
|
@ -9,31 +9,6 @@ describe('accounts reducer', () => {
|
|||
expect(reducer(undefined, {})).toEqual(ImmutableMap());
|
||||
});
|
||||
|
||||
// fails to add normalized accounts to state
|
||||
// it('should handle ACCOUNT_IMPORT', () => {
|
||||
// const state = ImmutableMap({ });
|
||||
// const account = take(accounts, 1);
|
||||
// const action = {
|
||||
// type: actions.ACCOUNT_IMPORT,
|
||||
// account: account,
|
||||
// };
|
||||
// debugger;
|
||||
// expect(reducer(state, action).toJS()).toMatchObject({
|
||||
// });
|
||||
// });
|
||||
|
||||
// fails to add normalized accounts to state
|
||||
// it('should handle ACCOUNTS_IMPORT', () => {
|
||||
// const state = ImmutableMap({ });
|
||||
// const accounts = take(accounts, 2);
|
||||
// const action = {
|
||||
// type: actions.ACCOUNTS_IMPORT,
|
||||
// accounts: accounts,
|
||||
// };
|
||||
// expect(reducer(state, action).toJS()).toMatchObject({
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// it('should handle ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP', () => {
|
||||
// const state = ImmutableMap({ username: 'curtis' });
|
||||
// const action = {
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
import reducer from '../accounts_counters';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
// import { ACCOUNT_FOLLOW_SUCCESS, ACCOUNT_UNFOLLOW_SUCCESS } from 'soapbox/actions/accounts';
|
||||
// import relationship from 'soapbox/__fixtures__/relationship.json';
|
||||
// import accounts_counter_initial from 'soapbox/__fixtures__/accounts_counter_initial.json';
|
||||
// import accounts_counter_unfollow from 'soapbox/__fixtures__/accounts_counter_unfollow.json';
|
||||
// import accounts_counter_follow from 'soapbox/__fixtures__/accounts_counter_follow.json';
|
||||
|
||||
|
||||
describe('accounts_counters reducer', () => {
|
||||
it('should return the initial state', () => {
|
||||
expect(reducer(undefined, {})).toEqual(ImmutableMap());
|
||||
});
|
||||
|
||||
// it('should handle ACCOUNT_FOLLOW_SUCCESS', () => {
|
||||
// const state = ImmutableList([accounts_counter_initial]);
|
||||
// const action = {
|
||||
// type: ACCOUNT_FOLLOW_SUCCESS,
|
||||
// relationship: relationship,
|
||||
// alreadyFollowing: false,
|
||||
// };
|
||||
// expect(reducer(state, action)).toEqual(
|
||||
// ImmutableList([ accounts_counter_follow ]));
|
||||
// });
|
||||
//
|
||||
// it('should handle ACCOUNT_UNFOLLOW_SUCCESS', () => {
|
||||
// const state = ImmutableList([accounts_counter_initial]);
|
||||
// const action = {
|
||||
// type: ACCOUNT_UNFOLLOW_SUCCESS,
|
||||
// relationship: relationship,
|
||||
// alreadyFollowing: true,
|
||||
// };
|
||||
// expect(reducer(state, action)).toEqual(
|
||||
// ImmutableList([accounts_counter_unfollow]));
|
||||
// });
|
||||
|
||||
});
|
|
@ -1,38 +1,8 @@
|
|||
import reducer from '../relationships';
|
||||
import {
|
||||
ACCOUNT_IMPORT,
|
||||
} from '../../actions/importer';
|
||||
import lain from 'soapbox/__fixtures__/lain.json';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
describe('relationships reducer', () => {
|
||||
it('should return the initial state', () => {
|
||||
expect(reducer(undefined, {})).toEqual(ImmutableMap());
|
||||
});
|
||||
|
||||
describe('ACCOUNT_IMPORT', () => {
|
||||
it('should import the relationship', () => {
|
||||
const action = {
|
||||
type: ACCOUNT_IMPORT,
|
||||
account: lain,
|
||||
};
|
||||
const state = ImmutableMap();
|
||||
expect(reducer(state, action)).toEqual(fromJS({
|
||||
'9v5bqYwY2jfmvPNhTM': {
|
||||
blocked_by: false,
|
||||
blocking: false,
|
||||
domain_blocking: false,
|
||||
endorsed: false,
|
||||
followed_by: true,
|
||||
following: true,
|
||||
id: '9v5bqYwY2jfmvPNhTM',
|
||||
muting: false,
|
||||
muting_notifications: false,
|
||||
requested: false,
|
||||
showing_reblogs: true,
|
||||
subscribing: false,
|
||||
},
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,17 +1,90 @@
|
|||
import {
|
||||
ACCOUNT_IMPORT,
|
||||
ACCOUNTS_IMPORT,
|
||||
ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP,
|
||||
} from '../actions/importer';
|
||||
import { CHATS_FETCH_SUCCESS, CHAT_FETCH_SUCCESS } from 'soapbox/actions/chats';
|
||||
import { STREAMING_CHAT_UPDATE } from 'soapbox/actions/streaming';
|
||||
import { normalizeAccount as normalizeAccount2 } from 'soapbox/actions/importer/normalizer';
|
||||
} from 'soapbox/actions/importer';
|
||||
import {
|
||||
Map as ImmutableMap,
|
||||
List as ImmutableList,
|
||||
fromJS,
|
||||
} from 'immutable';
|
||||
import { normalizePleromaUserFields } from 'soapbox/utils/pleroma';
|
||||
ACCOUNT_FETCH_SUCCESS,
|
||||
FOLLOWERS_FETCH_SUCCESS,
|
||||
FOLLOWERS_EXPAND_SUCCESS,
|
||||
FOLLOWING_FETCH_SUCCESS,
|
||||
FOLLOWING_EXPAND_SUCCESS,
|
||||
FOLLOW_REQUESTS_FETCH_SUCCESS,
|
||||
FOLLOW_REQUESTS_EXPAND_SUCCESS,
|
||||
} from 'soapbox/actions/accounts';
|
||||
import {
|
||||
VERIFY_CREDENTIALS_SUCCESS,
|
||||
} from 'soapbox/actions/auth';
|
||||
import {
|
||||
ME_FETCH_SUCCESS,
|
||||
ME_PATCH_SUCCESS,
|
||||
} from 'soapbox/actions/me';
|
||||
import {
|
||||
BLOCKS_FETCH_SUCCESS,
|
||||
BLOCKS_EXPAND_SUCCESS,
|
||||
} from 'soapbox/actions/blocks';
|
||||
import {
|
||||
MUTES_FETCH_SUCCESS,
|
||||
MUTES_EXPAND_SUCCESS,
|
||||
} from 'soapbox/actions/mutes';
|
||||
import {
|
||||
COMPOSE_SUGGESTIONS_READY,
|
||||
} from 'soapbox/actions/compose';
|
||||
import {
|
||||
REBLOG_SUCCESS,
|
||||
UNREBLOG_SUCCESS,
|
||||
FAVOURITE_SUCCESS,
|
||||
UNFAVOURITE_SUCCESS,
|
||||
REBLOGS_FETCH_SUCCESS,
|
||||
FAVOURITES_FETCH_SUCCESS,
|
||||
BOOKMARK_SUCCESS,
|
||||
UNBOOKMARK_SUCCESS,
|
||||
} from 'soapbox/actions/interactions';
|
||||
import {
|
||||
TIMELINE_REFRESH_SUCCESS,
|
||||
TIMELINE_EXPAND_SUCCESS,
|
||||
} from 'soapbox/actions/timelines';
|
||||
import {
|
||||
STATUS_FETCH_SUCCESS,
|
||||
CONTEXT_FETCH_SUCCESS,
|
||||
} from 'soapbox/actions/statuses';
|
||||
import { SEARCH_FETCH_SUCCESS } from 'soapbox/actions/search';
|
||||
import {
|
||||
CONVERSATIONS_FETCH_SUCCESS,
|
||||
CONVERSATIONS_UPDATE,
|
||||
} from 'soapbox/actions/conversations';
|
||||
import {
|
||||
NOTIFICATIONS_UPDATE,
|
||||
NOTIFICATIONS_REFRESH_SUCCESS,
|
||||
NOTIFICATIONS_EXPAND_SUCCESS,
|
||||
} from 'soapbox/actions/notifications';
|
||||
import {
|
||||
FAVOURITED_STATUSES_FETCH_SUCCESS,
|
||||
FAVOURITED_STATUSES_EXPAND_SUCCESS,
|
||||
} from 'soapbox/actions/favourites';
|
||||
import {
|
||||
LIST_ACCOUNTS_FETCH_SUCCESS,
|
||||
LIST_EDITOR_SUGGESTIONS_READY,
|
||||
} from 'soapbox/actions/lists';
|
||||
import {
|
||||
SUGGESTIONS_FETCH_SUCCESS,
|
||||
} from 'soapbox/actions/suggestions';
|
||||
import {
|
||||
CHATS_FETCH_SUCCESS,
|
||||
CHAT_FETCH_SUCCESS,
|
||||
} from 'soapbox/actions/chats';
|
||||
import {
|
||||
EMOJI_REACTS_FETCH_SUCCESS,
|
||||
} from 'soapbox/actions/emoji_reacts';
|
||||
import {
|
||||
GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS,
|
||||
GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS,
|
||||
GROUP_MEMBERS_FETCH_SUCCESS,
|
||||
GROUP_MEMBERS_EXPAND_SUCCESS,
|
||||
} from 'soapbox/actions/groups';
|
||||
import {
|
||||
STREAMING_NOTIFICATION_UPDATE,
|
||||
STREAMING_CHAT_UPDATE,
|
||||
STREAMING_TIMELINE_UPDATE,
|
||||
} from 'soapbox/actions/streaming';
|
||||
import {
|
||||
ADMIN_USERS_FETCH_SUCCESS,
|
||||
ADMIN_USERS_TAG_REQUEST,
|
||||
|
@ -26,48 +99,165 @@ import {
|
|||
ADMIN_REMOVE_PERMISSION_GROUP_REQUEST,
|
||||
ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS,
|
||||
ADMIN_REMOVE_PERMISSION_GROUP_FAIL,
|
||||
} from 'soapbox/actions/admin';
|
||||
import {
|
||||
ADMIN_USERS_DELETE_REQUEST,
|
||||
ADMIN_USERS_DELETE_FAIL,
|
||||
ADMIN_USERS_DEACTIVATE_REQUEST,
|
||||
ADMIN_USERS_DEACTIVATE_FAIL,
|
||||
ADMIN_REPORTS_FETCH_SUCCESS,
|
||||
} from 'soapbox/actions/admin';
|
||||
import {
|
||||
Map as ImmutableMap,
|
||||
List as ImmutableList,
|
||||
fromJS,
|
||||
} from 'immutable';
|
||||
import { normalizePleromaUserFields } from 'soapbox/utils/pleroma';
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import emojify from 'soapbox/features/emoji/emoji';
|
||||
import { unescapeHTML } from 'soapbox/utils/html';
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {
|
||||
obj[`:${emoji.shortcode}:`] = emoji;
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
const normalizePleroma = account => {
|
||||
if (!account.pleroma) return account;
|
||||
account.pleroma = normalizePleromaUserFields(account.pleroma);
|
||||
delete account.pleroma.chat_token;
|
||||
if (account.pleroma) {
|
||||
account.pleroma = normalizePleromaUserFields(account.pleroma);
|
||||
delete account.pleroma.chat_token;
|
||||
}
|
||||
return account;
|
||||
};
|
||||
|
||||
const normalizeAccount = (state, account) => {
|
||||
const normalized = fromJS(normalizePleroma(account)).deleteAll([
|
||||
'followers_count',
|
||||
'following_count',
|
||||
'statuses_count',
|
||||
]);
|
||||
const normalizeAccount = account => {
|
||||
account = { ...account };
|
||||
|
||||
return state.set(account.id, normalized);
|
||||
if (!account.id) {
|
||||
throw 'missing ID property';
|
||||
}
|
||||
|
||||
const emojiMap = makeEmojiMap(account);
|
||||
const displayName = account.display_name.trim().length === 0 ? account.username : account.display_name;
|
||||
|
||||
account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap);
|
||||
account.note_emojified = emojify(account.note, emojiMap);
|
||||
|
||||
if (account.fields) {
|
||||
account.fields = account.fields.map(pair => ({
|
||||
...pair,
|
||||
name_emojified: emojify(escapeTextContentForBrowser(pair.name)),
|
||||
value_emojified: emojify(pair.value, emojiMap),
|
||||
value_plain: unescapeHTML(pair.value),
|
||||
}));
|
||||
}
|
||||
|
||||
if (account.moved) {
|
||||
account.moved = account.moved.id;
|
||||
}
|
||||
|
||||
account = normalizePleroma(account);
|
||||
|
||||
return fromJS(account);
|
||||
};
|
||||
|
||||
const normalizeAccounts = (state, accounts) => {
|
||||
accounts.forEach(account => {
|
||||
state = normalizeAccount(state, account);
|
||||
const importAccount = (state, account) => {
|
||||
return state.withMutations(state => {
|
||||
if (account.moved) {
|
||||
importAccount(state, account.moved);
|
||||
}
|
||||
|
||||
try {
|
||||
state.set(account.id, normalizeAccount(account));
|
||||
} catch(e) {
|
||||
// Skip broken accounts
|
||||
console.warn(`Skipped broken account returned from the API: ${e}`);
|
||||
console.warn(account);
|
||||
}
|
||||
});
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
const importAccountFromChat = (state, chat) =>
|
||||
// TODO: Fix this monstrosity
|
||||
normalizeAccount(state, normalizeAccount2(chat.account));
|
||||
const importAccounts = (state, accounts) => {
|
||||
return state.withMutations(state => {
|
||||
accounts.forEach(account => {
|
||||
importAccount(state, account);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const importAccountsFromChats = (state, chats) =>
|
||||
state.withMutations(mutable =>
|
||||
chats.forEach(chat => importAccountFromChat(mutable, chat)));
|
||||
const importStatus = (state, status) => {
|
||||
return state.withMutations(state => {
|
||||
importAccount(state, status.account);
|
||||
|
||||
if (status.reblog && status.reblog.account) {
|
||||
importAccount(state, status.reblog.account);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const importStatuses = (state, statuses) => {
|
||||
return state.withMutations(state => {
|
||||
statuses.forEach(status => importStatus(state, status));
|
||||
});
|
||||
};
|
||||
|
||||
const importContext = (state, ancestors, descendants) => {
|
||||
return state.withMutations(state => {
|
||||
importStatuses(state, ancestors);
|
||||
importStatuses(state, descendants);
|
||||
});
|
||||
};
|
||||
|
||||
const importNotification = (state, notification) => (
|
||||
importAccount(state, notification.account)
|
||||
);
|
||||
|
||||
const importNotifications = (state, notifications) => {
|
||||
return state.withMutations(state => {
|
||||
notifications.forEach(notification => importNotification(state, notification));
|
||||
});
|
||||
};
|
||||
|
||||
const importConversation = (state, conversation) => (
|
||||
importAccounts(conversation.accounts)
|
||||
);
|
||||
|
||||
const importConversations = (state, conversations) => {
|
||||
return state.withMutations(state => {
|
||||
conversations.forEach(conversation => importConversation(state, conversation));
|
||||
});
|
||||
};
|
||||
|
||||
const importChat = (state, chat) => importAccount(state, chat.account);
|
||||
|
||||
const importChats = (state, chats) => {
|
||||
return state.withMutations(state => {
|
||||
chats.forEach(chat => importChat(state, chat));
|
||||
});
|
||||
};
|
||||
|
||||
const importEmojiReact = (state, emojiReact) => (
|
||||
importAccounts(emojiReact.accounts)
|
||||
);
|
||||
|
||||
const importEmojiReacts = (state, emojiReacts) => {
|
||||
return state.withMutations(state => {
|
||||
emojiReacts.forEach(emojiReact => importEmojiReact(state, emojiReact));
|
||||
});
|
||||
};
|
||||
|
||||
const importReport = (state, report) => {
|
||||
return state.withMutations(state => {
|
||||
importAccount(report.account);
|
||||
importAccount(report.actor);
|
||||
});
|
||||
};
|
||||
|
||||
const importAdminReports = (state, reports) => {
|
||||
return state.withMutations(state => {
|
||||
reports.forEach(report => importReport(state, report));
|
||||
});
|
||||
};
|
||||
|
||||
const addTags = (state, accountIds, tags) => {
|
||||
return state.withMutations(state => {
|
||||
|
@ -188,19 +378,72 @@ const importAdminUsers = (state, adminUsers) => {
|
|||
|
||||
export default function accounts(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case ACCOUNT_IMPORT:
|
||||
return normalizeAccount(state, action.account);
|
||||
case ACCOUNTS_IMPORT:
|
||||
return normalizeAccounts(state, action.accounts);
|
||||
case ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP:
|
||||
return state.set(-1, ImmutableMap({
|
||||
username: action.username,
|
||||
}));
|
||||
case ACCOUNT_FETCH_SUCCESS:
|
||||
case VERIFY_CREDENTIALS_SUCCESS:
|
||||
return importAccount(state, action.account);
|
||||
case ME_FETCH_SUCCESS:
|
||||
case ME_PATCH_SUCCESS:
|
||||
return importAccount(state, action.me);
|
||||
case FOLLOWERS_FETCH_SUCCESS:
|
||||
case FOLLOWERS_EXPAND_SUCCESS:
|
||||
case FOLLOWING_FETCH_SUCCESS:
|
||||
case FOLLOWING_EXPAND_SUCCESS:
|
||||
case REBLOGS_FETCH_SUCCESS:
|
||||
case FAVOURITES_FETCH_SUCCESS:
|
||||
case COMPOSE_SUGGESTIONS_READY:
|
||||
case FOLLOW_REQUESTS_FETCH_SUCCESS:
|
||||
case FOLLOW_REQUESTS_EXPAND_SUCCESS:
|
||||
case BLOCKS_FETCH_SUCCESS:
|
||||
case BLOCKS_EXPAND_SUCCESS:
|
||||
case MUTES_FETCH_SUCCESS:
|
||||
case MUTES_EXPAND_SUCCESS:
|
||||
case LIST_ACCOUNTS_FETCH_SUCCESS:
|
||||
case LIST_EDITOR_SUGGESTIONS_READY:
|
||||
case SUGGESTIONS_FETCH_SUCCESS:
|
||||
case GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS:
|
||||
case GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS:
|
||||
case GROUP_MEMBERS_FETCH_SUCCESS:
|
||||
case GROUP_MEMBERS_EXPAND_SUCCESS:
|
||||
return action.accounts ? importAccounts(state, action.accounts) : state;
|
||||
case CONVERSATIONS_FETCH_SUCCESS:
|
||||
return importConversations(state, action.conversations);
|
||||
case CONVERSATIONS_UPDATE:
|
||||
return importConversation(state, action.conversation);
|
||||
case NOTIFICATIONS_REFRESH_SUCCESS:
|
||||
case NOTIFICATIONS_EXPAND_SUCCESS:
|
||||
return importNotifications(state, action.notifications);
|
||||
case NOTIFICATIONS_UPDATE:
|
||||
case STREAMING_NOTIFICATION_UPDATE:
|
||||
return importNotification(state, action.notification);
|
||||
case SEARCH_FETCH_SUCCESS:
|
||||
return importAccounts(state, action.results.accounts);
|
||||
case TIMELINE_REFRESH_SUCCESS:
|
||||
case TIMELINE_EXPAND_SUCCESS:
|
||||
case FAVOURITED_STATUSES_FETCH_SUCCESS:
|
||||
case FAVOURITED_STATUSES_EXPAND_SUCCESS:
|
||||
return importStatuses(state, action.statuses);
|
||||
case CONTEXT_FETCH_SUCCESS:
|
||||
return importContext(state, action.ancestors, action.descendants);
|
||||
case REBLOG_SUCCESS:
|
||||
case FAVOURITE_SUCCESS:
|
||||
case UNREBLOG_SUCCESS:
|
||||
case UNFAVOURITE_SUCCESS:
|
||||
case STREAMING_TIMELINE_UPDATE:
|
||||
case STATUS_FETCH_SUCCESS:
|
||||
case BOOKMARK_SUCCESS:
|
||||
case UNBOOKMARK_SUCCESS:
|
||||
return importStatus(state, action.status);
|
||||
case CHATS_FETCH_SUCCESS:
|
||||
return importAccountsFromChats(state, action.chats);
|
||||
return importChats(state, action.chats);
|
||||
case CHAT_FETCH_SUCCESS:
|
||||
case STREAMING_CHAT_UPDATE:
|
||||
return importAccountsFromChats(state, [action.chat]);
|
||||
return importChats(state, [action.chat]);
|
||||
case EMOJI_REACTS_FETCH_SUCCESS:
|
||||
return importEmojiReacts(state, action.emojiReacts);
|
||||
case ADMIN_USERS_TAG_REQUEST:
|
||||
case ADMIN_USERS_TAG_SUCCESS:
|
||||
case ADMIN_USERS_UNTAG_FAIL:
|
||||
|
@ -225,6 +468,8 @@ export default function accounts(state = initialState, action) {
|
|||
return setActive(state, action.accountIds, true);
|
||||
case ADMIN_USERS_FETCH_SUCCESS:
|
||||
return importAdminUsers(state, action.users);
|
||||
case ADMIN_REPORTS_FETCH_SUCCESS:
|
||||
return importAdminReports(state, action.reports);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
import {
|
||||
ACCOUNT_FOLLOW_SUCCESS,
|
||||
ACCOUNT_UNFOLLOW_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer';
|
||||
import { STREAMING_FOLLOW_RELATIONSHIPS_UPDATE } from 'soapbox/actions/streaming';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
|
||||
const normalizeAccount = (state, account) => state.set(account.id, fromJS({
|
||||
followers_count: account.followers_count,
|
||||
following_count: account.following_count,
|
||||
statuses_count: account.statuses_count,
|
||||
}));
|
||||
|
||||
const normalizeAccounts = (state, accounts) => {
|
||||
accounts.forEach(account => {
|
||||
state = normalizeAccount(state, account);
|
||||
});
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
const updateFollowCounters = (state, counterUpdates) => {
|
||||
return state.withMutations(state => {
|
||||
counterUpdates.forEach(counterUpdate => {
|
||||
state.update(counterUpdate.id, ImmutableMap(), counters => counters.merge({
|
||||
followers_count: counterUpdate.follower_count,
|
||||
following_count: counterUpdate.following_count,
|
||||
}));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
export default function accountsCounters(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case ACCOUNT_IMPORT:
|
||||
return normalizeAccount(state, action.account);
|
||||
case ACCOUNTS_IMPORT:
|
||||
return normalizeAccounts(state, action.accounts);
|
||||
case ACCOUNT_FOLLOW_SUCCESS:
|
||||
return action.alreadyFollowing ? state :
|
||||
state.updateIn([action.relationship.id, 'followers_count'], num => num + 1);
|
||||
case ACCOUNT_UNFOLLOW_SUCCESS:
|
||||
return state.updateIn([action.relationship.id, 'followers_count'], num => Math.max(0, num - 1));
|
||||
case STREAMING_FOLLOW_RELATIONSHIPS_UPDATE:
|
||||
return updateFollowCounters(state, [action.follower, action.following]);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
|
@ -4,7 +4,7 @@ import {
|
|||
} from '../actions/accounts';
|
||||
import { CONTEXT_FETCH_SUCCESS } from '../actions/statuses';
|
||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||
import { STATUS_IMPORT, STATUSES_IMPORT } from 'soapbox/actions/importer';
|
||||
import { STREAMING_TIMELINE_UPDATE } from 'soapbox/actions/streaming';
|
||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
|
@ -24,12 +24,6 @@ const importStatus = (state, { id, in_reply_to_id }) => {
|
|||
});
|
||||
};
|
||||
|
||||
const importStatuses = (state, statuses) => {
|
||||
return state.withMutations(state => {
|
||||
statuses.forEach(status => importStatus(state, status));
|
||||
});
|
||||
};
|
||||
|
||||
const insertTombstone = (state, ancestorId, descendantId) => {
|
||||
const tombstoneId = `${descendantId}-tombstone`;
|
||||
return state.withMutations(state => {
|
||||
|
@ -100,10 +94,8 @@ export default function replies(state = initialState, action) {
|
|||
return normalizeContext(state, action.id, action.ancestors, action.descendants);
|
||||
case TIMELINE_DELETE:
|
||||
return deleteStatuses(state, [action.id]);
|
||||
case STATUS_IMPORT:
|
||||
case STREAMING_TIMELINE_UPDATE:
|
||||
return importStatus(state, action.status);
|
||||
case STATUSES_IMPORT:
|
||||
return importStatuses(state, action.statuses);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import modal from './modal';
|
|||
import user_lists from './user_lists';
|
||||
import domain_lists from './domain_lists';
|
||||
import accounts from './accounts';
|
||||
import accounts_counters from './accounts_counters';
|
||||
import statuses from './statuses';
|
||||
import relationships from './relationships';
|
||||
import settings from './settings';
|
||||
|
@ -65,7 +64,6 @@ const appReducer = combineReducers({
|
|||
domain_lists,
|
||||
status_lists,
|
||||
accounts,
|
||||
accounts_counters,
|
||||
statuses,
|
||||
relationships,
|
||||
settings,
|
||||
|
|
|
@ -15,17 +15,12 @@ import {
|
|||
ACCOUNT_UNPIN_SUCCESS,
|
||||
RELATIONSHIPS_FETCH_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import {
|
||||
ACCOUNT_IMPORT,
|
||||
ACCOUNTS_IMPORT,
|
||||
} from '../actions/importer';
|
||||
import {
|
||||
DOMAIN_BLOCK_SUCCESS,
|
||||
DOMAIN_UNBLOCK_SUCCESS,
|
||||
} from '../actions/domain_blocks';
|
||||
import { STREAMING_FOLLOW_RELATIONSHIPS_UPDATE } from 'soapbox/actions/streaming';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
import { get } from 'lodash';
|
||||
|
||||
const normalizeRelationship = (state, relationship) => state.set(relationship.id, fromJS(relationship));
|
||||
|
||||
|
@ -45,21 +40,6 @@ const setDomainBlocking = (state, accounts, blocking) => {
|
|||
});
|
||||
};
|
||||
|
||||
const importPleromaAccount = (state, account) => {
|
||||
const relationship = get(account, ['pleroma', 'relationship'], {});
|
||||
if (relationship.id && relationship !== {})
|
||||
return normalizeRelationship(state, relationship);
|
||||
return state;
|
||||
};
|
||||
|
||||
const importPleromaAccounts = (state, accounts) => {
|
||||
accounts.forEach(account => {
|
||||
state = importPleromaAccount(state, account);
|
||||
});
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
const followStateToRelationship = followState => {
|
||||
switch(followState) {
|
||||
case 'follow_pending':
|
||||
|
@ -82,10 +62,6 @@ const initialState = ImmutableMap();
|
|||
|
||||
export default function relationships(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case ACCOUNT_IMPORT:
|
||||
return importPleromaAccount(state, action.account);
|
||||
case ACCOUNTS_IMPORT:
|
||||
return importPleromaAccounts(state, action.accounts);
|
||||
case ACCOUNT_FOLLOW_REQUEST:
|
||||
return state.setIn([action.id, 'requested'], true);
|
||||
case ACCOUNT_FOLLOW_FAIL:
|
||||
|
|
|
@ -4,12 +4,14 @@ import {
|
|||
SCHEDULED_STATUS_CANCEL_REQUEST,
|
||||
SCHEDULED_STATUS_CANCEL_SUCCESS,
|
||||
} from 'soapbox/actions/scheduled_statuses';
|
||||
import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
|
||||
const importStatus = (state, status) => {
|
||||
if (!status.scheduled_at) return state;
|
||||
return state.set(status.id, fromJS(status));
|
||||
if (status.scheduled_at) {
|
||||
return state.set(status.id, fromJS(status));
|
||||
} else {
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const importStatuses = (state, statuses) =>
|
||||
|
@ -21,10 +23,8 @@ const initialState = ImmutableMap();
|
|||
|
||||
export default function statuses(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case STATUS_IMPORT:
|
||||
case STATUS_CREATE_SUCCESS:
|
||||
return importStatus(state, action.status);
|
||||
case STATUSES_IMPORT:
|
||||
case SCHEDULED_STATUSES_FETCH_SUCCESS:
|
||||
return importStatuses(state, action.statuses);
|
||||
case SCHEDULED_STATUS_CANCEL_REQUEST:
|
||||
|
|
|
@ -1,45 +1,141 @@
|
|||
import {
|
||||
REBLOG_REQUEST,
|
||||
REBLOG_SUCCESS,
|
||||
REBLOG_FAIL,
|
||||
UNREBLOG_SUCCESS,
|
||||
FAVOURITE_REQUEST,
|
||||
UNFAVOURITE_REQUEST,
|
||||
FAVOURITE_SUCCESS,
|
||||
FAVOURITE_FAIL,
|
||||
} from '../actions/interactions';
|
||||
UNFAVOURITE_REQUEST,
|
||||
UNFAVOURITE_SUCCESS,
|
||||
PIN_SUCCESS,
|
||||
UNPIN_SUCCESS,
|
||||
} from 'soapbox/actions/interactions';
|
||||
import {
|
||||
STATUS_FETCH_SUCCESS,
|
||||
CONTEXT_FETCH_SUCCESS,
|
||||
STATUS_MUTE_SUCCESS,
|
||||
STATUS_UNMUTE_SUCCESS,
|
||||
STATUS_REVEAL,
|
||||
STATUS_HIDE,
|
||||
} from '../actions/statuses';
|
||||
} from 'soapbox/actions/statuses';
|
||||
import {
|
||||
EMOJI_REACT_REQUEST,
|
||||
UNEMOJI_REACT_REQUEST,
|
||||
} from '../actions/emoji_reacts';
|
||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||
import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer';
|
||||
} from 'soapbox/actions/emoji_reacts';
|
||||
import {
|
||||
TIMELINE_REFRESH_SUCCESS,
|
||||
TIMELINE_DELETE,
|
||||
TIMELINE_EXPAND_SUCCESS,
|
||||
} from 'soapbox/actions/timelines';
|
||||
import {
|
||||
NOTIFICATIONS_UPDATE,
|
||||
NOTIFICATIONS_REFRESH_SUCCESS,
|
||||
NOTIFICATIONS_EXPAND_SUCCESS,
|
||||
} from 'soapbox/actions/notifications';
|
||||
import {
|
||||
STREAMING_TIMELINE_UPDATE,
|
||||
} from 'soapbox/actions/streaming';
|
||||
import {
|
||||
FAVOURITED_STATUSES_FETCH_SUCCESS,
|
||||
FAVOURITED_STATUSES_EXPAND_SUCCESS,
|
||||
} from 'soapbox/actions/favourites';
|
||||
import {
|
||||
PINNED_STATUSES_FETCH_SUCCESS,
|
||||
} from 'soapbox/actions/pin_statuses';
|
||||
import { SEARCH_FETCH_SUCCESS } from '../actions/search';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
import { simulateEmojiReact, simulateUnEmojiReact } from 'soapbox/utils/emoji_reacts';
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import emojify from 'soapbox/features/emoji/emoji';
|
||||
|
||||
const importStatus = (state, status) => state.set(status.id, fromJS(status));
|
||||
const domParser = new DOMParser();
|
||||
|
||||
const importStatuses = (state, statuses) =>
|
||||
state.withMutations(mutable => statuses.forEach(status => importStatus(mutable, status)));
|
||||
const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {
|
||||
obj[`:${emoji.shortcode}:`] = emoji;
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
export function normalizeStatus(status, normalOldStatus, expandSpoilers) {
|
||||
const normalStatus = { ...status };
|
||||
|
||||
normalStatus.account = status.account.id;
|
||||
|
||||
if (status.reblog && status.reblog.id) {
|
||||
normalStatus.reblog = status.reblog.id;
|
||||
}
|
||||
|
||||
if (status.poll && status.poll.id) {
|
||||
normalStatus.poll = status.poll.id;
|
||||
}
|
||||
|
||||
// Only calculate these values when status first encountered
|
||||
// Otherwise keep the ones already in the reducer
|
||||
if (normalOldStatus) {
|
||||
normalStatus.search_index = normalOldStatus.get('search_index');
|
||||
normalStatus.contentHtml = normalOldStatus.get('contentHtml');
|
||||
normalStatus.spoilerHtml = normalOldStatus.get('spoilerHtml');
|
||||
normalStatus.hidden = normalOldStatus.get('hidden');
|
||||
} else {
|
||||
const spoilerText = normalStatus.spoiler_text || '';
|
||||
const searchContent = [spoilerText, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
|
||||
const emojiMap = makeEmojiMap(normalStatus);
|
||||
|
||||
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
|
||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
||||
normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
|
||||
}
|
||||
|
||||
return fromJS(normalStatus);
|
||||
}
|
||||
|
||||
const importStatus = (state, status) => {
|
||||
try {
|
||||
return state.set(status.id, normalizeStatus(status));
|
||||
} catch(e) {
|
||||
// Skip broken statuses
|
||||
console.warn(`Skipped broken status returned from the API: ${e}`);
|
||||
console.warn(status);
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const importStatuses = (state, statuses) => {
|
||||
return state.withMutations(state => {
|
||||
statuses.forEach(status => importStatus(state, status));
|
||||
});
|
||||
};
|
||||
|
||||
const deleteStatus = (state, id, references) => {
|
||||
references.forEach(ref => {
|
||||
state = deleteStatus(state, ref[0], []);
|
||||
return state.withMutations(state => {
|
||||
references.forEach(ref => deleteStatus(state, ref[0], []));
|
||||
});
|
||||
|
||||
return state.delete(id);
|
||||
};
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
export default function statuses(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case STATUS_IMPORT:
|
||||
case STREAMING_TIMELINE_UPDATE:
|
||||
case STATUS_FETCH_SUCCESS:
|
||||
case NOTIFICATIONS_UPDATE:
|
||||
case REBLOG_SUCCESS:
|
||||
case UNREBLOG_SUCCESS:
|
||||
case FAVOURITE_SUCCESS:
|
||||
case UNFAVOURITE_SUCCESS:
|
||||
case PIN_SUCCESS:
|
||||
case UNPIN_SUCCESS:
|
||||
return importStatus(state, action.status);
|
||||
case STATUSES_IMPORT:
|
||||
case TIMELINE_REFRESH_SUCCESS:
|
||||
case TIMELINE_EXPAND_SUCCESS:
|
||||
case CONTEXT_FETCH_SUCCESS:
|
||||
case NOTIFICATIONS_REFRESH_SUCCESS:
|
||||
case NOTIFICATIONS_EXPAND_SUCCESS:
|
||||
case FAVOURITED_STATUSES_FETCH_SUCCESS:
|
||||
case FAVOURITED_STATUSES_EXPAND_SUCCESS:
|
||||
case PINNED_STATUSES_FETCH_SUCCESS:
|
||||
case SEARCH_FETCH_SUCCESS:
|
||||
return importStatuses(state, action.statuses);
|
||||
case FAVOURITE_REQUEST:
|
||||
return state.update(action.status.get('id'), status =>
|
||||
|
|
|
@ -2,7 +2,6 @@ import { createSelector } from 'reselect';
|
|||
import { List as ImmutableList } from 'immutable';
|
||||
|
||||
const getAccountBase = (state, id) => state.getIn(['accounts', id], null);
|
||||
const getAccountCounters = (state, id) => state.getIn(['accounts_counters', id], null);
|
||||
const getAccountRelationship = (state, id) => state.getIn(['relationships', id], null);
|
||||
const getAccountMoved = (state, id) => state.getIn(['accounts', state.getIn(['accounts', id, 'moved'])]);
|
||||
const getAccountAdminData = (state, id) => state.getIn(['admin', 'users', id]);
|
||||
|
@ -14,17 +13,16 @@ const getAccountPatron = (state, id) => {
|
|||
export const makeGetAccount = () => {
|
||||
return createSelector([
|
||||
getAccountBase,
|
||||
getAccountCounters,
|
||||
getAccountRelationship,
|
||||
getAccountMoved,
|
||||
getAccountAdminData,
|
||||
getAccountPatron,
|
||||
], (base, counters, relationship, moved, admin, patron) => {
|
||||
], (base, relationship, moved, admin, patron) => {
|
||||
if (base === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return base.merge(counters).withMutations(map => {
|
||||
return base.withMutations(map => {
|
||||
map.set('relationship', relationship);
|
||||
map.set('moved', moved);
|
||||
map.set('patron', patron);
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
// import { freeStorage, storageFreeable } from '../storage/modifier';
|
||||
import './web_push_notifications';
|
||||
|
||||
// function openSystemCache() {
|
||||
// return caches.open('soapbox-system');
|
||||
// }
|
||||
|
||||
function openWebCache() {
|
||||
return caches.open('soapbox-web');
|
||||
}
|
||||
|
@ -13,9 +8,6 @@ function fetchRoot() {
|
|||
return fetch('/', { credentials: 'include', redirect: 'manual' });
|
||||
}
|
||||
|
||||
// const firefox = navigator.userAgent.match(/Firefox\/(\d+)/);
|
||||
// const invalidOnlyIfCached = firefox && firefox[1] < 60;
|
||||
|
||||
// Cause a new version of a registered Service Worker to replace an existing one
|
||||
// that is already installed, and replace the currently active worker on open pages.
|
||||
self.addEventListener('install', function(event) {
|
||||
|
@ -81,26 +73,5 @@ self.addEventListener('fetch', function(event) {
|
|||
return response;
|
||||
},
|
||||
() => asyncCache.then(cache => cache.match('/'))));
|
||||
} /* else if (storageFreeable && (ATTACHMENT_HOST ? url.host === ATTACHMENT_HOST : url.pathname.startsWith('/system/'))) {
|
||||
event.respondWith(openSystemCache().then(cache => {
|
||||
return cache.match(event.request.url).then(cached => {
|
||||
if (cached === undefined) {
|
||||
const asyncResponse = invalidOnlyIfCached && event.request.cache === 'only-if-cached' ?
|
||||
fetch(event.request, { cache: 'no-cache' }) : fetch(event.request);
|
||||
|
||||
return asyncResponse.then(response => {
|
||||
if (response.ok) {
|
||||
cache
|
||||
.put(event.request.url, response.clone())
|
||||
.catch(()=>{}).then(freeStorage()).catch();
|
||||
}
|
||||
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
return cached;
|
||||
});
|
||||
}));
|
||||
} */
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
export default () => new Promise((resolve, reject) => {
|
||||
// ServiceWorker is required to synchronize the login state.
|
||||
// Microsoft Edge 17 does not support getAll according to:
|
||||
// Catalog of standard and vendor APIs across browsers - Microsoft Edge Development
|
||||
// https://developer.microsoft.com/en-us/microsoft-edge/platform/catalog/?q=specName%3Aindexeddb
|
||||
if (!('caches' in self && 'getAll' in IDBObjectStore.prototype)) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
||||
const request = indexedDB.open('soapbox');
|
||||
|
||||
request.onerror = reject;
|
||||
request.onsuccess = ({ target }) => resolve(target.result);
|
||||
|
||||
request.onupgradeneeded = ({ target }) => {
|
||||
const accounts = target.result.createObjectStore('accounts', { autoIncrement: true });
|
||||
const statuses = target.result.createObjectStore('statuses', { autoIncrement: true });
|
||||
|
||||
accounts.createIndex('id', 'id', { unique: true });
|
||||
accounts.createIndex('moved', 'moved');
|
||||
|
||||
statuses.createIndex('id', 'id', { unique: true });
|
||||
statuses.createIndex('account', 'account');
|
||||
statuses.createIndex('reblog', 'reblog');
|
||||
};
|
||||
});
|
|
@ -1,211 +0,0 @@
|
|||
import openDB from './db';
|
||||
|
||||
const accountAssetKeys = ['avatar', 'avatar_static', 'header', 'header_static'];
|
||||
const storageMargin = 8388608;
|
||||
const storeLimit = 1024;
|
||||
|
||||
// navigator.storage is not present on:
|
||||
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.100 Safari/537.36 Edge/16.16299
|
||||
// estimate method is not present on Chrome 57.0.2987.98 on Linux.
|
||||
export const storageFreeable = 'storage' in navigator && 'estimate' in navigator.storage;
|
||||
|
||||
function openCache() {
|
||||
// ServiceWorker and Cache API is not available on iOS 11
|
||||
// https://webkit.org/status/#specification-service-workers
|
||||
return self.caches ? caches.open('soapbox-system') : Promise.reject();
|
||||
}
|
||||
|
||||
function printErrorIfAvailable(error) {
|
||||
if (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
}
|
||||
|
||||
function put(name, objects, onupdate, oncreate) {
|
||||
return openDB().then(db => (new Promise((resolve, reject) => {
|
||||
const putTransaction = db.transaction(name, 'readwrite');
|
||||
const putStore = putTransaction.objectStore(name);
|
||||
const putIndex = putStore.index('id');
|
||||
|
||||
objects.forEach(object => {
|
||||
putIndex.getKey(object.id).onsuccess = retrieval => {
|
||||
function addObject() {
|
||||
putStore.add(object);
|
||||
}
|
||||
|
||||
function deleteObject() {
|
||||
putStore.delete(retrieval.target.result).onsuccess = addObject;
|
||||
}
|
||||
|
||||
if (retrieval.target.result) {
|
||||
if (onupdate) {
|
||||
onupdate(object, retrieval.target.result, putStore, deleteObject);
|
||||
} else {
|
||||
deleteObject();
|
||||
}
|
||||
} else {
|
||||
if (oncreate) {
|
||||
oncreate(object, addObject);
|
||||
} else {
|
||||
addObject();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
putTransaction.oncomplete = () => {
|
||||
const readTransaction = db.transaction(name, 'readonly');
|
||||
const readStore = readTransaction.objectStore(name);
|
||||
const count = readStore.count();
|
||||
|
||||
count.onsuccess = () => {
|
||||
const excess = count.result - storeLimit;
|
||||
|
||||
if (excess > 0) {
|
||||
const retrieval = readStore.getAll(null, excess);
|
||||
|
||||
retrieval.onsuccess = () => resolve(retrieval.result);
|
||||
retrieval.onerror = reject;
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
};
|
||||
|
||||
count.onerror = reject;
|
||||
};
|
||||
|
||||
putTransaction.onerror = reject;
|
||||
})).then(resolved => {
|
||||
db.close();
|
||||
return resolved;
|
||||
}, error => {
|
||||
db.close();
|
||||
throw error;
|
||||
}));
|
||||
}
|
||||
|
||||
function evictAccountsByRecords(records) {
|
||||
return openDB().then(db => {
|
||||
const transaction = db.transaction(['accounts', 'statuses'], 'readwrite');
|
||||
const accounts = transaction.objectStore('accounts');
|
||||
const accountsIdIndex = accounts.index('id');
|
||||
const accountsMovedIndex = accounts.index('moved');
|
||||
const statuses = transaction.objectStore('statuses');
|
||||
const statusesIndex = statuses.index('account');
|
||||
|
||||
function evict(toEvict) {
|
||||
toEvict.forEach(record => {
|
||||
openCache()
|
||||
.then(cache => accountAssetKeys.forEach(key => cache.delete(records[key])))
|
||||
.catch(printErrorIfAvailable);
|
||||
|
||||
accountsMovedIndex.getAll(record.id).onsuccess = ({ target }) => evict(target.result);
|
||||
|
||||
statusesIndex.getAll(record.id).onsuccess =
|
||||
({ target }) => evictStatusesByRecords(target.result);
|
||||
|
||||
accountsIdIndex.getKey(record.id).onsuccess =
|
||||
({ target }) => target.result && accounts.delete(target.result);
|
||||
});
|
||||
}
|
||||
|
||||
evict(records);
|
||||
|
||||
db.close();
|
||||
}).catch(printErrorIfAvailable);
|
||||
}
|
||||
|
||||
export function evictStatus(id) {
|
||||
evictStatuses([id]);
|
||||
}
|
||||
|
||||
export function evictStatuses(ids) {
|
||||
return openDB().then(db => {
|
||||
const transaction = db.transaction('statuses', 'readwrite');
|
||||
const store = transaction.objectStore('statuses');
|
||||
const idIndex = store.index('id');
|
||||
const reblogIndex = store.index('reblog');
|
||||
|
||||
ids.forEach(id => {
|
||||
reblogIndex.getAllKeys(id).onsuccess =
|
||||
({ target }) => target.result.forEach(reblogKey => store.delete(reblogKey));
|
||||
|
||||
idIndex.getKey(id).onsuccess =
|
||||
({ target }) => target.result && store.delete(target.result);
|
||||
});
|
||||
|
||||
db.close();
|
||||
}).catch(printErrorIfAvailable);
|
||||
}
|
||||
|
||||
function evictStatusesByRecords(records) {
|
||||
return evictStatuses(records.map(({ id }) => id));
|
||||
}
|
||||
|
||||
export function putAccounts(records, avatarStatic) {
|
||||
const avatarKey = avatarStatic ? 'avatar_static' : 'avatar';
|
||||
const newURLs = [];
|
||||
|
||||
put('accounts', records, (newRecord, oldKey, store, oncomplete) => {
|
||||
store.get(oldKey).onsuccess = ({ target }) => {
|
||||
accountAssetKeys.forEach(key => {
|
||||
const newURL = newRecord[key];
|
||||
const oldURL = target.result[key];
|
||||
|
||||
if (newURL !== oldURL) {
|
||||
openCache()
|
||||
.then(cache => cache.delete(oldURL))
|
||||
.catch(printErrorIfAvailable);
|
||||
}
|
||||
});
|
||||
|
||||
const newURL = newRecord[avatarKey];
|
||||
const oldURL = target.result[avatarKey];
|
||||
|
||||
if (newURL !== oldURL) {
|
||||
newURLs.push(newURL);
|
||||
}
|
||||
|
||||
oncomplete();
|
||||
};
|
||||
}, (newRecord, oncomplete) => {
|
||||
newURLs.push(newRecord[avatarKey]);
|
||||
oncomplete();
|
||||
}).then(records => Promise.all([
|
||||
evictAccountsByRecords(records),
|
||||
openCache().then(cache => cache.addAll(newURLs)),
|
||||
])).then(freeStorage, error => {
|
||||
freeStorage();
|
||||
throw error;
|
||||
}).catch(printErrorIfAvailable);
|
||||
}
|
||||
|
||||
export function putStatuses(records) {
|
||||
put('statuses', records)
|
||||
.then(evictStatusesByRecords)
|
||||
.catch(printErrorIfAvailable);
|
||||
}
|
||||
|
||||
export function freeStorage() {
|
||||
return storageFreeable && navigator.storage.estimate().then(({ quota, usage }) => {
|
||||
if (usage + storageMargin < quota) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return openDB().then(db => new Promise((resolve, reject) => {
|
||||
const retrieval = db.transaction('accounts', 'readonly').objectStore('accounts').getAll(null, 1);
|
||||
|
||||
retrieval.onsuccess = () => {
|
||||
if (retrieval.result.length > 0) {
|
||||
resolve(evictAccountsByRecords(retrieval.result).then(freeStorage));
|
||||
} else {
|
||||
resolve(caches.delete('soapbox-system'));
|
||||
}
|
||||
};
|
||||
|
||||
retrieval.onerror = reject;
|
||||
|
||||
db.close();
|
||||
}));
|
||||
});
|
||||
}
|
|
@ -45,7 +45,7 @@ export const isModerator = account => (
|
|||
|
||||
export const getFollowDifference = (state, accountId, type) => {
|
||||
const listSize = state.getIn(['user_lists', type, accountId, 'items'], ImmutableList()).size;
|
||||
const counter = state.getIn(['accounts_counters', accountId, `${type}_count`], 0);
|
||||
const counter = state.getIn(['accounts', accountId, `${type}_count`], 0);
|
||||
return Math.max(counter - listSize, 0);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue