The code powering m.abunchtell.com https://m.abunchtell.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

694 lines
17 KiB

  1. import api, { getLinks } from '../api';
  2. import asyncDB from '../storage/db';
  3. import { importAccount, importFetchedAccount, importFetchedAccounts } from './importer';
  4. export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST';
  5. export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS';
  6. export const ACCOUNT_FETCH_FAIL = 'ACCOUNT_FETCH_FAIL';
  7. export const ACCOUNT_FOLLOW_REQUEST = 'ACCOUNT_FOLLOW_REQUEST';
  8. export const ACCOUNT_FOLLOW_SUCCESS = 'ACCOUNT_FOLLOW_SUCCESS';
  9. export const ACCOUNT_FOLLOW_FAIL = 'ACCOUNT_FOLLOW_FAIL';
  10. export const ACCOUNT_UNFOLLOW_REQUEST = 'ACCOUNT_UNFOLLOW_REQUEST';
  11. export const ACCOUNT_UNFOLLOW_SUCCESS = 'ACCOUNT_UNFOLLOW_SUCCESS';
  12. export const ACCOUNT_UNFOLLOW_FAIL = 'ACCOUNT_UNFOLLOW_FAIL';
  13. export const ACCOUNT_BLOCK_REQUEST = 'ACCOUNT_BLOCK_REQUEST';
  14. export const ACCOUNT_BLOCK_SUCCESS = 'ACCOUNT_BLOCK_SUCCESS';
  15. export const ACCOUNT_BLOCK_FAIL = 'ACCOUNT_BLOCK_FAIL';
  16. export const ACCOUNT_UNBLOCK_REQUEST = 'ACCOUNT_UNBLOCK_REQUEST';
  17. export const ACCOUNT_UNBLOCK_SUCCESS = 'ACCOUNT_UNBLOCK_SUCCESS';
  18. export const ACCOUNT_UNBLOCK_FAIL = 'ACCOUNT_UNBLOCK_FAIL';
  19. export const ACCOUNT_MUTE_REQUEST = 'ACCOUNT_MUTE_REQUEST';
  20. export const ACCOUNT_MUTE_SUCCESS = 'ACCOUNT_MUTE_SUCCESS';
  21. export const ACCOUNT_MUTE_FAIL = 'ACCOUNT_MUTE_FAIL';
  22. export const ACCOUNT_UNMUTE_REQUEST = 'ACCOUNT_UNMUTE_REQUEST';
  23. export const ACCOUNT_UNMUTE_SUCCESS = 'ACCOUNT_UNMUTE_SUCCESS';
  24. export const ACCOUNT_UNMUTE_FAIL = 'ACCOUNT_UNMUTE_FAIL';
  25. export const FOLLOWERS_FETCH_REQUEST = 'FOLLOWERS_FETCH_REQUEST';
  26. export const FOLLOWERS_FETCH_SUCCESS = 'FOLLOWERS_FETCH_SUCCESS';
  27. export const FOLLOWERS_FETCH_FAIL = 'FOLLOWERS_FETCH_FAIL';
  28. export const FOLLOWERS_EXPAND_REQUEST = 'FOLLOWERS_EXPAND_REQUEST';
  29. export const FOLLOWERS_EXPAND_SUCCESS = 'FOLLOWERS_EXPAND_SUCCESS';
  30. export const FOLLOWERS_EXPAND_FAIL = 'FOLLOWERS_EXPAND_FAIL';
  31. export const FOLLOWING_FETCH_REQUEST = 'FOLLOWING_FETCH_REQUEST';
  32. export const FOLLOWING_FETCH_SUCCESS = 'FOLLOWING_FETCH_SUCCESS';
  33. export const FOLLOWING_FETCH_FAIL = 'FOLLOWING_FETCH_FAIL';
  34. export const FOLLOWING_EXPAND_REQUEST = 'FOLLOWING_EXPAND_REQUEST';
  35. export const FOLLOWING_EXPAND_SUCCESS = 'FOLLOWING_EXPAND_SUCCESS';
  36. export const FOLLOWING_EXPAND_FAIL = 'FOLLOWING_EXPAND_FAIL';
  37. export const RELATIONSHIPS_FETCH_REQUEST = 'RELATIONSHIPS_FETCH_REQUEST';
  38. export const RELATIONSHIPS_FETCH_SUCCESS = 'RELATIONSHIPS_FETCH_SUCCESS';
  39. export const RELATIONSHIPS_FETCH_FAIL = 'RELATIONSHIPS_FETCH_FAIL';
  40. export const FOLLOW_REQUESTS_FETCH_REQUEST = 'FOLLOW_REQUESTS_FETCH_REQUEST';
  41. export const FOLLOW_REQUESTS_FETCH_SUCCESS = 'FOLLOW_REQUESTS_FETCH_SUCCESS';
  42. export const FOLLOW_REQUESTS_FETCH_FAIL = 'FOLLOW_REQUESTS_FETCH_FAIL';
  43. export const FOLLOW_REQUESTS_EXPAND_REQUEST = 'FOLLOW_REQUESTS_EXPAND_REQUEST';
  44. export const FOLLOW_REQUESTS_EXPAND_SUCCESS = 'FOLLOW_REQUESTS_EXPAND_SUCCESS';
  45. export const FOLLOW_REQUESTS_EXPAND_FAIL = 'FOLLOW_REQUESTS_EXPAND_FAIL';
  46. export const FOLLOW_REQUEST_AUTHORIZE_REQUEST = 'FOLLOW_REQUEST_AUTHORIZE_REQUEST';
  47. export const FOLLOW_REQUEST_AUTHORIZE_SUCCESS = 'FOLLOW_REQUEST_AUTHORIZE_SUCCESS';
  48. export const FOLLOW_REQUEST_AUTHORIZE_FAIL = 'FOLLOW_REQUEST_AUTHORIZE_FAIL';
  49. export const FOLLOW_REQUEST_REJECT_REQUEST = 'FOLLOW_REQUEST_REJECT_REQUEST';
  50. export const FOLLOW_REQUEST_REJECT_SUCCESS = 'FOLLOW_REQUEST_REJECT_SUCCESS';
  51. export const FOLLOW_REQUEST_REJECT_FAIL = 'FOLLOW_REQUEST_REJECT_FAIL';
  52. function getFromDB(dispatch, getState, index, id) {
  53. return new Promise((resolve, reject) => {
  54. const request = index.get(id);
  55. request.onerror = reject;
  56. request.onsuccess = () => {
  57. if (!request.result) {
  58. reject();
  59. return;
  60. }
  61. dispatch(importAccount(request.result));
  62. resolve(request.result.moved && getFromDB(dispatch, getState, index, request.result.moved));
  63. };
  64. });
  65. }
  66. export function fetchAccount(id) {
  67. return (dispatch, getState) => {
  68. dispatch(fetchRelationships([id]));
  69. if (getState().getIn(['accounts', id], null) !== null) {
  70. return;
  71. }
  72. dispatch(fetchAccountRequest(id));
  73. asyncDB.then(db => getFromDB(
  74. dispatch,
  75. getState,
  76. db.transaction('accounts', 'read').objectStore('accounts').index('id'),
  77. id
  78. )).catch(() => api(getState).get(`/api/v1/accounts/${id}`).then(response => {
  79. dispatch(importFetchedAccount(response.data));
  80. })).then(() => {
  81. dispatch(fetchAccountSuccess());
  82. }).catch(error => {
  83. dispatch(fetchAccountFail(id, error));
  84. });
  85. };
  86. };
  87. export function fetchAccountRequest(id) {
  88. return {
  89. type: ACCOUNT_FETCH_REQUEST,
  90. id,
  91. };
  92. };
  93. export function fetchAccountSuccess() {
  94. return {
  95. type: ACCOUNT_FETCH_SUCCESS,
  96. };
  97. };
  98. export function fetchAccountFail(id, error) {
  99. return {
  100. type: ACCOUNT_FETCH_FAIL,
  101. id,
  102. error,
  103. skipAlert: true,
  104. };
  105. };
  106. export function followAccount(id, reblogs = true) {
  107. return (dispatch, getState) => {
  108. const alreadyFollowing = getState().getIn(['relationships', id, 'following']);
  109. dispatch(followAccountRequest(id));
  110. api(getState).post(`/api/v1/accounts/${id}/follow`, { reblogs }).then(response => {
  111. dispatch(followAccountSuccess(response.data, alreadyFollowing));
  112. }).catch(error => {
  113. dispatch(followAccountFail(error));
  114. });
  115. };
  116. };
  117. export function unfollowAccount(id) {
  118. return (dispatch, getState) => {
  119. dispatch(unfollowAccountRequest(id));
  120. api(getState).post(`/api/v1/accounts/${id}/unfollow`).then(response => {
  121. dispatch(unfollowAccountSuccess(response.data, getState().get('statuses')));
  122. }).catch(error => {
  123. dispatch(unfollowAccountFail(error));
  124. });
  125. };
  126. };
  127. export function followAccountRequest(id) {
  128. return {
  129. type: ACCOUNT_FOLLOW_REQUEST,
  130. id,
  131. };
  132. };
  133. export function followAccountSuccess(relationship, alreadyFollowing) {
  134. return {
  135. type: ACCOUNT_FOLLOW_SUCCESS,
  136. relationship,
  137. alreadyFollowing,
  138. };
  139. };
  140. export function followAccountFail(error) {
  141. return {
  142. type: ACCOUNT_FOLLOW_FAIL,
  143. error,
  144. };
  145. };
  146. export function unfollowAccountRequest(id) {
  147. return {
  148. type: ACCOUNT_UNFOLLOW_REQUEST,
  149. id,
  150. };
  151. };
  152. export function unfollowAccountSuccess(relationship, statuses) {
  153. return {
  154. type: ACCOUNT_UNFOLLOW_SUCCESS,
  155. relationship,
  156. statuses,
  157. };
  158. };
  159. export function unfollowAccountFail(error) {
  160. return {
  161. type: ACCOUNT_UNFOLLOW_FAIL,
  162. error,
  163. };
  164. };
  165. export function blockAccount(id) {
  166. return (dispatch, getState) => {
  167. dispatch(blockAccountRequest(id));
  168. api(getState).post(`/api/v1/accounts/${id}/block`).then(response => {
  169. // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
  170. dispatch(blockAccountSuccess(response.data, getState().get('statuses')));
  171. }).catch(error => {
  172. dispatch(blockAccountFail(id, error));
  173. });
  174. };
  175. };
  176. export function unblockAccount(id) {
  177. return (dispatch, getState) => {
  178. dispatch(unblockAccountRequest(id));
  179. api(getState).post(`/api/v1/accounts/${id}/unblock`).then(response => {
  180. dispatch(unblockAccountSuccess(response.data));
  181. }).catch(error => {
  182. dispatch(unblockAccountFail(id, error));
  183. });
  184. };
  185. };
  186. export function blockAccountRequest(id) {
  187. return {
  188. type: ACCOUNT_BLOCK_REQUEST,
  189. id,
  190. };
  191. };
  192. export function blockAccountSuccess(relationship, statuses) {
  193. return {
  194. type: ACCOUNT_BLOCK_SUCCESS,
  195. relationship,
  196. statuses,
  197. };
  198. };
  199. export function blockAccountFail(error) {
  200. return {
  201. type: ACCOUNT_BLOCK_FAIL,
  202. error,
  203. };
  204. };
  205. export function unblockAccountRequest(id) {
  206. return {
  207. type: ACCOUNT_UNBLOCK_REQUEST,
  208. id,
  209. };
  210. };
  211. export function unblockAccountSuccess(relationship) {
  212. return {
  213. type: ACCOUNT_UNBLOCK_SUCCESS,
  214. relationship,
  215. };
  216. };
  217. export function unblockAccountFail(error) {
  218. return {
  219. type: ACCOUNT_UNBLOCK_FAIL,
  220. error,
  221. };
  222. };
  223. export function muteAccount(id, notifications) {
  224. return (dispatch, getState) => {
  225. dispatch(muteAccountRequest(id));
  226. api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications }).then(response => {
  227. // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
  228. dispatch(muteAccountSuccess(response.data, getState().get('statuses')));
  229. }).catch(error => {
  230. dispatch(muteAccountFail(id, error));
  231. });
  232. };
  233. };
  234. export function unmuteAccount(id) {
  235. return (dispatch, getState) => {
  236. dispatch(unmuteAccountRequest(id));
  237. api(getState).post(`/api/v1/accounts/${id}/unmute`).then(response => {
  238. dispatch(unmuteAccountSuccess(response.data));
  239. }).catch(error => {
  240. dispatch(unmuteAccountFail(id, error));
  241. });
  242. };
  243. };
  244. export function muteAccountRequest(id) {
  245. return {
  246. type: ACCOUNT_MUTE_REQUEST,
  247. id,
  248. };
  249. };
  250. export function muteAccountSuccess(relationship, statuses) {
  251. return {
  252. type: ACCOUNT_MUTE_SUCCESS,
  253. relationship,
  254. statuses,
  255. };
  256. };
  257. export function muteAccountFail(error) {
  258. return {
  259. type: ACCOUNT_MUTE_FAIL,
  260. error,
  261. };
  262. };
  263. export function unmuteAccountRequest(id) {
  264. return {
  265. type: ACCOUNT_UNMUTE_REQUEST,
  266. id,
  267. };
  268. };
  269. export function unmuteAccountSuccess(relationship) {
  270. return {
  271. type: ACCOUNT_UNMUTE_SUCCESS,
  272. relationship,
  273. };
  274. };
  275. export function unmuteAccountFail(error) {
  276. return {
  277. type: ACCOUNT_UNMUTE_FAIL,
  278. error,
  279. };
  280. };
  281. export function fetchFollowers(id) {
  282. return (dispatch, getState) => {
  283. dispatch(fetchFollowersRequest(id));
  284. api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => {
  285. const next = getLinks(response).refs.find(link => link.rel === 'next');
  286. dispatch(importFetchedAccounts(response.data));
  287. dispatch(fetchFollowersSuccess(id, response.data, next ? next.uri : null));
  288. dispatch(fetchRelationships(response.data.map(item => item.id)));
  289. }).catch(error => {
  290. dispatch(fetchFollowersFail(id, error));
  291. });
  292. };
  293. };
  294. export function fetchFollowersRequest(id) {
  295. return {
  296. type: FOLLOWERS_FETCH_REQUEST,
  297. id,
  298. };
  299. };
  300. export function fetchFollowersSuccess(id, accounts, next) {
  301. return {
  302. type: FOLLOWERS_FETCH_SUCCESS,
  303. id,
  304. accounts,
  305. next,
  306. };
  307. };
  308. export function fetchFollowersFail(id, error) {
  309. return {
  310. type: FOLLOWERS_FETCH_FAIL,
  311. id,
  312. error,
  313. };
  314. };
  315. export function expandFollowers(id) {
  316. return (dispatch, getState) => {
  317. const url = getState().getIn(['user_lists', 'followers', id, 'next']);
  318. if (url === null) {
  319. return;
  320. }
  321. dispatch(expandFollowersRequest(id));
  322. api(getState).get(url).then(response => {
  323. const next = getLinks(response).refs.find(link => link.rel === 'next');
  324. dispatch(importFetchedAccounts(response.data));
  325. dispatch(expandFollowersSuccess(id, response.data, next ? next.uri : null));
  326. dispatch(fetchRelationships(response.data.map(item => item.id)));
  327. }).catch(error => {
  328. dispatch(expandFollowersFail(id, error));
  329. });
  330. };
  331. };
  332. export function expandFollowersRequest(id) {
  333. return {
  334. type: FOLLOWERS_EXPAND_REQUEST,
  335. id,
  336. };
  337. };
  338. export function expandFollowersSuccess(id, accounts, next) {
  339. return {
  340. type: FOLLOWERS_EXPAND_SUCCESS,
  341. id,
  342. accounts,
  343. next,
  344. };
  345. };
  346. export function expandFollowersFail(id, error) {
  347. return {
  348. type: FOLLOWERS_EXPAND_FAIL,
  349. id,
  350. error,
  351. };
  352. };
  353. export function fetchFollowing(id) {
  354. return (dispatch, getState) => {
  355. dispatch(fetchFollowingRequest(id));
  356. api(getState).get(`/api/v1/accounts/${id}/following`).then(response => {
  357. const next = getLinks(response).refs.find(link => link.rel === 'next');
  358. dispatch(importFetchedAccounts(response.data));
  359. dispatch(fetchFollowingSuccess(id, response.data, next ? next.uri : null));
  360. dispatch(fetchRelationships(response.data.map(item => item.id)));
  361. }).catch(error => {
  362. dispatch(fetchFollowingFail(id, error));
  363. });
  364. };
  365. };
  366. export function fetchFollowingRequest(id) {
  367. return {
  368. type: FOLLOWING_FETCH_REQUEST,
  369. id,
  370. };
  371. };
  372. export function fetchFollowingSuccess(id, accounts, next) {
  373. return {
  374. type: FOLLOWING_FETCH_SUCCESS,
  375. id,
  376. accounts,
  377. next,
  378. };
  379. };
  380. export function fetchFollowingFail(id, error) {
  381. return {
  382. type: FOLLOWING_FETCH_FAIL,
  383. id,
  384. error,
  385. };
  386. };
  387. export function expandFollowing(id) {
  388. return (dispatch, getState) => {
  389. const url = getState().getIn(['user_lists', 'following', id, 'next']);
  390. if (url === null) {
  391. return;
  392. }
  393. dispatch(expandFollowingRequest(id));
  394. api(getState).get(url).then(response => {
  395. const next = getLinks(response).refs.find(link => link.rel === 'next');
  396. dispatch(importFetchedAccounts(response.data));
  397. dispatch(expandFollowingSuccess(id, response.data, next ? next.uri : null));
  398. dispatch(fetchRelationships(response.data.map(item => item.id)));
  399. }).catch(error => {
  400. dispatch(expandFollowingFail(id, error));
  401. });
  402. };
  403. };
  404. export function expandFollowingRequest(id) {
  405. return {
  406. type: FOLLOWING_EXPAND_REQUEST,
  407. id,
  408. };
  409. };
  410. export function expandFollowingSuccess(id, accounts, next) {
  411. return {
  412. type: FOLLOWING_EXPAND_SUCCESS,
  413. id,
  414. accounts,
  415. next,
  416. };
  417. };
  418. export function expandFollowingFail(id, error) {
  419. return {
  420. type: FOLLOWING_EXPAND_FAIL,
  421. id,
  422. error,
  423. };
  424. };
  425. export function fetchRelationships(accountIds) {
  426. return (dispatch, getState) => {
  427. const loadedRelationships = getState().get('relationships');
  428. const newAccountIds = accountIds.filter(id => loadedRelationships.get(id, null) === null);
  429. if (newAccountIds.length === 0) {
  430. return;
  431. }
  432. dispatch(fetchRelationshipsRequest(newAccountIds));
  433. api(getState).get(`/api/v1/accounts/relationships?${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => {
  434. dispatch(fetchRelationshipsSuccess(response.data));
  435. }).catch(error => {
  436. dispatch(fetchRelationshipsFail(error));
  437. });
  438. };
  439. };
  440. export function fetchRelationshipsRequest(ids) {
  441. return {
  442. type: RELATIONSHIPS_FETCH_REQUEST,
  443. ids,
  444. skipLoading: true,
  445. };
  446. };
  447. export function fetchRelationshipsSuccess(relationships) {
  448. return {
  449. type: RELATIONSHIPS_FETCH_SUCCESS,
  450. relationships,
  451. skipLoading: true,
  452. };
  453. };
  454. export function fetchRelationshipsFail(error) {
  455. return {
  456. type: RELATIONSHIPS_FETCH_FAIL,
  457. error,
  458. skipLoading: true,
  459. };
  460. };
  461. export function fetchFollowRequests() {
  462. return (dispatch, getState) => {
  463. dispatch(fetchFollowRequestsRequest());
  464. api(getState).get('/api/v1/follow_requests').then(response => {
  465. const next = getLinks(response).refs.find(link => link.rel === 'next');
  466. dispatch(importFetchedAccounts(response.data));
  467. dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null));
  468. }).catch(error => dispatch(fetchFollowRequestsFail(error)));
  469. };
  470. };
  471. export function fetchFollowRequestsRequest() {
  472. return {
  473. type: FOLLOW_REQUESTS_FETCH_REQUEST,
  474. };
  475. };
  476. export function fetchFollowRequestsSuccess(accounts, next) {
  477. return {
  478. type: FOLLOW_REQUESTS_FETCH_SUCCESS,
  479. accounts,
  480. next,
  481. };
  482. };
  483. export function fetchFollowRequestsFail(error) {
  484. return {
  485. type: FOLLOW_REQUESTS_FETCH_FAIL,
  486. error,
  487. };
  488. };
  489. export function expandFollowRequests() {
  490. return (dispatch, getState) => {
  491. const url = getState().getIn(['user_lists', 'follow_requests', 'next']);
  492. if (url === null) {
  493. return;
  494. }
  495. dispatch(expandFollowRequestsRequest());
  496. api(getState).get(url).then(response => {
  497. const next = getLinks(response).refs.find(link => link.rel === 'next');
  498. dispatch(importFetchedAccounts(response.data));
  499. dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null));
  500. }).catch(error => dispatch(expandFollowRequestsFail(error)));
  501. };
  502. };
  503. export function expandFollowRequestsRequest() {
  504. return {
  505. type: FOLLOW_REQUESTS_EXPAND_REQUEST,
  506. };
  507. };
  508. export function expandFollowRequestsSuccess(accounts, next) {
  509. return {
  510. type: FOLLOW_REQUESTS_EXPAND_SUCCESS,
  511. accounts,
  512. next,
  513. };
  514. };
  515. export function expandFollowRequestsFail(error) {
  516. return {
  517. type: FOLLOW_REQUESTS_EXPAND_FAIL,
  518. error,
  519. };
  520. };
  521. export function authorizeFollowRequest(id) {
  522. return (dispatch, getState) => {
  523. dispatch(authorizeFollowRequestRequest(id));
  524. api(getState)
  525. .post(`/api/v1/follow_requests/${id}/authorize`)
  526. .then(() => dispatch(authorizeFollowRequestSuccess(id)))
  527. .catch(error => dispatch(authorizeFollowRequestFail(id, error)));
  528. };
  529. };
  530. export function authorizeFollowRequestRequest(id) {
  531. return {
  532. type: FOLLOW_REQUEST_AUTHORIZE_REQUEST,
  533. id,
  534. };
  535. };
  536. export function authorizeFollowRequestSuccess(id) {
  537. return {
  538. type: FOLLOW_REQUEST_AUTHORIZE_SUCCESS,
  539. id,
  540. };
  541. };
  542. export function authorizeFollowRequestFail(id, error) {
  543. return {
  544. type: FOLLOW_REQUEST_AUTHORIZE_FAIL,
  545. id,
  546. error,
  547. };
  548. };
  549. export function rejectFollowRequest(id) {
  550. return (dispatch, getState) => {
  551. dispatch(rejectFollowRequestRequest(id));
  552. api(getState)
  553. .post(`/api/v1/follow_requests/${id}/reject`)
  554. .then(() => dispatch(rejectFollowRequestSuccess(id)))
  555. .catch(error => dispatch(rejectFollowRequestFail(id, error)));
  556. };
  557. };
  558. export function rejectFollowRequestRequest(id) {
  559. return {
  560. type: FOLLOW_REQUEST_REJECT_REQUEST,
  561. id,
  562. };
  563. };
  564. export function rejectFollowRequestSuccess(id) {
  565. return {
  566. type: FOLLOW_REQUEST_REJECT_SUCCESS,
  567. id,
  568. };
  569. };
  570. export function rejectFollowRequestFail(id, error) {
  571. return {
  572. type: FOLLOW_REQUEST_REJECT_FAIL,
  573. id,
  574. error,
  575. };
  576. };