Merge remote-tracking branch 'origin/develop' into sw-skipwaiting
This commit is contained in:
commit
638fc35f77
|
@ -258,6 +258,7 @@ module.exports = {
|
||||||
alphabetize: { order: 'asc' },
|
alphabetize: { order: 'asc' },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
'@typescript-eslint/no-duplicate-imports': 'error',
|
||||||
|
|
||||||
'promise/catch-or-return': 'error',
|
'promise/catch-or-return': 'error',
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
/deploy.sh
|
/deploy.sh
|
||||||
/.vs/
|
/.vs/
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
/junit.xml
|
||||||
|
|
||||||
/static/
|
/static/
|
||||||
/static-test/
|
/static-test/
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
image: node:16
|
image: node:18
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
NODE_ENV: test
|
NODE_ENV: test
|
||||||
|
|
||||||
cache:
|
cache: &cache
|
||||||
key:
|
key:
|
||||||
files:
|
files:
|
||||||
- yarn.lock
|
- yarn.lock
|
||||||
paths:
|
paths:
|
||||||
- node_modules/
|
- node_modules/
|
||||||
|
policy: pull
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- deps
|
- deps
|
||||||
|
@ -21,6 +22,17 @@ deps:
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- yarn.lock
|
- yarn.lock
|
||||||
|
cache:
|
||||||
|
<<: *cache
|
||||||
|
policy: push
|
||||||
|
|
||||||
|
danger:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
# https://github.com/danger/danger-js/issues/1029#issuecomment-998915436
|
||||||
|
- export CI_MERGE_REQUEST_IID=${CI_OPEN_MERGE_REQUESTS#*!}
|
||||||
|
- npx danger ci
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
lint-js:
|
lint-js:
|
||||||
stage: test
|
stage: test
|
||||||
|
@ -56,7 +68,14 @@ jest:
|
||||||
- "jest.config.js"
|
- "jest.config.js"
|
||||||
- "package.json"
|
- "package.json"
|
||||||
- "yarn.lock"
|
- "yarn.lock"
|
||||||
|
- ".gitlab-ci.yml"
|
||||||
coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
|
coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
|
||||||
|
artifacts:
|
||||||
|
reports:
|
||||||
|
junit: junit.xml
|
||||||
|
coverage_report:
|
||||||
|
coverage_format: cobertura
|
||||||
|
path: .coverage/cobertura-coverage.xml
|
||||||
|
|
||||||
nginx-test:
|
nginx-test:
|
||||||
stage: test
|
stage: test
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
nodejs 16.14.2
|
nodejs 18.2.0
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { jest } from '@jest/globals';
|
import { jest } from '@jest/globals';
|
||||||
import { AxiosInstance, AxiosResponse } from 'axios';
|
|
||||||
import MockAdapter from 'axios-mock-adapter';
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
import LinkHeader from 'http-link-header';
|
import LinkHeader from 'http-link-header';
|
||||||
|
|
||||||
|
import type { AxiosInstance, AxiosResponse } from 'axios';
|
||||||
|
|
||||||
const api = jest.requireActual('../api') as Record<string, Function>;
|
const api = jest.requireActual('../api') as Record<string, Function>;
|
||||||
let mocks: Array<Function> = [];
|
let mocks: Array<Function> = [];
|
||||||
|
|
||||||
export const __stub = (func: Function) => mocks.push(func);
|
export const __stub = (func: (mock: MockAdapter) => void) => mocks.push(func);
|
||||||
export const __clear = (): Function[] => mocks = [];
|
export const __clear = (): Function[] => mocks = [];
|
||||||
|
|
||||||
const setupMock = (axios: AxiosInstance) => {
|
const setupMock = (axios: AxiosInstance) => {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
import { __stub } from 'soapbox/api';
|
import { __stub } from 'soapbox/api';
|
||||||
import { mockStore } from 'soapbox/jest/test-helpers';
|
import { mockStore } from 'soapbox/jest/test-helpers';
|
||||||
import rootReducer from 'soapbox/reducers';
|
import rootReducer from 'soapbox/reducers';
|
||||||
|
@ -10,7 +12,7 @@ describe('submitAccountNote()', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const state = rootReducer(undefined, {})
|
const state = rootReducer(undefined, {})
|
||||||
.set('account_notes', { edit: { account_id: 1, comment: 'hello' } });
|
.set('account_notes', { edit: { account: 1, comment: 'hello' } });
|
||||||
store = mockStore(state);
|
store = mockStore(state);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -62,7 +64,7 @@ describe('initAccountNoteModal()', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const state = rootReducer(undefined, {})
|
const state = rootReducer(undefined, {})
|
||||||
.set('relationships', { 1: { note: 'hello' } });
|
.set('relationships', ImmutableMap({ 1: { note: 'hello' } }));
|
||||||
store = mockStore(state);
|
store = mockStore(state);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,923 @@
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
|
import { __stub } from 'soapbox/api';
|
||||||
|
import { mockStore } from 'soapbox/jest/test-helpers';
|
||||||
|
import rootReducer from 'soapbox/reducers';
|
||||||
|
|
||||||
|
import { normalizeAccount } from '../../normalizers';
|
||||||
|
import {
|
||||||
|
blockAccount,
|
||||||
|
createAccount,
|
||||||
|
fetchAccount,
|
||||||
|
fetchAccountByUsername,
|
||||||
|
followAccount,
|
||||||
|
muteAccount,
|
||||||
|
subscribeAccount,
|
||||||
|
unblockAccount,
|
||||||
|
unfollowAccount,
|
||||||
|
unmuteAccount,
|
||||||
|
unsubscribeAccount,
|
||||||
|
} from '../accounts';
|
||||||
|
|
||||||
|
let store;
|
||||||
|
|
||||||
|
describe('createAccount()', () => {
|
||||||
|
const params = {
|
||||||
|
email: 'foo@bar.com',
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {});
|
||||||
|
store = mockStore(state);
|
||||||
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost('/api/v1/accounts').reply(200, { token: '123 ' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispatches the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_CREATE_REQUEST', params },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_CREATE_SUCCESS',
|
||||||
|
params,
|
||||||
|
token: { token: '123 ' },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(createAccount(params));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fetchAccount()', () => {
|
||||||
|
const id = '123';
|
||||||
|
|
||||||
|
describe('when the account has "should_refetch" set to false', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const account = normalizeAccount({
|
||||||
|
id,
|
||||||
|
acct: 'justin-username',
|
||||||
|
display_name: 'Justin L',
|
||||||
|
avatar: 'test.jpg',
|
||||||
|
});
|
||||||
|
|
||||||
|
const state = rootReducer(undefined, {})
|
||||||
|
.set('accounts', ImmutableMap({
|
||||||
|
[id]: account,
|
||||||
|
}));
|
||||||
|
|
||||||
|
store = mockStore(state);
|
||||||
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/accounts/${id}`).reply(200, account);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(fetchAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
const account = require('soapbox/__fixtures__/pleroma-account.json');
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {});
|
||||||
|
store = mockStore(state);
|
||||||
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/accounts/${id}`).reply(200, account);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_FETCH_REQUEST', id: '123' },
|
||||||
|
{ type: 'ACCOUNTS_IMPORT', accounts: [account] },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_FETCH_SUCCESS',
|
||||||
|
account,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
await store.dispatch(fetchAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {});
|
||||||
|
store = mockStore(state);
|
||||||
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/accounts/${id}`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_FETCH_REQUEST', id: '123' },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_FETCH_FAIL',
|
||||||
|
id,
|
||||||
|
error: new Error('Network Error'),
|
||||||
|
skipAlert: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
await store.dispatch(fetchAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fetchAccountByUsername()', () => {
|
||||||
|
const id = '123';
|
||||||
|
const username = 'tiger';
|
||||||
|
let state, account;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
account = normalizeAccount({
|
||||||
|
id,
|
||||||
|
acct: username,
|
||||||
|
display_name: 'Tiger',
|
||||||
|
avatar: 'test.jpg',
|
||||||
|
birthday: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
state = rootReducer(undefined, {})
|
||||||
|
.set('accounts', ImmutableMap({
|
||||||
|
[id]: account,
|
||||||
|
}));
|
||||||
|
|
||||||
|
store = mockStore(state);
|
||||||
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/accounts/${id}`).reply(200, account);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when "accountByUsername" feature is enabled', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {})
|
||||||
|
.set('instance', {
|
||||||
|
version: '2.7.2 (compatible; Pleroma 2.4.52-1337-g4779199e.gleasonator+soapbox)',
|
||||||
|
pleroma: ImmutableMap({
|
||||||
|
metadata: ImmutableMap({
|
||||||
|
features: [],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/accounts/${username}`).reply(200, account);
|
||||||
|
mock.onGet(`/api/v1/accounts/relationships?${[account.id].map(id => `id[]=${id}`).join('&')}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return dispatch the proper actions', async() => {
|
||||||
|
await store.dispatch(fetchAccountByUsername(username));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions[0]).toEqual({
|
||||||
|
type: 'RELATIONSHIPS_FETCH_REQUEST',
|
||||||
|
ids: ['123'],
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
expect(actions[1].type).toEqual('ACCOUNTS_IMPORT');
|
||||||
|
expect(actions[2].type).toEqual('ACCOUNT_FETCH_SUCCESS');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/accounts/${username}`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return dispatch the proper actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_FETCH_FAIL',
|
||||||
|
id: null,
|
||||||
|
error: new Error('Network Error'),
|
||||||
|
skipAlert: true,
|
||||||
|
},
|
||||||
|
{ type: 'ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP', username: 'tiger' },
|
||||||
|
];
|
||||||
|
|
||||||
|
await store.dispatch(fetchAccountByUsername(username));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when "accountLookup" feature is enabled', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {})
|
||||||
|
.set('instance', {
|
||||||
|
version: '3.4.1 (compatible; TruthSocial 1.0.0)',
|
||||||
|
pleroma: ImmutableMap({
|
||||||
|
metadata: ImmutableMap({
|
||||||
|
features: [],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet('/api/v1/accounts/lookup').reply(200, account);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return dispatch the proper actions', async() => {
|
||||||
|
await store.dispatch(fetchAccountByUsername(username));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions[0]).toEqual({
|
||||||
|
type: 'ACCOUNT_LOOKUP_REQUEST',
|
||||||
|
acct: username,
|
||||||
|
});
|
||||||
|
expect(actions[1].type).toEqual('ACCOUNTS_IMPORT');
|
||||||
|
expect(actions[2].type).toEqual('ACCOUNT_LOOKUP_SUCCESS');
|
||||||
|
expect(actions[3].type).toEqual('RELATIONSHIPS_FETCH_REQUEST');
|
||||||
|
expect(actions[4].type).toEqual('ACCOUNT_FETCH_SUCCESS');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet('/api/v1/accounts/lookup').networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return dispatch the proper actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_LOOKUP_REQUEST', acct: 'tiger' },
|
||||||
|
{ type: 'ACCOUNT_LOOKUP_FAIL' },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_FETCH_FAIL',
|
||||||
|
id: null,
|
||||||
|
error: new Error('Network Error'),
|
||||||
|
skipAlert: true,
|
||||||
|
},
|
||||||
|
{ type: 'ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP', username },
|
||||||
|
];
|
||||||
|
|
||||||
|
await store.dispatch(fetchAccountByUsername(username));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when using the accountSearch function', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet('/api/v1/accounts/search').reply(200, [account]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return dispatch the proper actions', async() => {
|
||||||
|
await store.dispatch(fetchAccountByUsername(username));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions[0]).toEqual({
|
||||||
|
type: 'ACCOUNT_SEARCH_REQUEST',
|
||||||
|
params: { q: username, limit: 5, resolve: true },
|
||||||
|
});
|
||||||
|
expect(actions[1].type).toEqual('ACCOUNTS_IMPORT');
|
||||||
|
expect(actions[2].type).toEqual('ACCOUNT_SEARCH_SUCCESS');
|
||||||
|
expect(actions[3]).toEqual({
|
||||||
|
type: 'RELATIONSHIPS_FETCH_REQUEST',
|
||||||
|
ids: [ '123' ],
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
expect(actions[4].type).toEqual('ACCOUNT_FETCH_SUCCESS');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet('/api/v1/accounts/search').networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return dispatch the proper actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_SEARCH_REQUEST',
|
||||||
|
params: { q: username, limit: 5, resolve: true },
|
||||||
|
},
|
||||||
|
{ type: 'ACCOUNT_SEARCH_FAIL', skipAlert: true },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_FETCH_FAIL',
|
||||||
|
id: null,
|
||||||
|
error: new Error('Network Error'),
|
||||||
|
skipAlert: true,
|
||||||
|
},
|
||||||
|
{ type: 'ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP', username },
|
||||||
|
];
|
||||||
|
|
||||||
|
await store.dispatch(fetchAccountByUsername(username));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('followAccount()', () => {
|
||||||
|
describe('when logged out', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', null);
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(followAccount(1));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when logged in', () => {
|
||||||
|
const id = 1;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/follow`).reply(200, { success: true });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_FOLLOW_REQUEST',
|
||||||
|
id,
|
||||||
|
locked: false,
|
||||||
|
skipLoading: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_FOLLOW_SUCCESS',
|
||||||
|
relationship: { success: true },
|
||||||
|
alreadyFollowing: undefined,
|
||||||
|
skipLoading: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(followAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/follow`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_FOLLOW_REQUEST',
|
||||||
|
id,
|
||||||
|
locked: false,
|
||||||
|
skipLoading: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_FOLLOW_FAIL',
|
||||||
|
error: new Error('Network Error'),
|
||||||
|
locked: false,
|
||||||
|
skipLoading: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
await store.dispatch(followAccount(id));
|
||||||
|
} catch (e) {
|
||||||
|
const actions = store.getActions();
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
expect(e).toEqual(new Error('Network Error'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('unfollowAccount()', () => {
|
||||||
|
describe('when logged out', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', null);
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(unfollowAccount(1));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when logged in', () => {
|
||||||
|
const id = 1;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/unfollow`).reply(200, { success: true });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_UNFOLLOW_REQUEST', id: 1, skipLoading: true },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_UNFOLLOW_SUCCESS',
|
||||||
|
relationship: { success: true },
|
||||||
|
statuses: ImmutableMap({}),
|
||||||
|
skipLoading: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(unfollowAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/unfollow`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_UNFOLLOW_REQUEST',
|
||||||
|
id,
|
||||||
|
skipLoading: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_UNFOLLOW_FAIL',
|
||||||
|
error: new Error('Network Error'),
|
||||||
|
skipLoading: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(unfollowAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('blockAccount()', () => {
|
||||||
|
const id = 1;
|
||||||
|
|
||||||
|
describe('when logged out', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', null);
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(blockAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when logged in', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/block`).reply(200, {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_BLOCK_REQUEST', id },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_BLOCK_SUCCESS',
|
||||||
|
relationship: {},
|
||||||
|
statuses: ImmutableMap({}),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(blockAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/block`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_BLOCK_REQUEST', id },
|
||||||
|
{ type: 'ACCOUNT_BLOCK_FAIL', error: new Error('Network Error') },
|
||||||
|
];
|
||||||
|
await store.dispatch(blockAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('unblockAccount()', () => {
|
||||||
|
const id = 1;
|
||||||
|
|
||||||
|
describe('when logged out', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', null);
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(unblockAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when logged in', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/unblock`).reply(200, {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_UNBLOCK_REQUEST', id },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_UNBLOCK_SUCCESS',
|
||||||
|
relationship: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(unblockAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/unblock`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_UNBLOCK_REQUEST', id },
|
||||||
|
{ type: 'ACCOUNT_UNBLOCK_FAIL', error: new Error('Network Error') },
|
||||||
|
];
|
||||||
|
await store.dispatch(unblockAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('muteAccount()', () => {
|
||||||
|
const id = 1;
|
||||||
|
|
||||||
|
describe('when logged out', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', null);
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(unblockAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when logged in', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/mute`).reply(200, {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_MUTE_REQUEST', id },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_MUTE_SUCCESS',
|
||||||
|
relationship: {},
|
||||||
|
statuses: ImmutableMap({}),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(muteAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/mute`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_MUTE_REQUEST', id },
|
||||||
|
{ type: 'ACCOUNT_MUTE_FAIL', error: new Error('Network Error') },
|
||||||
|
];
|
||||||
|
await store.dispatch(muteAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('unmuteAccount()', () => {
|
||||||
|
const id = 1;
|
||||||
|
|
||||||
|
describe('when logged out', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', null);
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(unblockAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when logged in', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/unmute`).reply(200, {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_UNMUTE_REQUEST', id },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_UNMUTE_SUCCESS',
|
||||||
|
relationship: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(unmuteAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/accounts/${id}/unmute`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_UNMUTE_REQUEST', id },
|
||||||
|
{ type: 'ACCOUNT_UNMUTE_FAIL', error: new Error('Network Error') },
|
||||||
|
];
|
||||||
|
await store.dispatch(unmuteAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('subscribeAccount()', () => {
|
||||||
|
const id = 1;
|
||||||
|
|
||||||
|
describe('when logged out', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', null);
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(subscribeAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when logged in', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/pleroma/accounts/${id}/subscribe`).reply(200, {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_SUBSCRIBE_REQUEST', id },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_SUBSCRIBE_SUCCESS',
|
||||||
|
relationship: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(subscribeAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/pleroma/accounts/${id}/subscribe`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_SUBSCRIBE_REQUEST', id },
|
||||||
|
{ type: 'ACCOUNT_SUBSCRIBE_FAIL', error: new Error('Network Error') },
|
||||||
|
];
|
||||||
|
await store.dispatch(subscribeAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('unsubscribeAccount()', () => {
|
||||||
|
const id = 1;
|
||||||
|
|
||||||
|
describe('when logged out', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', null);
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(subscribeAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when logged in', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', '123');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/pleroma/accounts/${id}/unsubscribe`).reply(200, {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_UNSUBSCRIBE_REQUEST', id },
|
||||||
|
{
|
||||||
|
type: 'ACCOUNT_UNSUBSCRIBE_SUCCESS',
|
||||||
|
relationship: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(unsubscribeAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onPost(`/api/v1/pleroma/accounts/${id}/unsubscribe`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch the correct actions', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'ACCOUNT_UNSUBSCRIBE_REQUEST', id },
|
||||||
|
{ type: 'ACCOUNT_UNSUBSCRIBE_FAIL', error: new Error('Network Error') },
|
||||||
|
];
|
||||||
|
await store.dispatch(unsubscribeAccount(id));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
import { __stub } from 'soapbox/api';
|
import { __stub } from 'soapbox/api';
|
||||||
import { mockStore } from 'soapbox/jest/test-helpers';
|
import { mockStore } from 'soapbox/jest/test-helpers';
|
||||||
import rootReducer from 'soapbox/reducers';
|
import rootReducer from 'soapbox/reducers';
|
||||||
|
@ -111,7 +113,7 @@ describe('expandBlocks()', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const state = rootReducer(undefined, {})
|
const state = rootReducer(undefined, {})
|
||||||
.set('me', '1234')
|
.set('me', '1234')
|
||||||
.set('user_lists', { blocks: { next: null } });
|
.set('user_lists', ImmutableMap({ blocks: { next: null } }));
|
||||||
store = mockStore(state);
|
store = mockStore(state);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -127,7 +129,7 @@ describe('expandBlocks()', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const state = rootReducer(undefined, {})
|
const state = rootReducer(undefined, {})
|
||||||
.set('me', '1234')
|
.set('me', '1234')
|
||||||
.set('user_lists', { blocks: { next: 'example' } });
|
.set('user_lists', ImmutableMap({ blocks: { next: 'example' } }));
|
||||||
store = mockStore(state);
|
store = mockStore(state);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { fromJS } from 'immutable';
|
||||||
|
|
||||||
import { mockStore } from 'soapbox/jest/test-helpers';
|
import { mockStore } from 'soapbox/jest/test-helpers';
|
||||||
import { InstanceRecord } from 'soapbox/normalizers';
|
import { InstanceRecord } from 'soapbox/normalizers';
|
||||||
import rootReducer from 'soapbox/reducers';
|
import rootReducer from 'soapbox/reducers';
|
||||||
|
@ -10,14 +12,14 @@ describe('uploadCompose()', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const instance = InstanceRecord({
|
const instance = InstanceRecord({
|
||||||
configuration: {
|
configuration: fromJS({
|
||||||
statuses: {
|
statuses: {
|
||||||
max_media_attachments: 4,
|
max_media_attachments: 4,
|
||||||
},
|
},
|
||||||
media_attachments: {
|
media_attachments: {
|
||||||
image_size_limit: 10,
|
image_size_limit: 10,
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const state = rootReducer(undefined, {})
|
const state = rootReducer(undefined, {})
|
||||||
|
@ -62,14 +64,14 @@ describe('uploadCompose()', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const instance = InstanceRecord({
|
const instance = InstanceRecord({
|
||||||
configuration: {
|
configuration: fromJS({
|
||||||
statuses: {
|
statuses: {
|
||||||
max_media_attachments: 4,
|
max_media_attachments: 4,
|
||||||
},
|
},
|
||||||
media_attachments: {
|
media_attachments: {
|
||||||
video_size_limit: 10,
|
video_size_limit: 10,
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const state = rootReducer(undefined, {})
|
const state = rootReducer(undefined, {})
|
|
@ -1,27 +0,0 @@
|
||||||
import { STATUSES_IMPORT } from 'soapbox/actions/importer';
|
|
||||||
import { __stub } from 'soapbox/api';
|
|
||||||
import { mockStore, rootState } from 'soapbox/jest/test-helpers';
|
|
||||||
|
|
||||||
import { fetchContext } from '../statuses';
|
|
||||||
|
|
||||||
describe('fetchContext()', () => {
|
|
||||||
it('handles Mitra context', done => {
|
|
||||||
const statuses = require('soapbox/__fixtures__/mitra-context.json');
|
|
||||||
|
|
||||||
__stub(mock => {
|
|
||||||
mock.onGet('/api/v1/statuses/017ed505-5926-392f-256a-f86d5075df70/context')
|
|
||||||
.reply(200, statuses);
|
|
||||||
});
|
|
||||||
|
|
||||||
const store = mockStore(rootState);
|
|
||||||
|
|
||||||
store.dispatch(fetchContext('017ed505-5926-392f-256a-f86d5075df70')).then(context => {
|
|
||||||
const actions = store.getActions();
|
|
||||||
|
|
||||||
expect(actions[3].type).toEqual(STATUSES_IMPORT);
|
|
||||||
expect(actions[3].statuses[0].id).toEqual('017ed503-bc96-301a-e871-2c23b30ddd05');
|
|
||||||
|
|
||||||
done();
|
|
||||||
}).catch(console.error);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
import { fromJS, Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
|
import { STATUSES_IMPORT } from 'soapbox/actions/importer';
|
||||||
|
import { __stub } from 'soapbox/api';
|
||||||
|
import { mockStore, rootState } from 'soapbox/jest/test-helpers';
|
||||||
|
import { normalizeStatus } from 'soapbox/normalizers/status';
|
||||||
|
import rootReducer from 'soapbox/reducers';
|
||||||
|
|
||||||
|
import { deleteStatus, fetchContext } from '../statuses';
|
||||||
|
|
||||||
|
describe('fetchContext()', () => {
|
||||||
|
it('handles Mitra context', done => {
|
||||||
|
const statuses = require('soapbox/__fixtures__/mitra-context.json');
|
||||||
|
|
||||||
|
__stub(mock => {
|
||||||
|
mock.onGet('/api/v1/statuses/017ed505-5926-392f-256a-f86d5075df70/context')
|
||||||
|
.reply(200, statuses);
|
||||||
|
});
|
||||||
|
|
||||||
|
const store = mockStore(rootState);
|
||||||
|
|
||||||
|
store.dispatch(fetchContext('017ed505-5926-392f-256a-f86d5075df70')).then(context => {
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions[3].type).toEqual(STATUSES_IMPORT);
|
||||||
|
expect(actions[3].statuses[0].id).toEqual('017ed503-bc96-301a-e871-2c23b30ddd05');
|
||||||
|
|
||||||
|
done();
|
||||||
|
}).catch(console.error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteStatus()', () => {
|
||||||
|
let store;
|
||||||
|
|
||||||
|
describe('if logged out', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {}).set('me', null);
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(deleteStatus('1'));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if logged in', () => {
|
||||||
|
const statusId = 'AHU2RrX0wdcwzCYjFQ';
|
||||||
|
const cachedStatus = normalizeStatus({
|
||||||
|
id: statusId,
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootReducer(undefined, {})
|
||||||
|
.set('me', '1234')
|
||||||
|
.set('statuses', fromJS({
|
||||||
|
[statusId]: cachedStatus,
|
||||||
|
}));
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
let status;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
status = require('soapbox/__fixtures__/pleroma-status-deleted.json');
|
||||||
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onDelete(`/api/v1/statuses/${statusId}`).reply(200, status);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the status from the API', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: 'STATUS_DELETE_REQUEST',
|
||||||
|
params: cachedStatus,
|
||||||
|
},
|
||||||
|
{ type: 'STATUS_DELETE_SUCCESS', id: statusId },
|
||||||
|
{
|
||||||
|
type: 'TIMELINE_DELETE',
|
||||||
|
id: statusId,
|
||||||
|
accountId: null,
|
||||||
|
references: ImmutableMap({}),
|
||||||
|
reblogOf: null,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(deleteStatus(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle redraft', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: 'STATUS_DELETE_REQUEST',
|
||||||
|
params: cachedStatus,
|
||||||
|
},
|
||||||
|
{ type: 'STATUS_DELETE_SUCCESS', id: statusId },
|
||||||
|
{
|
||||||
|
type: 'TIMELINE_DELETE',
|
||||||
|
id: statusId,
|
||||||
|
accountId: null,
|
||||||
|
references: ImmutableMap({}),
|
||||||
|
reblogOf: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'COMPOSE_SET_STATUS',
|
||||||
|
status: cachedStatus,
|
||||||
|
rawText: status.text,
|
||||||
|
explicitAddressing: false,
|
||||||
|
spoilerText: '',
|
||||||
|
contentType: 'text/markdown',
|
||||||
|
v: {
|
||||||
|
build: undefined,
|
||||||
|
compatVersion: '0.0.0',
|
||||||
|
software: 'Mastodon',
|
||||||
|
version: '0.0.0',
|
||||||
|
},
|
||||||
|
withRedraft: true,
|
||||||
|
},
|
||||||
|
{ type: 'MODAL_OPEN', modalType: 'COMPOSE', modalProps: undefined },
|
||||||
|
];
|
||||||
|
await store.dispatch(deleteStatus(statusId, true));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onDelete(`/api/v1/statuses/${statusId}`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch failed action', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: 'STATUS_DELETE_REQUEST',
|
||||||
|
params: cachedStatus,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'STATUS_DELETE_FAIL',
|
||||||
|
params: cachedStatus,
|
||||||
|
error: new Error('Network Error'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await store.dispatch(deleteStatus(statusId, true));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,12 +1,12 @@
|
||||||
import { AnyAction } from 'redux';
|
|
||||||
|
|
||||||
import { staticClient } from '../api';
|
import { staticClient } from '../api';
|
||||||
|
|
||||||
|
import type { AnyAction } from 'redux';
|
||||||
|
|
||||||
const FETCH_ABOUT_PAGE_REQUEST = 'FETCH_ABOUT_PAGE_REQUEST';
|
const FETCH_ABOUT_PAGE_REQUEST = 'FETCH_ABOUT_PAGE_REQUEST';
|
||||||
const FETCH_ABOUT_PAGE_SUCCESS = 'FETCH_ABOUT_PAGE_SUCCESS';
|
const FETCH_ABOUT_PAGE_SUCCESS = 'FETCH_ABOUT_PAGE_SUCCESS';
|
||||||
const FETCH_ABOUT_PAGE_FAIL = 'FETCH_ABOUT_PAGE_FAIL';
|
const FETCH_ABOUT_PAGE_FAIL = 'FETCH_ABOUT_PAGE_FAIL';
|
||||||
|
|
||||||
const fetchAboutPage = (slug = 'index', locale?: string) => (dispatch: React.Dispatch<AnyAction>, getState: any) => {
|
const fetchAboutPage = (slug = 'index', locale?: string) => (dispatch: React.Dispatch<AnyAction>) => {
|
||||||
dispatch({ type: FETCH_ABOUT_PAGE_REQUEST, slug, locale });
|
dispatch({ type: FETCH_ABOUT_PAGE_REQUEST, slug, locale });
|
||||||
|
|
||||||
const filename = `${slug}${locale ? `.${locale}` : ''}.html`;
|
const filename = `${slug}${locale ? `.${locale}` : ''}.html`;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { AxiosError } from 'axios';
|
|
||||||
import { AnyAction } from 'redux';
|
|
||||||
|
|
||||||
import api from '../api';
|
import api from '../api';
|
||||||
|
|
||||||
import { openModal, closeModal } from './modals';
|
import { openModal, closeModal } from './modals';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AnyAction } from 'redux';
|
||||||
|
import type { RootState } from 'soapbox/store';
|
||||||
import type { Account } from 'soapbox/types/entities';
|
import type { Account } from 'soapbox/types/entities';
|
||||||
|
|
||||||
const ACCOUNT_NOTE_SUBMIT_REQUEST = 'ACCOUNT_NOTE_SUBMIT_REQUEST';
|
const ACCOUNT_NOTE_SUBMIT_REQUEST = 'ACCOUNT_NOTE_SUBMIT_REQUEST';
|
||||||
|
@ -15,14 +15,14 @@ const ACCOUNT_NOTE_INIT_MODAL = 'ACCOUNT_NOTE_INIT_MODAL';
|
||||||
|
|
||||||
const ACCOUNT_NOTE_CHANGE_COMMENT = 'ACCOUNT_NOTE_CHANGE_COMMENT';
|
const ACCOUNT_NOTE_CHANGE_COMMENT = 'ACCOUNT_NOTE_CHANGE_COMMENT';
|
||||||
|
|
||||||
const submitAccountNote = () => (dispatch: React.Dispatch<AnyAction>, getState: any) => {
|
const submitAccountNote = () => (dispatch: React.Dispatch<AnyAction>, getState: () => RootState) => {
|
||||||
dispatch(submitAccountNoteRequest());
|
dispatch(submitAccountNoteRequest());
|
||||||
|
|
||||||
const id = getState().getIn(['account_notes', 'edit', 'account_id']);
|
const id = getState().account_notes.edit.account;
|
||||||
|
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.post(`/api/v1/accounts/${id}/note`, {
|
.post(`/api/v1/accounts/${id}/note`, {
|
||||||
comment: getState().getIn(['account_notes', 'edit', 'comment']),
|
comment: getState().account_notes.edit.comment,
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
dispatch(closeModal());
|
dispatch(closeModal());
|
||||||
|
@ -51,8 +51,8 @@ function submitAccountNoteFail(error: AxiosError) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const initAccountNoteModal = (account: Account) => (dispatch: React.Dispatch<AnyAction>, getState: any) => {
|
const initAccountNoteModal = (account: Account) => (dispatch: React.Dispatch<AnyAction>, getState: () => RootState) => {
|
||||||
const comment = getState().getIn(['relationships', account.get('id'), 'note']);
|
const comment = getState().relationships.get(account.id)!.note;
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACCOUNT_NOTE_INIT_MODAL,
|
type: ACCOUNT_NOTE_INIT_MODAL,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -4,78 +4,82 @@ import { getFeatures } from 'soapbox/utils/features';
|
||||||
|
|
||||||
import api, { getLinks } from '../api';
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
export const ADMIN_CONFIG_FETCH_REQUEST = 'ADMIN_CONFIG_FETCH_REQUEST';
|
import type { AxiosResponse } from 'axios';
|
||||||
export const ADMIN_CONFIG_FETCH_SUCCESS = 'ADMIN_CONFIG_FETCH_SUCCESS';
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
export const ADMIN_CONFIG_FETCH_FAIL = 'ADMIN_CONFIG_FETCH_FAIL';
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
export const ADMIN_CONFIG_UPDATE_REQUEST = 'ADMIN_CONFIG_UPDATE_REQUEST';
|
const ADMIN_CONFIG_FETCH_REQUEST = 'ADMIN_CONFIG_FETCH_REQUEST';
|
||||||
export const ADMIN_CONFIG_UPDATE_SUCCESS = 'ADMIN_CONFIG_UPDATE_SUCCESS';
|
const ADMIN_CONFIG_FETCH_SUCCESS = 'ADMIN_CONFIG_FETCH_SUCCESS';
|
||||||
export const ADMIN_CONFIG_UPDATE_FAIL = 'ADMIN_CONFIG_UPDATE_FAIL';
|
const ADMIN_CONFIG_FETCH_FAIL = 'ADMIN_CONFIG_FETCH_FAIL';
|
||||||
|
|
||||||
export const ADMIN_REPORTS_FETCH_REQUEST = 'ADMIN_REPORTS_FETCH_REQUEST';
|
const ADMIN_CONFIG_UPDATE_REQUEST = 'ADMIN_CONFIG_UPDATE_REQUEST';
|
||||||
export const ADMIN_REPORTS_FETCH_SUCCESS = 'ADMIN_REPORTS_FETCH_SUCCESS';
|
const ADMIN_CONFIG_UPDATE_SUCCESS = 'ADMIN_CONFIG_UPDATE_SUCCESS';
|
||||||
export const ADMIN_REPORTS_FETCH_FAIL = 'ADMIN_REPORTS_FETCH_FAIL';
|
const ADMIN_CONFIG_UPDATE_FAIL = 'ADMIN_CONFIG_UPDATE_FAIL';
|
||||||
|
|
||||||
export const ADMIN_REPORTS_PATCH_REQUEST = 'ADMIN_REPORTS_PATCH_REQUEST';
|
const ADMIN_REPORTS_FETCH_REQUEST = 'ADMIN_REPORTS_FETCH_REQUEST';
|
||||||
export const ADMIN_REPORTS_PATCH_SUCCESS = 'ADMIN_REPORTS_PATCH_SUCCESS';
|
const ADMIN_REPORTS_FETCH_SUCCESS = 'ADMIN_REPORTS_FETCH_SUCCESS';
|
||||||
export const ADMIN_REPORTS_PATCH_FAIL = 'ADMIN_REPORTS_PATCH_FAIL';
|
const ADMIN_REPORTS_FETCH_FAIL = 'ADMIN_REPORTS_FETCH_FAIL';
|
||||||
|
|
||||||
export const ADMIN_USERS_FETCH_REQUEST = 'ADMIN_USERS_FETCH_REQUEST';
|
const ADMIN_REPORTS_PATCH_REQUEST = 'ADMIN_REPORTS_PATCH_REQUEST';
|
||||||
export const ADMIN_USERS_FETCH_SUCCESS = 'ADMIN_USERS_FETCH_SUCCESS';
|
const ADMIN_REPORTS_PATCH_SUCCESS = 'ADMIN_REPORTS_PATCH_SUCCESS';
|
||||||
export const ADMIN_USERS_FETCH_FAIL = 'ADMIN_USERS_FETCH_FAIL';
|
const ADMIN_REPORTS_PATCH_FAIL = 'ADMIN_REPORTS_PATCH_FAIL';
|
||||||
|
|
||||||
export const ADMIN_USERS_DELETE_REQUEST = 'ADMIN_USERS_DELETE_REQUEST';
|
const ADMIN_USERS_FETCH_REQUEST = 'ADMIN_USERS_FETCH_REQUEST';
|
||||||
export const ADMIN_USERS_DELETE_SUCCESS = 'ADMIN_USERS_DELETE_SUCCESS';
|
const ADMIN_USERS_FETCH_SUCCESS = 'ADMIN_USERS_FETCH_SUCCESS';
|
||||||
export const ADMIN_USERS_DELETE_FAIL = 'ADMIN_USERS_DELETE_FAIL';
|
const ADMIN_USERS_FETCH_FAIL = 'ADMIN_USERS_FETCH_FAIL';
|
||||||
|
|
||||||
export const ADMIN_USERS_APPROVE_REQUEST = 'ADMIN_USERS_APPROVE_REQUEST';
|
const ADMIN_USERS_DELETE_REQUEST = 'ADMIN_USERS_DELETE_REQUEST';
|
||||||
export const ADMIN_USERS_APPROVE_SUCCESS = 'ADMIN_USERS_APPROVE_SUCCESS';
|
const ADMIN_USERS_DELETE_SUCCESS = 'ADMIN_USERS_DELETE_SUCCESS';
|
||||||
export const ADMIN_USERS_APPROVE_FAIL = 'ADMIN_USERS_APPROVE_FAIL';
|
const ADMIN_USERS_DELETE_FAIL = 'ADMIN_USERS_DELETE_FAIL';
|
||||||
|
|
||||||
export const ADMIN_USERS_DEACTIVATE_REQUEST = 'ADMIN_USERS_DEACTIVATE_REQUEST';
|
const ADMIN_USERS_APPROVE_REQUEST = 'ADMIN_USERS_APPROVE_REQUEST';
|
||||||
export const ADMIN_USERS_DEACTIVATE_SUCCESS = 'ADMIN_USERS_DEACTIVATE_SUCCESS';
|
const ADMIN_USERS_APPROVE_SUCCESS = 'ADMIN_USERS_APPROVE_SUCCESS';
|
||||||
export const ADMIN_USERS_DEACTIVATE_FAIL = 'ADMIN_USERS_DEACTIVATE_FAIL';
|
const ADMIN_USERS_APPROVE_FAIL = 'ADMIN_USERS_APPROVE_FAIL';
|
||||||
|
|
||||||
export const ADMIN_STATUS_DELETE_REQUEST = 'ADMIN_STATUS_DELETE_REQUEST';
|
const ADMIN_USERS_DEACTIVATE_REQUEST = 'ADMIN_USERS_DEACTIVATE_REQUEST';
|
||||||
export const ADMIN_STATUS_DELETE_SUCCESS = 'ADMIN_STATUS_DELETE_SUCCESS';
|
const ADMIN_USERS_DEACTIVATE_SUCCESS = 'ADMIN_USERS_DEACTIVATE_SUCCESS';
|
||||||
export const ADMIN_STATUS_DELETE_FAIL = 'ADMIN_STATUS_DELETE_FAIL';
|
const ADMIN_USERS_DEACTIVATE_FAIL = 'ADMIN_USERS_DEACTIVATE_FAIL';
|
||||||
|
|
||||||
export const ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST';
|
const ADMIN_STATUS_DELETE_REQUEST = 'ADMIN_STATUS_DELETE_REQUEST';
|
||||||
export const ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS';
|
const ADMIN_STATUS_DELETE_SUCCESS = 'ADMIN_STATUS_DELETE_SUCCESS';
|
||||||
export const ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL';
|
const ADMIN_STATUS_DELETE_FAIL = 'ADMIN_STATUS_DELETE_FAIL';
|
||||||
|
|
||||||
export const ADMIN_LOG_FETCH_REQUEST = 'ADMIN_LOG_FETCH_REQUEST';
|
const ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST';
|
||||||
export const ADMIN_LOG_FETCH_SUCCESS = 'ADMIN_LOG_FETCH_SUCCESS';
|
const ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS';
|
||||||
export const ADMIN_LOG_FETCH_FAIL = 'ADMIN_LOG_FETCH_FAIL';
|
const ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL';
|
||||||
|
|
||||||
export const ADMIN_USERS_TAG_REQUEST = 'ADMIN_USERS_TAG_REQUEST';
|
const ADMIN_LOG_FETCH_REQUEST = 'ADMIN_LOG_FETCH_REQUEST';
|
||||||
export const ADMIN_USERS_TAG_SUCCESS = 'ADMIN_USERS_TAG_SUCCESS';
|
const ADMIN_LOG_FETCH_SUCCESS = 'ADMIN_LOG_FETCH_SUCCESS';
|
||||||
export const ADMIN_USERS_TAG_FAIL = 'ADMIN_USERS_TAG_FAIL';
|
const ADMIN_LOG_FETCH_FAIL = 'ADMIN_LOG_FETCH_FAIL';
|
||||||
|
|
||||||
export const ADMIN_USERS_UNTAG_REQUEST = 'ADMIN_USERS_UNTAG_REQUEST';
|
const ADMIN_USERS_TAG_REQUEST = 'ADMIN_USERS_TAG_REQUEST';
|
||||||
export const ADMIN_USERS_UNTAG_SUCCESS = 'ADMIN_USERS_UNTAG_SUCCESS';
|
const ADMIN_USERS_TAG_SUCCESS = 'ADMIN_USERS_TAG_SUCCESS';
|
||||||
export const ADMIN_USERS_UNTAG_FAIL = 'ADMIN_USERS_UNTAG_FAIL';
|
const ADMIN_USERS_TAG_FAIL = 'ADMIN_USERS_TAG_FAIL';
|
||||||
|
|
||||||
export const ADMIN_ADD_PERMISSION_GROUP_REQUEST = 'ADMIN_ADD_PERMISSION_GROUP_REQUEST';
|
const ADMIN_USERS_UNTAG_REQUEST = 'ADMIN_USERS_UNTAG_REQUEST';
|
||||||
export const ADMIN_ADD_PERMISSION_GROUP_SUCCESS = 'ADMIN_ADD_PERMISSION_GROUP_SUCCESS';
|
const ADMIN_USERS_UNTAG_SUCCESS = 'ADMIN_USERS_UNTAG_SUCCESS';
|
||||||
export const ADMIN_ADD_PERMISSION_GROUP_FAIL = 'ADMIN_ADD_PERMISSION_GROUP_FAIL';
|
const ADMIN_USERS_UNTAG_FAIL = 'ADMIN_USERS_UNTAG_FAIL';
|
||||||
|
|
||||||
export const ADMIN_REMOVE_PERMISSION_GROUP_REQUEST = 'ADMIN_REMOVE_PERMISSION_GROUP_REQUEST';
|
const ADMIN_ADD_PERMISSION_GROUP_REQUEST = 'ADMIN_ADD_PERMISSION_GROUP_REQUEST';
|
||||||
export const ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS = 'ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS';
|
const ADMIN_ADD_PERMISSION_GROUP_SUCCESS = 'ADMIN_ADD_PERMISSION_GROUP_SUCCESS';
|
||||||
export const ADMIN_REMOVE_PERMISSION_GROUP_FAIL = 'ADMIN_REMOVE_PERMISSION_GROUP_FAIL';
|
const ADMIN_ADD_PERMISSION_GROUP_FAIL = 'ADMIN_ADD_PERMISSION_GROUP_FAIL';
|
||||||
|
|
||||||
export const ADMIN_USERS_SUGGEST_REQUEST = 'ADMIN_USERS_SUGGEST_REQUEST';
|
const ADMIN_REMOVE_PERMISSION_GROUP_REQUEST = 'ADMIN_REMOVE_PERMISSION_GROUP_REQUEST';
|
||||||
export const ADMIN_USERS_SUGGEST_SUCCESS = 'ADMIN_USERS_SUGGEST_SUCCESS';
|
const ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS = 'ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS';
|
||||||
export const ADMIN_USERS_SUGGEST_FAIL = 'ADMIN_USERS_SUGGEST_FAIL';
|
const ADMIN_REMOVE_PERMISSION_GROUP_FAIL = 'ADMIN_REMOVE_PERMISSION_GROUP_FAIL';
|
||||||
|
|
||||||
export const ADMIN_USERS_UNSUGGEST_REQUEST = 'ADMIN_USERS_UNSUGGEST_REQUEST';
|
const ADMIN_USERS_SUGGEST_REQUEST = 'ADMIN_USERS_SUGGEST_REQUEST';
|
||||||
export const ADMIN_USERS_UNSUGGEST_SUCCESS = 'ADMIN_USERS_UNSUGGEST_SUCCESS';
|
const ADMIN_USERS_SUGGEST_SUCCESS = 'ADMIN_USERS_SUGGEST_SUCCESS';
|
||||||
export const ADMIN_USERS_UNSUGGEST_FAIL = 'ADMIN_USERS_UNSUGGEST_FAIL';
|
const ADMIN_USERS_SUGGEST_FAIL = 'ADMIN_USERS_SUGGEST_FAIL';
|
||||||
|
|
||||||
const nicknamesFromIds = (getState, ids) => ids.map(id => getState().getIn(['accounts', id, 'acct']));
|
const ADMIN_USERS_UNSUGGEST_REQUEST = 'ADMIN_USERS_UNSUGGEST_REQUEST';
|
||||||
|
const ADMIN_USERS_UNSUGGEST_SUCCESS = 'ADMIN_USERS_UNSUGGEST_SUCCESS';
|
||||||
|
const ADMIN_USERS_UNSUGGEST_FAIL = 'ADMIN_USERS_UNSUGGEST_FAIL';
|
||||||
|
|
||||||
export function fetchConfig() {
|
const nicknamesFromIds = (getState: () => RootState, ids: string[]) => ids.map(id => getState().accounts.get(id)!.acct);
|
||||||
return (dispatch, getState) => {
|
|
||||||
|
const fetchConfig = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: ADMIN_CONFIG_FETCH_REQUEST });
|
dispatch({ type: ADMIN_CONFIG_FETCH_REQUEST });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.get('/api/pleroma/admin/config')
|
.get('/api/pleroma/admin/config')
|
||||||
|
@ -85,10 +89,9 @@ export function fetchConfig() {
|
||||||
dispatch({ type: ADMIN_CONFIG_FETCH_FAIL, error });
|
dispatch({ type: ADMIN_CONFIG_FETCH_FAIL, error });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function updateConfig(configs) {
|
const updateConfig = (configs: Record<string, any>[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: ADMIN_CONFIG_UPDATE_REQUEST, configs });
|
dispatch({ type: ADMIN_CONFIG_UPDATE_REQUEST, configs });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.post('/api/pleroma/admin/config', { configs })
|
.post('/api/pleroma/admin/config', { configs })
|
||||||
|
@ -98,14 +101,13 @@ export function updateConfig(configs) {
|
||||||
dispatch({ type: ADMIN_CONFIG_UPDATE_FAIL, error, configs });
|
dispatch({ type: ADMIN_CONFIG_UPDATE_FAIL, error, configs });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function fetchMastodonReports(params) {
|
const fetchMastodonReports = (params: Record<string, any>) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
return api(getState)
|
api(getState)
|
||||||
.get('/api/v1/admin/reports', { params })
|
.get('/api/v1/admin/reports', { params })
|
||||||
.then(({ data: reports }) => {
|
.then(({ data: reports }) => {
|
||||||
reports.forEach(report => {
|
reports.forEach((report: APIEntity) => {
|
||||||
dispatch(importFetchedAccount(report.account?.account));
|
dispatch(importFetchedAccount(report.account?.account));
|
||||||
dispatch(importFetchedAccount(report.target_account?.account));
|
dispatch(importFetchedAccount(report.target_account?.account));
|
||||||
dispatch(importFetchedStatuses(report.statuses));
|
dispatch(importFetchedStatuses(report.statuses));
|
||||||
|
@ -114,15 +116,13 @@ function fetchMastodonReports(params) {
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: ADMIN_REPORTS_FETCH_FAIL, error, params });
|
dispatch({ type: ADMIN_REPORTS_FETCH_FAIL, error, params });
|
||||||
});
|
});
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetchPleromaReports(params) {
|
const fetchPleromaReports = (params: Record<string, any>) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
return api(getState)
|
api(getState)
|
||||||
.get('/api/pleroma/admin/reports', { params })
|
.get('/api/pleroma/admin/reports', { params })
|
||||||
.then(({ data: { reports } }) => {
|
.then(({ data: { reports } }) => {
|
||||||
reports.forEach(report => {
|
reports.forEach((report: APIEntity) => {
|
||||||
dispatch(importFetchedAccount(report.account));
|
dispatch(importFetchedAccount(report.account));
|
||||||
dispatch(importFetchedAccount(report.actor));
|
dispatch(importFetchedAccount(report.actor));
|
||||||
dispatch(importFetchedStatuses(report.statuses));
|
dispatch(importFetchedStatuses(report.statuses));
|
||||||
|
@ -131,19 +131,17 @@ function fetchPleromaReports(params) {
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: ADMIN_REPORTS_FETCH_FAIL, error, params });
|
dispatch({ type: ADMIN_REPORTS_FETCH_FAIL, error, params });
|
||||||
});
|
});
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchReports(params = {}) {
|
const fetchReports = (params: Record<string, any> = {}) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const instance = state.get('instance');
|
const instance = state.instance;
|
||||||
const features = getFeatures(instance);
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
dispatch({ type: ADMIN_REPORTS_FETCH_REQUEST, params });
|
dispatch({ type: ADMIN_REPORTS_FETCH_REQUEST, params });
|
||||||
|
|
||||||
if (features.mastodonAdminApi) {
|
if (features.mastodonAdmin) {
|
||||||
return dispatch(fetchMastodonReports(params));
|
return dispatch(fetchMastodonReports(params));
|
||||||
} else {
|
} else {
|
||||||
const { resolved } = params;
|
const { resolved } = params;
|
||||||
|
@ -153,11 +151,10 @@ export function fetchReports(params = {}) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function patchMastodonReports(reports) {
|
const patchMastodonReports = (reports: { id: string, state: string }[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
return Promise.all(reports.map(({ id, state }) => api(getState)
|
Promise.all(reports.map(({ id, state }) => api(getState)
|
||||||
.post(`/api/v1/admin/reports/${id}/${state === 'resolved' ? 'reopen' : 'resolve'}`)
|
.post(`/api/v1/admin/reports/${id}/${state === 'resolved' ? 'reopen' : 'resolve'}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch({ type: ADMIN_REPORTS_PATCH_SUCCESS, reports });
|
dispatch({ type: ADMIN_REPORTS_PATCH_SUCCESS, reports });
|
||||||
|
@ -165,47 +162,41 @@ function patchMastodonReports(reports) {
|
||||||
dispatch({ type: ADMIN_REPORTS_PATCH_FAIL, error, reports });
|
dispatch({ type: ADMIN_REPORTS_PATCH_FAIL, error, reports });
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function patchPleromaReports(reports) {
|
const patchPleromaReports = (reports: { id: string, state: string }[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
return api(getState)
|
api(getState)
|
||||||
.patch('/api/pleroma/admin/reports', { reports })
|
.patch('/api/pleroma/admin/reports', { reports })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch({ type: ADMIN_REPORTS_PATCH_SUCCESS, reports });
|
dispatch({ type: ADMIN_REPORTS_PATCH_SUCCESS, reports });
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: ADMIN_REPORTS_PATCH_FAIL, error, reports });
|
dispatch({ type: ADMIN_REPORTS_PATCH_FAIL, error, reports });
|
||||||
});
|
});
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function patchReports(ids, reportState) {
|
const patchReports = (ids: string[], reportState: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const instance = state.get('instance');
|
const instance = state.instance;
|
||||||
const features = getFeatures(instance);
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
const reports = ids.map(id => ({ id, state: reportState }));
|
const reports = ids.map(id => ({ id, state: reportState }));
|
||||||
|
|
||||||
dispatch({ type: ADMIN_REPORTS_PATCH_REQUEST, reports });
|
dispatch({ type: ADMIN_REPORTS_PATCH_REQUEST, reports });
|
||||||
|
|
||||||
if (features.mastodonAdminApi) {
|
if (features.mastodonAdmin) {
|
||||||
return dispatch(patchMastodonReports(reports));
|
return dispatch(patchMastodonReports(reports));
|
||||||
} else {
|
} else {
|
||||||
return dispatch(patchPleromaReports(reports));
|
return dispatch(patchPleromaReports(reports));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function closeReports(ids) {
|
const closeReports = (ids: string[]) =>
|
||||||
return patchReports(ids, 'closed');
|
patchReports(ids, 'closed');
|
||||||
}
|
|
||||||
|
|
||||||
function fetchMastodonUsers(filters, page, query, pageSize, next) {
|
const fetchMastodonUsers = (filters: string[], page: number, query: string | null | undefined, pageSize: number, next?: string | null) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const params = {
|
const params: Record<string, any> = {
|
||||||
username: query,
|
username: query,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -216,59 +207,56 @@ function fetchMastodonUsers(filters, page, query, pageSize, next) {
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.get(next || '/api/v1/admin/accounts', { params })
|
.get(next || '/api/v1/admin/accounts', { params })
|
||||||
.then(({ data: accounts, ...response }) => {
|
.then(({ data: accounts, ...response }) => {
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
const next = getLinks(response as AxiosResponse<any, any>).refs.find(link => link.rel === 'next');
|
||||||
|
|
||||||
const count = next
|
const count = next
|
||||||
? page * pageSize + 1
|
? page * pageSize + 1
|
||||||
: (page - 1) * pageSize + accounts.length;
|
: (page - 1) * pageSize + accounts.length;
|
||||||
|
|
||||||
dispatch(importFetchedAccounts(accounts.map(({ account }) => account)));
|
dispatch(importFetchedAccounts(accounts.map(({ account }: APIEntity) => account)));
|
||||||
dispatch(fetchRelationships(accounts.map(account => account.id)));
|
dispatch(fetchRelationships(accounts.map((account: APIEntity) => account.id)));
|
||||||
dispatch({ type: ADMIN_USERS_FETCH_SUCCESS, users: accounts, count, pageSize, filters, page, next: next?.uri || false });
|
dispatch({ type: ADMIN_USERS_FETCH_SUCCESS, users: accounts, count, pageSize, filters, page, next: next?.uri || false });
|
||||||
return { users: accounts, count, pageSize, next: next?.uri || false };
|
return { users: accounts, count, pageSize, next: next?.uri || false };
|
||||||
}).catch(error => {
|
}).catch(error =>
|
||||||
dispatch({ type: ADMIN_USERS_FETCH_FAIL, error, filters, page, pageSize });
|
dispatch({ type: ADMIN_USERS_FETCH_FAIL, error, filters, page, pageSize }),
|
||||||
});
|
);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function fetchPleromaUsers(filters, page, query, pageSize) {
|
const fetchPleromaUsers = (filters: string[], page: number, query?: string | null, pageSize?: number) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const params = { filters: filters.join(), page, page_size: pageSize };
|
const params: Record<string, any> = { filters: filters.join(), page, page_size: pageSize };
|
||||||
if (query) params.query = query;
|
if (query) params.query = query;
|
||||||
|
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.get('/api/pleroma/admin/users', { params })
|
.get('/api/pleroma/admin/users', { params })
|
||||||
.then(({ data: { users, count, page_size: pageSize } }) => {
|
.then(({ data: { users, count, page_size: pageSize } }) => {
|
||||||
dispatch(fetchRelationships(users.map(user => user.id)));
|
dispatch(fetchRelationships(users.map((user: APIEntity) => user.id)));
|
||||||
dispatch({ type: ADMIN_USERS_FETCH_SUCCESS, users, count, pageSize, filters, page });
|
dispatch({ type: ADMIN_USERS_FETCH_SUCCESS, users, count, pageSize, filters, page });
|
||||||
return { users, count, pageSize };
|
return { users, count, pageSize };
|
||||||
}).catch(error => {
|
}).catch(error =>
|
||||||
dispatch({ type: ADMIN_USERS_FETCH_FAIL, error, filters, page, pageSize });
|
dispatch({ type: ADMIN_USERS_FETCH_FAIL, error, filters, page, pageSize }),
|
||||||
});
|
);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchUsers(filters = [], page = 1, query, pageSize = 50, next) {
|
const fetchUsers = (filters: string[] = [], page = 1, query?: string | null, pageSize = 50, next?: string | null) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const instance = state.get('instance');
|
const instance = state.instance;
|
||||||
const features = getFeatures(instance);
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
dispatch({ type: ADMIN_USERS_FETCH_REQUEST, filters, page, pageSize });
|
dispatch({ type: ADMIN_USERS_FETCH_REQUEST, filters, page, pageSize });
|
||||||
|
|
||||||
if (features.mastodonAdminApi) {
|
if (features.mastodonAdmin) {
|
||||||
return dispatch(fetchMastodonUsers(filters, page, query, pageSize, next));
|
return dispatch(fetchMastodonUsers(filters, page, query, pageSize, next));
|
||||||
} else {
|
} else {
|
||||||
return dispatch(fetchPleromaUsers(filters, page, query, pageSize));
|
return dispatch(fetchPleromaUsers(filters, page, query, pageSize));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function deactivateMastodonUsers(accountIds, reportId) {
|
const deactivateMastodonUsers = (accountIds: string[], reportId?: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
return Promise.all(accountIds.map(accountId => {
|
Promise.all(accountIds.map(accountId => {
|
||||||
api(getState)
|
api(getState)
|
||||||
.post(`/api/v1/admin/accounts/${accountId}/action`, {
|
.post(`/api/v1/admin/accounts/${accountId}/action`, {
|
||||||
type: 'disable',
|
type: 'disable',
|
||||||
|
@ -280,11 +268,9 @@ function deactivateMastodonUsers(accountIds, reportId) {
|
||||||
dispatch({ type: ADMIN_USERS_DEACTIVATE_FAIL, error, accountIds: [accountId] });
|
dispatch({ type: ADMIN_USERS_DEACTIVATE_FAIL, error, accountIds: [accountId] });
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function deactivatePleromaUsers(accountIds) {
|
const deactivatePleromaUsers = (accountIds: string[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.patch('/api/pleroma/admin/users/deactivate', { nicknames })
|
.patch('/api/pleroma/admin/users/deactivate', { nicknames })
|
||||||
|
@ -294,27 +280,25 @@ function deactivatePleromaUsers(accountIds) {
|
||||||
dispatch({ type: ADMIN_USERS_DEACTIVATE_FAIL, error, accountIds });
|
dispatch({ type: ADMIN_USERS_DEACTIVATE_FAIL, error, accountIds });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function deactivateUsers(accountIds, reportId) {
|
const deactivateUsers = (accountIds: string[], reportId?: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const instance = state.get('instance');
|
const instance = state.instance;
|
||||||
const features = getFeatures(instance);
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
dispatch({ type: ADMIN_USERS_DEACTIVATE_REQUEST, accountIds });
|
dispatch({ type: ADMIN_USERS_DEACTIVATE_REQUEST, accountIds });
|
||||||
|
|
||||||
if (features.mastodonAdminApi) {
|
if (features.mastodonAdmin) {
|
||||||
return dispatch(deactivateMastodonUsers(accountIds, reportId));
|
return dispatch(deactivateMastodonUsers(accountIds, reportId));
|
||||||
} else {
|
} else {
|
||||||
return dispatch(deactivatePleromaUsers(accountIds));
|
return dispatch(deactivatePleromaUsers(accountIds));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteUsers(accountIds) {
|
const deleteUsers = (accountIds: string[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||||
dispatch({ type: ADMIN_USERS_DELETE_REQUEST, accountIds });
|
dispatch({ type: ADMIN_USERS_DELETE_REQUEST, accountIds });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
|
@ -325,11 +309,10 @@ export function deleteUsers(accountIds) {
|
||||||
dispatch({ type: ADMIN_USERS_DELETE_FAIL, error, accountIds });
|
dispatch({ type: ADMIN_USERS_DELETE_FAIL, error, accountIds });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function approveMastodonUsers(accountIds) {
|
const approveMastodonUsers = (accountIds: string[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
return Promise.all(accountIds.map(accountId => {
|
Promise.all(accountIds.map(accountId => {
|
||||||
api(getState)
|
api(getState)
|
||||||
.post(`/api/v1/admin/accounts/${accountId}/approve`)
|
.post(`/api/v1/admin/accounts/${accountId}/approve`)
|
||||||
.then(({ data: user }) => {
|
.then(({ data: user }) => {
|
||||||
|
@ -338,11 +321,9 @@ function approveMastodonUsers(accountIds) {
|
||||||
dispatch({ type: ADMIN_USERS_APPROVE_FAIL, error, accountIds: [accountId] });
|
dispatch({ type: ADMIN_USERS_APPROVE_FAIL, error, accountIds: [accountId] });
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function approvePleromaUsers(accountIds) {
|
const approvePleromaUsers = (accountIds: string[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.patch('/api/pleroma/admin/users/approve', { nicknames })
|
.patch('/api/pleroma/admin/users/approve', { nicknames })
|
||||||
|
@ -352,27 +333,25 @@ function approvePleromaUsers(accountIds) {
|
||||||
dispatch({ type: ADMIN_USERS_APPROVE_FAIL, error, accountIds });
|
dispatch({ type: ADMIN_USERS_APPROVE_FAIL, error, accountIds });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function approveUsers(accountIds) {
|
const approveUsers = (accountIds: string[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const instance = state.get('instance');
|
const instance = state.instance;
|
||||||
const features = getFeatures(instance);
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
dispatch({ type: ADMIN_USERS_APPROVE_REQUEST, accountIds });
|
dispatch({ type: ADMIN_USERS_APPROVE_REQUEST, accountIds });
|
||||||
|
|
||||||
if (features.mastodonAdminApi) {
|
if (features.mastodonAdmin) {
|
||||||
return dispatch(approveMastodonUsers(accountIds));
|
return dispatch(approveMastodonUsers(accountIds));
|
||||||
} else {
|
} else {
|
||||||
return dispatch(approvePleromaUsers(accountIds));
|
return dispatch(approvePleromaUsers(accountIds));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteStatus(id) {
|
const deleteStatus = (id: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: ADMIN_STATUS_DELETE_REQUEST, id });
|
dispatch({ type: ADMIN_STATUS_DELETE_REQUEST, id });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.delete(`/api/pleroma/admin/statuses/${id}`)
|
.delete(`/api/pleroma/admin/statuses/${id}`)
|
||||||
|
@ -382,10 +361,9 @@ export function deleteStatus(id) {
|
||||||
dispatch({ type: ADMIN_STATUS_DELETE_FAIL, error, id });
|
dispatch({ type: ADMIN_STATUS_DELETE_FAIL, error, id });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleStatusSensitivity(id, sensitive) {
|
const toggleStatusSensitivity = (id: string, sensitive: boolean) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST, id });
|
dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST, id });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.put(`/api/pleroma/admin/statuses/${id}`, { sensitive: !sensitive })
|
.put(`/api/pleroma/admin/statuses/${id}`, { sensitive: !sensitive })
|
||||||
|
@ -395,10 +373,9 @@ export function toggleStatusSensitivity(id, sensitive) {
|
||||||
dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL, error, id });
|
dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL, error, id });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchModerationLog(params) {
|
const fetchModerationLog = (params?: Record<string, any>) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: ADMIN_LOG_FETCH_REQUEST });
|
dispatch({ type: ADMIN_LOG_FETCH_REQUEST });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.get('/api/pleroma/admin/moderation_log', { params })
|
.get('/api/pleroma/admin/moderation_log', { params })
|
||||||
|
@ -409,10 +386,9 @@ export function fetchModerationLog(params) {
|
||||||
dispatch({ type: ADMIN_LOG_FETCH_FAIL, error });
|
dispatch({ type: ADMIN_LOG_FETCH_FAIL, error });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function tagUsers(accountIds, tags) {
|
const tagUsers = (accountIds: string[], tags: string[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||||
dispatch({ type: ADMIN_USERS_TAG_REQUEST, accountIds, tags });
|
dispatch({ type: ADMIN_USERS_TAG_REQUEST, accountIds, tags });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
|
@ -423,10 +399,9 @@ export function tagUsers(accountIds, tags) {
|
||||||
dispatch({ type: ADMIN_USERS_TAG_FAIL, error, accountIds, tags });
|
dispatch({ type: ADMIN_USERS_TAG_FAIL, error, accountIds, tags });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function untagUsers(accountIds, tags) {
|
const untagUsers = (accountIds: string[], tags: string[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||||
dispatch({ type: ADMIN_USERS_UNTAG_REQUEST, accountIds, tags });
|
dispatch({ type: ADMIN_USERS_UNTAG_REQUEST, accountIds, tags });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
|
@ -437,34 +412,25 @@ export function untagUsers(accountIds, tags) {
|
||||||
dispatch({ type: ADMIN_USERS_UNTAG_FAIL, error, accountIds, tags });
|
dispatch({ type: ADMIN_USERS_UNTAG_FAIL, error, accountIds, tags });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function verifyUser(accountId) {
|
const verifyUser = (accountId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) =>
|
||||||
return dispatch(tagUsers([accountId], ['verified']));
|
dispatch(tagUsers([accountId], ['verified']));
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unverifyUser(accountId) {
|
const unverifyUser = (accountId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) =>
|
||||||
return dispatch(untagUsers([accountId], ['verified']));
|
dispatch(untagUsers([accountId], ['verified']));
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setDonor(accountId) {
|
const setDonor = (accountId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) =>
|
||||||
return dispatch(tagUsers([accountId], ['donor']));
|
dispatch(tagUsers([accountId], ['donor']));
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeDonor(accountId) {
|
const removeDonor = (accountId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) =>
|
||||||
return dispatch(untagUsers([accountId], ['donor']));
|
dispatch(untagUsers([accountId], ['donor']));
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addPermission(accountIds, permissionGroup) {
|
const addPermission = (accountIds: string[], permissionGroup: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||||
dispatch({ type: ADMIN_ADD_PERMISSION_GROUP_REQUEST, accountIds, permissionGroup });
|
dispatch({ type: ADMIN_ADD_PERMISSION_GROUP_REQUEST, accountIds, permissionGroup });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
|
@ -475,10 +441,9 @@ export function addPermission(accountIds, permissionGroup) {
|
||||||
dispatch({ type: ADMIN_ADD_PERMISSION_GROUP_FAIL, error, accountIds, permissionGroup });
|
dispatch({ type: ADMIN_ADD_PERMISSION_GROUP_FAIL, error, accountIds, permissionGroup });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function removePermission(accountIds, permissionGroup) {
|
const removePermission = (accountIds: string[], permissionGroup: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||||
dispatch({ type: ADMIN_REMOVE_PERMISSION_GROUP_REQUEST, accountIds, permissionGroup });
|
dispatch({ type: ADMIN_REMOVE_PERMISSION_GROUP_REQUEST, accountIds, permissionGroup });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
|
@ -489,37 +454,30 @@ export function removePermission(accountIds, permissionGroup) {
|
||||||
dispatch({ type: ADMIN_REMOVE_PERMISSION_GROUP_FAIL, error, accountIds, permissionGroup });
|
dispatch({ type: ADMIN_REMOVE_PERMISSION_GROUP_FAIL, error, accountIds, permissionGroup });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function promoteToAdmin(accountId) {
|
const promoteToAdmin = (accountId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) =>
|
||||||
return Promise.all([
|
Promise.all([
|
||||||
dispatch(addPermission([accountId], 'admin')),
|
dispatch(addPermission([accountId], 'admin')),
|
||||||
dispatch(removePermission([accountId], 'moderator')),
|
dispatch(removePermission([accountId], 'moderator')),
|
||||||
]);
|
]);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function promoteToModerator(accountId) {
|
const promoteToModerator = (accountId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) =>
|
||||||
return Promise.all([
|
Promise.all([
|
||||||
dispatch(removePermission([accountId], 'admin')),
|
dispatch(removePermission([accountId], 'admin')),
|
||||||
dispatch(addPermission([accountId], 'moderator')),
|
dispatch(addPermission([accountId], 'moderator')),
|
||||||
]);
|
]);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function demoteToUser(accountId) {
|
const demoteToUser = (accountId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) =>
|
||||||
return Promise.all([
|
Promise.all([
|
||||||
dispatch(removePermission([accountId], 'admin')),
|
dispatch(removePermission([accountId], 'admin')),
|
||||||
dispatch(removePermission([accountId], 'moderator')),
|
dispatch(removePermission([accountId], 'moderator')),
|
||||||
]);
|
]);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function suggestUsers(accountIds) {
|
const suggestUsers = (accountIds: string[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||||
dispatch({ type: ADMIN_USERS_SUGGEST_REQUEST, accountIds });
|
dispatch({ type: ADMIN_USERS_SUGGEST_REQUEST, accountIds });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
|
@ -530,10 +488,9 @@ export function suggestUsers(accountIds) {
|
||||||
dispatch({ type: ADMIN_USERS_SUGGEST_FAIL, error, accountIds });
|
dispatch({ type: ADMIN_USERS_SUGGEST_FAIL, error, accountIds });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function unsuggestUsers(accountIds) {
|
const unsuggestUsers = (accountIds: string[]) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||||
dispatch({ type: ADMIN_USERS_UNSUGGEST_REQUEST, accountIds });
|
dispatch({ type: ADMIN_USERS_UNSUGGEST_REQUEST, accountIds });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
|
@ -544,4 +501,81 @@ export function unsuggestUsers(accountIds) {
|
||||||
dispatch({ type: ADMIN_USERS_UNSUGGEST_FAIL, error, accountIds });
|
dispatch({ type: ADMIN_USERS_UNSUGGEST_FAIL, error, accountIds });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
export {
|
||||||
|
ADMIN_CONFIG_FETCH_REQUEST,
|
||||||
|
ADMIN_CONFIG_FETCH_SUCCESS,
|
||||||
|
ADMIN_CONFIG_FETCH_FAIL,
|
||||||
|
ADMIN_CONFIG_UPDATE_REQUEST,
|
||||||
|
ADMIN_CONFIG_UPDATE_SUCCESS,
|
||||||
|
ADMIN_CONFIG_UPDATE_FAIL,
|
||||||
|
ADMIN_REPORTS_FETCH_REQUEST,
|
||||||
|
ADMIN_REPORTS_FETCH_SUCCESS,
|
||||||
|
ADMIN_REPORTS_FETCH_FAIL,
|
||||||
|
ADMIN_REPORTS_PATCH_REQUEST,
|
||||||
|
ADMIN_REPORTS_PATCH_SUCCESS,
|
||||||
|
ADMIN_REPORTS_PATCH_FAIL,
|
||||||
|
ADMIN_USERS_FETCH_REQUEST,
|
||||||
|
ADMIN_USERS_FETCH_SUCCESS,
|
||||||
|
ADMIN_USERS_FETCH_FAIL,
|
||||||
|
ADMIN_USERS_DELETE_REQUEST,
|
||||||
|
ADMIN_USERS_DELETE_SUCCESS,
|
||||||
|
ADMIN_USERS_DELETE_FAIL,
|
||||||
|
ADMIN_USERS_APPROVE_REQUEST,
|
||||||
|
ADMIN_USERS_APPROVE_SUCCESS,
|
||||||
|
ADMIN_USERS_APPROVE_FAIL,
|
||||||
|
ADMIN_USERS_DEACTIVATE_REQUEST,
|
||||||
|
ADMIN_USERS_DEACTIVATE_SUCCESS,
|
||||||
|
ADMIN_USERS_DEACTIVATE_FAIL,
|
||||||
|
ADMIN_STATUS_DELETE_REQUEST,
|
||||||
|
ADMIN_STATUS_DELETE_SUCCESS,
|
||||||
|
ADMIN_STATUS_DELETE_FAIL,
|
||||||
|
ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST,
|
||||||
|
ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS,
|
||||||
|
ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL,
|
||||||
|
ADMIN_LOG_FETCH_REQUEST,
|
||||||
|
ADMIN_LOG_FETCH_SUCCESS,
|
||||||
|
ADMIN_LOG_FETCH_FAIL,
|
||||||
|
ADMIN_USERS_TAG_REQUEST,
|
||||||
|
ADMIN_USERS_TAG_SUCCESS,
|
||||||
|
ADMIN_USERS_TAG_FAIL,
|
||||||
|
ADMIN_USERS_UNTAG_REQUEST,
|
||||||
|
ADMIN_USERS_UNTAG_SUCCESS,
|
||||||
|
ADMIN_USERS_UNTAG_FAIL,
|
||||||
|
ADMIN_ADD_PERMISSION_GROUP_REQUEST,
|
||||||
|
ADMIN_ADD_PERMISSION_GROUP_SUCCESS,
|
||||||
|
ADMIN_ADD_PERMISSION_GROUP_FAIL,
|
||||||
|
ADMIN_REMOVE_PERMISSION_GROUP_REQUEST,
|
||||||
|
ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS,
|
||||||
|
ADMIN_REMOVE_PERMISSION_GROUP_FAIL,
|
||||||
|
ADMIN_USERS_SUGGEST_REQUEST,
|
||||||
|
ADMIN_USERS_SUGGEST_SUCCESS,
|
||||||
|
ADMIN_USERS_SUGGEST_FAIL,
|
||||||
|
ADMIN_USERS_UNSUGGEST_REQUEST,
|
||||||
|
ADMIN_USERS_UNSUGGEST_SUCCESS,
|
||||||
|
ADMIN_USERS_UNSUGGEST_FAIL,
|
||||||
|
fetchConfig,
|
||||||
|
updateConfig,
|
||||||
|
fetchReports,
|
||||||
|
closeReports,
|
||||||
|
fetchUsers,
|
||||||
|
deactivateUsers,
|
||||||
|
deleteUsers,
|
||||||
|
approveUsers,
|
||||||
|
deleteStatus,
|
||||||
|
toggleStatusSensitivity,
|
||||||
|
fetchModerationLog,
|
||||||
|
tagUsers,
|
||||||
|
untagUsers,
|
||||||
|
verifyUser,
|
||||||
|
unverifyUser,
|
||||||
|
setDonor,
|
||||||
|
removeDonor,
|
||||||
|
addPermission,
|
||||||
|
removePermission,
|
||||||
|
promoteToAdmin,
|
||||||
|
promoteToModerator,
|
||||||
|
demoteToUser,
|
||||||
|
suggestUsers,
|
||||||
|
unsuggestUsers,
|
||||||
|
};
|
|
@ -1,10 +1,10 @@
|
||||||
import { AnyAction } from '@reduxjs/toolkit';
|
|
||||||
import { AxiosError } from 'axios';
|
|
||||||
import { defineMessages, MessageDescriptor } from 'react-intl';
|
import { defineMessages, MessageDescriptor } from 'react-intl';
|
||||||
|
|
||||||
import { httpErrorMessages } from 'soapbox/utils/errors';
|
import { httpErrorMessages } from 'soapbox/utils/errors';
|
||||||
|
|
||||||
import { SnackbarActionSeverity } from './snackbar';
|
import type { SnackbarActionSeverity } from './snackbar';
|
||||||
|
import type { AnyAction } from '@reduxjs/toolkit';
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },
|
unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },
|
||||||
|
@ -38,7 +38,7 @@ function showAlert(
|
||||||
}
|
}
|
||||||
|
|
||||||
const showAlertForError = (error: AxiosError<any>) => (dispatch: React.Dispatch<AnyAction>, _getState: any) => {
|
const showAlertForError = (error: AxiosError<any>) => (dispatch: React.Dispatch<AnyAction>, _getState: any) => {
|
||||||
if (error.response) {
|
if (error?.response) {
|
||||||
const { data, status, statusText } = error.response;
|
const { data, status, statusText } = error.response;
|
||||||
|
|
||||||
if (status === 502) {
|
if (status === 502) {
|
||||||
|
@ -52,7 +52,7 @@ const showAlertForError = (error: AxiosError<any>) => (dispatch: React.Dispatch<
|
||||||
|
|
||||||
let message: string | undefined = statusText;
|
let message: string | undefined = statusText;
|
||||||
|
|
||||||
if (data.error) {
|
if (data?.error) {
|
||||||
message = data.error;
|
message = data.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,196 +0,0 @@
|
||||||
import { defineMessages } from 'react-intl';
|
|
||||||
|
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
import { getFeatures } from 'soapbox/utils/features';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
import { showAlertForError } from './alerts';
|
|
||||||
import { importFetchedAccounts } from './importer';
|
|
||||||
import { patchMeSuccess } from './me';
|
|
||||||
import snackbar from './snackbar';
|
|
||||||
|
|
||||||
export const ALIASES_FETCH_REQUEST = 'ALIASES_FETCH_REQUEST';
|
|
||||||
export const ALIASES_FETCH_SUCCESS = 'ALIASES_FETCH_SUCCESS';
|
|
||||||
export const ALIASES_FETCH_FAIL = 'ALIASES_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const ALIASES_SUGGESTIONS_CHANGE = 'ALIASES_SUGGESTIONS_CHANGE';
|
|
||||||
export const ALIASES_SUGGESTIONS_READY = 'ALIASES_SUGGESTIONS_READY';
|
|
||||||
export const ALIASES_SUGGESTIONS_CLEAR = 'ALIASES_SUGGESTIONS_CLEAR';
|
|
||||||
|
|
||||||
export const ALIASES_ADD_REQUEST = 'ALIASES_ADD_REQUEST';
|
|
||||||
export const ALIASES_ADD_SUCCESS = 'ALIASES_ADD_SUCCESS';
|
|
||||||
export const ALIASES_ADD_FAIL = 'ALIASES_ADD_FAIL';
|
|
||||||
|
|
||||||
export const ALIASES_REMOVE_REQUEST = 'ALIASES_REMOVE_REQUEST';
|
|
||||||
export const ALIASES_REMOVE_SUCCESS = 'ALIASES_REMOVE_SUCCESS';
|
|
||||||
export const ALIASES_REMOVE_FAIL = 'ALIASES_REMOVE_FAIL';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
createSuccess: { id: 'aliases.success.add', defaultMessage: 'Account alias created successfully' },
|
|
||||||
removeSuccess: { id: 'aliases.success.remove', defaultMessage: 'Account alias removed successfully' },
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchAliases = (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
const state = getState();
|
|
||||||
|
|
||||||
const instance = state.get('instance');
|
|
||||||
const features = getFeatures(instance);
|
|
||||||
|
|
||||||
if (!features.accountMoving) return;
|
|
||||||
|
|
||||||
dispatch(fetchAliasesRequest());
|
|
||||||
|
|
||||||
api(getState).get('/api/pleroma/aliases')
|
|
||||||
.then(response => {
|
|
||||||
dispatch(fetchAliasesSuccess(response.data.aliases));
|
|
||||||
})
|
|
||||||
.catch(err => dispatch(fetchAliasesFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchAliasesRequest = () => ({
|
|
||||||
type: ALIASES_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchAliasesSuccess = aliases => ({
|
|
||||||
type: ALIASES_FETCH_SUCCESS,
|
|
||||||
value: aliases,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchAliasesFail = error => ({
|
|
||||||
type: ALIASES_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchAliasesSuggestions = q => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
q,
|
|
||||||
resolve: true,
|
|
||||||
limit: 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
|
|
||||||
dispatch(importFetchedAccounts(data));
|
|
||||||
dispatch(fetchAliasesSuggestionsReady(q, data));
|
|
||||||
}).catch(error => dispatch(showAlertForError(error)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchAliasesSuggestionsReady = (query, accounts) => ({
|
|
||||||
type: ALIASES_SUGGESTIONS_READY,
|
|
||||||
query,
|
|
||||||
accounts,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const clearAliasesSuggestions = () => ({
|
|
||||||
type: ALIASES_SUGGESTIONS_CLEAR,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const changeAliasesSuggestions = value => ({
|
|
||||||
type: ALIASES_SUGGESTIONS_CHANGE,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addToAliases = (account) => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
const state = getState();
|
|
||||||
|
|
||||||
const instance = state.get('instance');
|
|
||||||
const features = getFeatures(instance);
|
|
||||||
|
|
||||||
if (!features.accountMoving) {
|
|
||||||
const me = state.get('me');
|
|
||||||
const alsoKnownAs = state.getIn(['accounts_meta', me, 'pleroma', 'also_known_as']);
|
|
||||||
|
|
||||||
dispatch(addToAliasesRequest());
|
|
||||||
|
|
||||||
api(getState).patch('/api/v1/accounts/update_credentials', { also_known_as: [...alsoKnownAs, account.getIn(['pleroma', 'ap_id'])] })
|
|
||||||
.then((response => {
|
|
||||||
dispatch(snackbar.success(messages.createSuccess));
|
|
||||||
dispatch(addToAliasesSuccess);
|
|
||||||
dispatch(patchMeSuccess(response.data));
|
|
||||||
}))
|
|
||||||
.catch(err => dispatch(addToAliasesFail(err)));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(addToAliasesRequest());
|
|
||||||
|
|
||||||
api(getState).put('/api/pleroma/aliases', {
|
|
||||||
alias: account.get('acct'),
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
dispatch(snackbar.success(messages.createSuccess));
|
|
||||||
dispatch(addToAliasesSuccess);
|
|
||||||
dispatch(fetchAliases);
|
|
||||||
})
|
|
||||||
.catch(err => dispatch(fetchAliasesFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addToAliasesRequest = () => ({
|
|
||||||
type: ALIASES_ADD_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addToAliasesSuccess = () => ({
|
|
||||||
type: ALIASES_ADD_SUCCESS,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addToAliasesFail = error => ({
|
|
||||||
type: ALIASES_ADD_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeFromAliases = (account) => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
const state = getState();
|
|
||||||
|
|
||||||
const instance = state.get('instance');
|
|
||||||
const features = getFeatures(instance);
|
|
||||||
|
|
||||||
if (!features.accountMoving) {
|
|
||||||
const me = state.get('me');
|
|
||||||
const alsoKnownAs = state.getIn(['accounts_meta', me, 'pleroma', 'also_known_as']);
|
|
||||||
|
|
||||||
dispatch(removeFromAliasesRequest());
|
|
||||||
|
|
||||||
api(getState).patch('/api/v1/accounts/update_credentials', { also_known_as: alsoKnownAs.filter(id => id !== account) })
|
|
||||||
.then(response => {
|
|
||||||
dispatch(snackbar.success(messages.removeSuccess));
|
|
||||||
dispatch(removeFromAliasesSuccess);
|
|
||||||
dispatch(patchMeSuccess(response.data));
|
|
||||||
})
|
|
||||||
.catch(err => dispatch(removeFromAliasesFail(err)));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(addToAliasesRequest());
|
|
||||||
|
|
||||||
api(getState).delete('/api/pleroma/aliases', {
|
|
||||||
data: {
|
|
||||||
alias: account,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
dispatch(snackbar.success(messages.removeSuccess));
|
|
||||||
dispatch(removeFromAliasesSuccess);
|
|
||||||
dispatch(fetchAliases);
|
|
||||||
})
|
|
||||||
.catch(err => dispatch(fetchAliasesFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeFromAliasesRequest = () => ({
|
|
||||||
type: ALIASES_REMOVE_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeFromAliasesSuccess = () => ({
|
|
||||||
type: ALIASES_REMOVE_SUCCESS,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeFromAliasesFail = error => ({
|
|
||||||
type: ALIASES_REMOVE_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
import { getFeatures } from 'soapbox/utils/features';
|
||||||
|
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import { showAlertForError } from './alerts';
|
||||||
|
import { importFetchedAccounts } from './importer';
|
||||||
|
import { patchMeSuccess } from './me';
|
||||||
|
import snackbar from './snackbar';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity, Account } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const ALIASES_FETCH_REQUEST = 'ALIASES_FETCH_REQUEST';
|
||||||
|
const ALIASES_FETCH_SUCCESS = 'ALIASES_FETCH_SUCCESS';
|
||||||
|
const ALIASES_FETCH_FAIL = 'ALIASES_FETCH_FAIL';
|
||||||
|
|
||||||
|
const ALIASES_SUGGESTIONS_CHANGE = 'ALIASES_SUGGESTIONS_CHANGE';
|
||||||
|
const ALIASES_SUGGESTIONS_READY = 'ALIASES_SUGGESTIONS_READY';
|
||||||
|
const ALIASES_SUGGESTIONS_CLEAR = 'ALIASES_SUGGESTIONS_CLEAR';
|
||||||
|
|
||||||
|
const ALIASES_ADD_REQUEST = 'ALIASES_ADD_REQUEST';
|
||||||
|
const ALIASES_ADD_SUCCESS = 'ALIASES_ADD_SUCCESS';
|
||||||
|
const ALIASES_ADD_FAIL = 'ALIASES_ADD_FAIL';
|
||||||
|
|
||||||
|
const ALIASES_REMOVE_REQUEST = 'ALIASES_REMOVE_REQUEST';
|
||||||
|
const ALIASES_REMOVE_SUCCESS = 'ALIASES_REMOVE_SUCCESS';
|
||||||
|
const ALIASES_REMOVE_FAIL = 'ALIASES_REMOVE_FAIL';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
createSuccess: { id: 'aliases.success.add', defaultMessage: 'Account alias created successfully' },
|
||||||
|
removeSuccess: { id: 'aliases.success.remove', defaultMessage: 'Account alias removed successfully' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchAliases = (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
const state = getState();
|
||||||
|
|
||||||
|
const instance = state.instance;
|
||||||
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
|
if (!features.accountMoving) return;
|
||||||
|
|
||||||
|
dispatch(fetchAliasesRequest());
|
||||||
|
|
||||||
|
api(getState).get('/api/pleroma/aliases')
|
||||||
|
.then(response => {
|
||||||
|
dispatch(fetchAliasesSuccess(response.data.aliases));
|
||||||
|
})
|
||||||
|
.catch(err => dispatch(fetchAliasesFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchAliasesRequest = () => ({
|
||||||
|
type: ALIASES_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchAliasesSuccess = (aliases: APIEntity[]) => ({
|
||||||
|
type: ALIASES_FETCH_SUCCESS,
|
||||||
|
value: aliases,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchAliasesFail = (error: AxiosError) => ({
|
||||||
|
type: ALIASES_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchAliasesSuggestions = (q: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
q,
|
||||||
|
resolve: true,
|
||||||
|
limit: 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
|
||||||
|
dispatch(importFetchedAccounts(data));
|
||||||
|
dispatch(fetchAliasesSuggestionsReady(q, data));
|
||||||
|
}).catch(error => dispatch(showAlertForError(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchAliasesSuggestionsReady = (query: string, accounts: APIEntity[]) => ({
|
||||||
|
type: ALIASES_SUGGESTIONS_READY,
|
||||||
|
query,
|
||||||
|
accounts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const clearAliasesSuggestions = () => ({
|
||||||
|
type: ALIASES_SUGGESTIONS_CLEAR,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeAliasesSuggestions = (value: string) => ({
|
||||||
|
type: ALIASES_SUGGESTIONS_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addToAliases = (account: Account) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
const state = getState();
|
||||||
|
|
||||||
|
const instance = state.instance;
|
||||||
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
|
if (!features.accountMoving) {
|
||||||
|
const me = state.me;
|
||||||
|
const alsoKnownAs = state.accounts_meta.get(me as string)!.pleroma.get('also_known_as');
|
||||||
|
|
||||||
|
dispatch(addToAliasesRequest());
|
||||||
|
|
||||||
|
api(getState).patch('/api/v1/accounts/update_credentials', { also_known_as: [...alsoKnownAs, account.pleroma.get('ap_id')] })
|
||||||
|
.then((response => {
|
||||||
|
dispatch(snackbar.success(messages.createSuccess));
|
||||||
|
dispatch(addToAliasesSuccess);
|
||||||
|
dispatch(patchMeSuccess(response.data));
|
||||||
|
}))
|
||||||
|
.catch(err => dispatch(addToAliasesFail(err)));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(addToAliasesRequest());
|
||||||
|
|
||||||
|
api(getState).put('/api/pleroma/aliases', {
|
||||||
|
alias: account.acct,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
dispatch(snackbar.success(messages.createSuccess));
|
||||||
|
dispatch(addToAliasesSuccess);
|
||||||
|
dispatch(fetchAliases);
|
||||||
|
})
|
||||||
|
.catch(err => dispatch(fetchAliasesFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const addToAliasesRequest = () => ({
|
||||||
|
type: ALIASES_ADD_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addToAliasesSuccess = () => ({
|
||||||
|
type: ALIASES_ADD_SUCCESS,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addToAliasesFail = (error: AxiosError) => ({
|
||||||
|
type: ALIASES_ADD_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeFromAliases = (account: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
const state = getState();
|
||||||
|
|
||||||
|
const instance = state.instance;
|
||||||
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
|
if (!features.accountMoving) {
|
||||||
|
const me = state.me;
|
||||||
|
const alsoKnownAs = state.accounts_meta.get(me as string)!.pleroma.get('also_known_as');
|
||||||
|
|
||||||
|
dispatch(removeFromAliasesRequest());
|
||||||
|
|
||||||
|
api(getState).patch('/api/v1/accounts/update_credentials', { also_known_as: alsoKnownAs.filter((id: string) => id !== account) })
|
||||||
|
.then(response => {
|
||||||
|
dispatch(snackbar.success(messages.removeSuccess));
|
||||||
|
dispatch(removeFromAliasesSuccess);
|
||||||
|
dispatch(patchMeSuccess(response.data));
|
||||||
|
})
|
||||||
|
.catch(err => dispatch(removeFromAliasesFail(err)));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(addToAliasesRequest());
|
||||||
|
|
||||||
|
api(getState).delete('/api/pleroma/aliases', {
|
||||||
|
data: {
|
||||||
|
alias: account,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
dispatch(snackbar.success(messages.removeSuccess));
|
||||||
|
dispatch(removeFromAliasesSuccess);
|
||||||
|
dispatch(fetchAliases);
|
||||||
|
})
|
||||||
|
.catch(err => dispatch(fetchAliasesFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeFromAliasesRequest = () => ({
|
||||||
|
type: ALIASES_REMOVE_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeFromAliasesSuccess = () => ({
|
||||||
|
type: ALIASES_REMOVE_SUCCESS,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeFromAliasesFail = (error: AxiosError) => ({
|
||||||
|
type: ALIASES_REMOVE_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
ALIASES_FETCH_REQUEST,
|
||||||
|
ALIASES_FETCH_SUCCESS,
|
||||||
|
ALIASES_FETCH_FAIL,
|
||||||
|
ALIASES_SUGGESTIONS_CHANGE,
|
||||||
|
ALIASES_SUGGESTIONS_READY,
|
||||||
|
ALIASES_SUGGESTIONS_CLEAR,
|
||||||
|
ALIASES_ADD_REQUEST,
|
||||||
|
ALIASES_ADD_SUCCESS,
|
||||||
|
ALIASES_ADD_FAIL,
|
||||||
|
ALIASES_REMOVE_REQUEST,
|
||||||
|
ALIASES_REMOVE_SUCCESS,
|
||||||
|
ALIASES_REMOVE_FAIL,
|
||||||
|
fetchAliases,
|
||||||
|
fetchAliasesRequest,
|
||||||
|
fetchAliasesSuccess,
|
||||||
|
fetchAliasesFail,
|
||||||
|
fetchAliasesSuggestions,
|
||||||
|
fetchAliasesSuggestionsReady,
|
||||||
|
clearAliasesSuggestions,
|
||||||
|
changeAliasesSuggestions,
|
||||||
|
addToAliases,
|
||||||
|
addToAliasesRequest,
|
||||||
|
addToAliasesSuccess,
|
||||||
|
addToAliasesFail,
|
||||||
|
removeFromAliases,
|
||||||
|
removeFromAliasesRequest,
|
||||||
|
removeFromAliasesSuccess,
|
||||||
|
removeFromAliasesFail,
|
||||||
|
};
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
import { baseClient } from '../api';
|
import { baseClient } from '../api';
|
||||||
|
|
||||||
|
import type { AnyAction } from 'redux';
|
||||||
|
|
||||||
export const APP_CREATE_REQUEST = 'APP_CREATE_REQUEST';
|
export const APP_CREATE_REQUEST = 'APP_CREATE_REQUEST';
|
||||||
export const APP_CREATE_SUCCESS = 'APP_CREATE_SUCCESS';
|
export const APP_CREATE_SUCCESS = 'APP_CREATE_SUCCESS';
|
||||||
export const APP_CREATE_FAIL = 'APP_CREATE_FAIL';
|
export const APP_CREATE_FAIL = 'APP_CREATE_FAIL';
|
||||||
|
@ -16,12 +18,12 @@ export const APP_VERIFY_CREDENTIALS_REQUEST = 'APP_VERIFY_CREDENTIALS_REQUEST';
|
||||||
export const APP_VERIFY_CREDENTIALS_SUCCESS = 'APP_VERIFY_CREDENTIALS_SUCCESS';
|
export const APP_VERIFY_CREDENTIALS_SUCCESS = 'APP_VERIFY_CREDENTIALS_SUCCESS';
|
||||||
export const APP_VERIFY_CREDENTIALS_FAIL = 'APP_VERIFY_CREDENTIALS_FAIL';
|
export const APP_VERIFY_CREDENTIALS_FAIL = 'APP_VERIFY_CREDENTIALS_FAIL';
|
||||||
|
|
||||||
export function createApp(params, baseURL) {
|
export function createApp(params?: Record<string, string>, baseURL?: string) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch: React.Dispatch<AnyAction>) => {
|
||||||
dispatch({ type: APP_CREATE_REQUEST, params });
|
dispatch({ type: APP_CREATE_REQUEST, params });
|
||||||
return baseClient(null, baseURL).post('/api/v1/apps', params).then(({ data: app }) => {
|
return baseClient(null, baseURL).post('/api/v1/apps', params).then(({ data: app }) => {
|
||||||
dispatch({ type: APP_CREATE_SUCCESS, params, app });
|
dispatch({ type: APP_CREATE_SUCCESS, params, app });
|
||||||
return app;
|
return app as Record<string, string>;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: APP_CREATE_FAIL, params, error });
|
dispatch({ type: APP_CREATE_FAIL, params, error });
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -29,8 +31,8 @@ export function createApp(params, baseURL) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function verifyAppCredentials(token) {
|
export function verifyAppCredentials(token: string) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch: React.Dispatch<AnyAction>) => {
|
||||||
dispatch({ type: APP_VERIFY_CREDENTIALS_REQUEST, token });
|
dispatch({ type: APP_VERIFY_CREDENTIALS_REQUEST, token });
|
||||||
return baseClient(token).get('/api/v1/apps/verify_credentials').then(({ data: app }) => {
|
return baseClient(token).get('/api/v1/apps/verify_credentials').then(({ data: app }) => {
|
||||||
dispatch({ type: APP_VERIFY_CREDENTIALS_SUCCESS, token, app });
|
dispatch({ type: APP_VERIFY_CREDENTIALS_SUCCESS, token, app });
|
|
@ -26,6 +26,10 @@ import api, { baseClient } from '../api';
|
||||||
|
|
||||||
import { importFetchedAccount } from './importer';
|
import { importFetchedAccount } from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { Map as ImmutableMap } from 'immutable';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
export const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT';
|
export const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT';
|
||||||
|
|
||||||
export const AUTH_APP_CREATED = 'AUTH_APP_CREATED';
|
export const AUTH_APP_CREATED = 'AUTH_APP_CREATED';
|
||||||
|
@ -48,35 +52,32 @@ export const messages = defineMessages({
|
||||||
invalidCredentials: { id: 'auth.invalid_credentials', defaultMessage: 'Wrong username or password' },
|
invalidCredentials: { id: 'auth.invalid_credentials', defaultMessage: 'Wrong username or password' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const noOp = () => new Promise(f => f());
|
const noOp = () => new Promise(f => f(undefined));
|
||||||
|
|
||||||
const getScopes = state => {
|
const getScopes = (state: RootState) => {
|
||||||
const instance = state.get('instance');
|
const instance = state.instance;
|
||||||
const { scopes } = getFeatures(instance);
|
const { scopes } = getFeatures(instance);
|
||||||
return scopes;
|
return scopes;
|
||||||
};
|
};
|
||||||
|
|
||||||
function createAppAndToken() {
|
const createAppAndToken = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) =>
|
||||||
return dispatch(getAuthApp()).then(() => {
|
dispatch(getAuthApp()).then(() =>
|
||||||
return dispatch(createAppToken());
|
dispatch(createAppToken()),
|
||||||
});
|
);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create an auth app, or use it from build config */
|
/** Create an auth app, or use it from build config */
|
||||||
function getAuthApp() {
|
const getAuthApp = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => {
|
||||||
if (customApp?.client_secret) {
|
if (customApp?.client_secret) {
|
||||||
return noOp().then(() => dispatch({ type: AUTH_APP_CREATED, app: customApp }));
|
return noOp().then(() => dispatch({ type: AUTH_APP_CREATED, app: customApp }));
|
||||||
} else {
|
} else {
|
||||||
return dispatch(createAuthApp());
|
return dispatch(createAuthApp());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function createAuthApp() {
|
const createAuthApp = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const params = {
|
const params = {
|
||||||
client_name: sourceCode.displayName,
|
client_name: sourceCode.displayName,
|
||||||
redirect_uris: 'urn:ietf:wg:oauth:2.0:oob',
|
redirect_uris: 'urn:ietf:wg:oauth:2.0:oob',
|
||||||
|
@ -84,15 +85,14 @@ function createAuthApp() {
|
||||||
website: sourceCode.homepage,
|
website: sourceCode.homepage,
|
||||||
};
|
};
|
||||||
|
|
||||||
return dispatch(createApp(params)).then(app => {
|
return dispatch(createApp(params)).then((app: Record<string, string>) =>
|
||||||
return dispatch({ type: AUTH_APP_CREATED, app });
|
dispatch({ type: AUTH_APP_CREATED, app }),
|
||||||
});
|
);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function createAppToken() {
|
const createAppToken = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const app = getState().getIn(['auth', 'app']);
|
const app = getState().auth.get('app');
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
client_id: app.get('client_id'),
|
client_id: app.get('client_id'),
|
||||||
|
@ -102,15 +102,14 @@ function createAppToken() {
|
||||||
scope: getScopes(getState()),
|
scope: getScopes(getState()),
|
||||||
};
|
};
|
||||||
|
|
||||||
return dispatch(obtainOAuthToken(params)).then(token => {
|
return dispatch(obtainOAuthToken(params)).then((token: Record<string, string | number>) =>
|
||||||
return dispatch({ type: AUTH_APP_AUTHORIZED, app, token });
|
dispatch({ type: AUTH_APP_AUTHORIZED, app, token }),
|
||||||
});
|
);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function createUserToken(username, password) {
|
const createUserToken = (username: string, password: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const app = getState().getIn(['auth', 'app']);
|
const app = getState().auth.get('app');
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
client_id: app.get('client_id'),
|
client_id: app.get('client_id'),
|
||||||
|
@ -123,14 +122,13 @@ function createUserToken(username, password) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return dispatch(obtainOAuthToken(params))
|
return dispatch(obtainOAuthToken(params))
|
||||||
.then(token => dispatch(authLoggedIn(token)));
|
.then((token: Record<string, string | number>) => dispatch(authLoggedIn(token)));
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function refreshUserToken() {
|
export const refreshUserToken = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const refreshToken = getState().getIn(['auth', 'user', 'refresh_token']);
|
const refreshToken = getState().auth.getIn(['user', 'refresh_token']);
|
||||||
const app = getState().getIn(['auth', 'app']);
|
const app = getState().auth.get('app');
|
||||||
|
|
||||||
if (!refreshToken) return dispatch(noOp);
|
if (!refreshToken) return dispatch(noOp);
|
||||||
|
|
||||||
|
@ -144,13 +142,12 @@ export function refreshUserToken() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return dispatch(obtainOAuthToken(params))
|
return dispatch(obtainOAuthToken(params))
|
||||||
.then(token => dispatch(authLoggedIn(token)));
|
.then((token: Record<string, string | number>) => dispatch(authLoggedIn(token)));
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function otpVerify(code, mfa_token) {
|
export const otpVerify = (code: string, mfa_token: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const app = getState().getIn(['auth', 'app']);
|
const app = getState().auth.get('app');
|
||||||
return api(getState, 'app').post('/oauth/mfa/challenge', {
|
return api(getState, 'app').post('/oauth/mfa/challenge', {
|
||||||
client_id: app.get('client_id'),
|
client_id: app.get('client_id'),
|
||||||
client_secret: app.get('client_secret'),
|
client_secret: app.get('client_secret'),
|
||||||
|
@ -161,18 +158,17 @@ export function otpVerify(code, mfa_token) {
|
||||||
scope: getScopes(getState()),
|
scope: getScopes(getState()),
|
||||||
}).then(({ data: token }) => dispatch(authLoggedIn(token)));
|
}).then(({ data: token }) => dispatch(authLoggedIn(token)));
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function verifyCredentials(token, accountUrl) {
|
export const verifyCredentials = (token: string, accountUrl?: string) => {
|
||||||
const baseURL = parseBaseURL(accountUrl);
|
const baseURL = parseBaseURL(accountUrl);
|
||||||
|
|
||||||
return (dispatch, getState) => {
|
return (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: VERIFY_CREDENTIALS_REQUEST, token });
|
dispatch({ type: VERIFY_CREDENTIALS_REQUEST, token });
|
||||||
|
|
||||||
return baseClient(token, baseURL).get('/api/v1/accounts/verify_credentials').then(({ data: account }) => {
|
return baseClient(token, baseURL).get('/api/v1/accounts/verify_credentials').then(({ data: account }) => {
|
||||||
dispatch(importFetchedAccount(account));
|
dispatch(importFetchedAccount(account));
|
||||||
dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account });
|
dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account });
|
||||||
if (account.id === getState().get('me')) dispatch(fetchMeSuccess(account));
|
if (account.id === getState().me) dispatch(fetchMeSuccess(account));
|
||||||
return account;
|
return account;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
if (error?.response?.status === 403 && error?.response?.data?.id) {
|
if (error?.response?.status === 403 && error?.response?.data?.id) {
|
||||||
|
@ -180,75 +176,64 @@ export function verifyCredentials(token, accountUrl) {
|
||||||
const account = error.response.data;
|
const account = error.response.data;
|
||||||
dispatch(importFetchedAccount(account));
|
dispatch(importFetchedAccount(account));
|
||||||
dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account });
|
dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account });
|
||||||
if (account.id === getState().get('me')) dispatch(fetchMeSuccess(account));
|
if (account.id === getState().me) dispatch(fetchMeSuccess(account));
|
||||||
return account;
|
return account;
|
||||||
} else {
|
} else {
|
||||||
if (getState().get('me') === null) dispatch(fetchMeFail(error));
|
if (getState().me === null) dispatch(fetchMeFail(error));
|
||||||
dispatch({ type: VERIFY_CREDENTIALS_FAIL, token, error, skipAlert: true });
|
dispatch({ type: VERIFY_CREDENTIALS_FAIL, token, error, skipAlert: true });
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function rememberAuthAccount(accountUrl) {
|
export const rememberAuthAccount = (accountUrl: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: AUTH_ACCOUNT_REMEMBER_REQUEST, accountUrl });
|
dispatch({ type: AUTH_ACCOUNT_REMEMBER_REQUEST, accountUrl });
|
||||||
return KVStore.getItemOrError(`authAccount:${accountUrl}`).then(account => {
|
return KVStore.getItemOrError(`authAccount:${accountUrl}`).then(account => {
|
||||||
dispatch(importFetchedAccount(account));
|
dispatch(importFetchedAccount(account));
|
||||||
dispatch({ type: AUTH_ACCOUNT_REMEMBER_SUCCESS, account, accountUrl });
|
dispatch({ type: AUTH_ACCOUNT_REMEMBER_SUCCESS, account, accountUrl });
|
||||||
if (account.id === getState().get('me')) dispatch(fetchMeSuccess(account));
|
if (account.id === getState().me) dispatch(fetchMeSuccess(account));
|
||||||
return account;
|
return account;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: AUTH_ACCOUNT_REMEMBER_FAIL, error, accountUrl, skipAlert: true });
|
dispatch({ type: AUTH_ACCOUNT_REMEMBER_FAIL, error, accountUrl, skipAlert: true });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function loadCredentials(token, accountUrl) {
|
export const loadCredentials = (token: string, accountUrl: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => dispatch(rememberAuthAccount(accountUrl))
|
||||||
return dispatch(rememberAuthAccount(accountUrl))
|
|
||||||
.then(account => account)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch(verifyCredentials(token, accountUrl));
|
dispatch(verifyCredentials(token, accountUrl));
|
||||||
})
|
})
|
||||||
.catch(error => dispatch(verifyCredentials(token, accountUrl)));
|
.catch(() => dispatch(verifyCredentials(token, accountUrl)));
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function logIn(intl, username, password) {
|
export const logIn = (username: string, password: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => dispatch(getAuthApp()).then(() => {
|
||||||
return dispatch(getAuthApp()).then(() => {
|
|
||||||
return dispatch(createUserToken(username, password));
|
return dispatch(createUserToken(username, password));
|
||||||
}).catch(error => {
|
}).catch((error: AxiosError) => {
|
||||||
if (error.response.data.error === 'mfa_required') {
|
if ((error.response?.data as any).error === 'mfa_required') {
|
||||||
// If MFA is required, throw the error and handle it in the component.
|
// If MFA is required, throw the error and handle it in the component.
|
||||||
throw error;
|
throw error;
|
||||||
} else if (error.response.data.error === 'invalid_grant') {
|
} else if ((error.response?.data as any).error === 'invalid_grant') {
|
||||||
// Mastodon returns this user-unfriendly error as a catch-all
|
// Mastodon returns this user-unfriendly error as a catch-all
|
||||||
// for everything from "bad request" to "wrong password".
|
// for everything from "bad request" to "wrong password".
|
||||||
// Assume our code is correct and it's a wrong password.
|
// Assume our code is correct and it's a wrong password.
|
||||||
dispatch(snackbar.error(intl.formatMessage(messages.invalidCredentials)));
|
dispatch(snackbar.error(messages.invalidCredentials));
|
||||||
} else if (error.response.data.error) {
|
} else if ((error.response?.data as any).error) {
|
||||||
// If the backend returns an error, display it.
|
// If the backend returns an error, display it.
|
||||||
dispatch(snackbar.error(error.response.data.error));
|
dispatch(snackbar.error((error.response?.data as any).error));
|
||||||
} else {
|
} else {
|
||||||
// Return "wrong password" message.
|
// Return "wrong password" message.
|
||||||
dispatch(snackbar.error(intl.formatMessage(messages.invalidCredentials)));
|
dispatch(snackbar.error(messages.invalidCredentials));
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteSession() {
|
export const deleteSession = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => api(getState).delete('/api/sign_out');
|
||||||
return api(getState).delete('/api/sign_out');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function logOut(intl) {
|
export const logOut = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const account = getLoggedInAccount(state);
|
const account = getLoggedInAccount(state);
|
||||||
const standalone = isStandalone(state);
|
const standalone = isStandalone(state);
|
||||||
|
@ -256,62 +241,54 @@ export function logOut(intl) {
|
||||||
if (!account) return dispatch(noOp);
|
if (!account) return dispatch(noOp);
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
client_id: state.getIn(['auth', 'app', 'client_id']),
|
client_id: state.auth.getIn(['app', 'client_id']),
|
||||||
client_secret: state.getIn(['auth', 'app', 'client_secret']),
|
client_secret: state.auth.getIn(['app', 'client_secret']),
|
||||||
token: state.getIn(['auth', 'users', account.url, 'access_token']),
|
token: state.auth.getIn(['users', account.url, 'access_token']),
|
||||||
};
|
};
|
||||||
|
|
||||||
return Promise.all([
|
return dispatch(revokeOAuthToken(params)).finally(() => {
|
||||||
dispatch(revokeOAuthToken(params)),
|
|
||||||
dispatch(deleteSession()),
|
|
||||||
]).finally(() => {
|
|
||||||
dispatch({ type: AUTH_LOGGED_OUT, account, standalone });
|
dispatch({ type: AUTH_LOGGED_OUT, account, standalone });
|
||||||
dispatch(snackbar.success(intl.formatMessage(messages.loggedOut)));
|
return dispatch(snackbar.success(messages.loggedOut));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function switchAccount(accountId, background = false) {
|
export const switchAccount = (accountId: string, background = false) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const account = getState().getIn(['accounts', accountId]);
|
const account = getState().accounts.get(accountId);
|
||||||
dispatch({ type: SWITCH_ACCOUNT, account, background });
|
return dispatch({ type: SWITCH_ACCOUNT, account, background });
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchOwnAccounts() {
|
export const fetchOwnAccounts = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
state.getIn(['auth', 'users']).forEach(user => {
|
return state.auth.get('users').forEach((user: ImmutableMap<string, string>) => {
|
||||||
const account = state.getIn(['accounts', user.get('id')]);
|
const account = state.accounts.get(user.get('id'));
|
||||||
if (!account) {
|
if (!account) {
|
||||||
dispatch(verifyCredentials(user.get('access_token'), user.get('url')));
|
dispatch(verifyCredentials(user.get('access_token')!, user.get('url')));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function register(params) {
|
|
||||||
return (dispatch, getState) => {
|
export const register = (params: Record<string, any>) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
params.fullname = params.username;
|
params.fullname = params.username;
|
||||||
|
|
||||||
return dispatch(createAppAndToken())
|
return dispatch(createAppAndToken())
|
||||||
.then(() => dispatch(createAccount(params)))
|
.then(() => dispatch(createAccount(params)))
|
||||||
.then(({ token }) => {
|
.then(({ token }: { token: Record<string, string | number> }) => {
|
||||||
dispatch(startOnboarding());
|
dispatch(startOnboarding());
|
||||||
return dispatch(authLoggedIn(token));
|
return dispatch(authLoggedIn(token));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchCaptcha() {
|
export const fetchCaptcha = () =>
|
||||||
return (dispatch, getState) => {
|
(_dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
return api(getState).get('/api/pleroma/captcha');
|
return api(getState).get('/api/pleroma/captcha');
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function authLoggedIn(token) {
|
export const authLoggedIn = (token: Record<string, string | number>) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => {
|
||||||
dispatch({ type: AUTH_LOGGED_IN, token });
|
dispatch({ type: AUTH_LOGGED_IN, token });
|
||||||
return token;
|
return token;
|
||||||
};
|
};
|
||||||
}
|
|
|
@ -1,5 +1,7 @@
|
||||||
import api from '../api';
|
import api from '../api';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
export const BACKUPS_FETCH_REQUEST = 'BACKUPS_FETCH_REQUEST';
|
export const BACKUPS_FETCH_REQUEST = 'BACKUPS_FETCH_REQUEST';
|
||||||
export const BACKUPS_FETCH_SUCCESS = 'BACKUPS_FETCH_SUCCESS';
|
export const BACKUPS_FETCH_SUCCESS = 'BACKUPS_FETCH_SUCCESS';
|
||||||
export const BACKUPS_FETCH_FAIL = 'BACKUPS_FETCH_FAIL';
|
export const BACKUPS_FETCH_FAIL = 'BACKUPS_FETCH_FAIL';
|
||||||
|
@ -8,24 +10,22 @@ export const BACKUPS_CREATE_REQUEST = 'BACKUPS_CREATE_REQUEST';
|
||||||
export const BACKUPS_CREATE_SUCCESS = 'BACKUPS_CREATE_SUCCESS';
|
export const BACKUPS_CREATE_SUCCESS = 'BACKUPS_CREATE_SUCCESS';
|
||||||
export const BACKUPS_CREATE_FAIL = 'BACKUPS_CREATE_FAIL';
|
export const BACKUPS_CREATE_FAIL = 'BACKUPS_CREATE_FAIL';
|
||||||
|
|
||||||
export function fetchBackups() {
|
export const fetchBackups = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: BACKUPS_FETCH_REQUEST });
|
dispatch({ type: BACKUPS_FETCH_REQUEST });
|
||||||
return api(getState).get('/api/v1/pleroma/backups').then(({ data: backups }) => {
|
return api(getState).get('/api/v1/pleroma/backups').then(({ data: backups }) =>
|
||||||
dispatch({ type: BACKUPS_FETCH_SUCCESS, backups });
|
dispatch({ type: BACKUPS_FETCH_SUCCESS, backups }),
|
||||||
}).catch(error => {
|
).catch(error => {
|
||||||
dispatch({ type: BACKUPS_FETCH_FAIL, error });
|
dispatch({ type: BACKUPS_FETCH_FAIL, error });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function createBackup() {
|
export const createBackup = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: BACKUPS_CREATE_REQUEST });
|
dispatch({ type: BACKUPS_CREATE_REQUEST });
|
||||||
return api(getState).post('/api/v1/pleroma/backups').then(({ data: backups }) => {
|
return api(getState).post('/api/v1/pleroma/backups').then(({ data: backups }) =>
|
||||||
dispatch({ type: BACKUPS_CREATE_SUCCESS, backups });
|
dispatch({ type: BACKUPS_CREATE_SUCCESS, backups }),
|
||||||
}).catch(error => {
|
).catch(error => {
|
||||||
dispatch({ type: BACKUPS_CREATE_FAIL, error });
|
dispatch({ type: BACKUPS_CREATE_FAIL, error });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
|
@ -1,6 +1,3 @@
|
||||||
import { AnyAction } from '@reduxjs/toolkit';
|
|
||||||
import { AxiosError } from 'axios';
|
|
||||||
|
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
import { getNextLinkName } from 'soapbox/utils/quirks';
|
import { getNextLinkName } from 'soapbox/utils/quirks';
|
||||||
|
|
||||||
|
@ -9,6 +6,10 @@ import api, { getLinks } from '../api';
|
||||||
import { fetchRelationships } from './accounts';
|
import { fetchRelationships } from './accounts';
|
||||||
import { importFetchedAccounts } from './importer';
|
import { importFetchedAccounts } from './importer';
|
||||||
|
|
||||||
|
import type { AnyAction } from '@reduxjs/toolkit';
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { RootState } from 'soapbox/store';
|
||||||
|
|
||||||
const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST';
|
const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST';
|
||||||
const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS';
|
const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS';
|
||||||
const BLOCKS_FETCH_FAIL = 'BLOCKS_FETCH_FAIL';
|
const BLOCKS_FETCH_FAIL = 'BLOCKS_FETCH_FAIL';
|
||||||
|
@ -17,7 +18,7 @@ const BLOCKS_EXPAND_REQUEST = 'BLOCKS_EXPAND_REQUEST';
|
||||||
const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS';
|
const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS';
|
||||||
const BLOCKS_EXPAND_FAIL = 'BLOCKS_EXPAND_FAIL';
|
const BLOCKS_EXPAND_FAIL = 'BLOCKS_EXPAND_FAIL';
|
||||||
|
|
||||||
const fetchBlocks = () => (dispatch: React.Dispatch<AnyAction>, getState: any) => {
|
const fetchBlocks = () => (dispatch: React.Dispatch<AnyAction>, getState: () => RootState) => {
|
||||||
if (!isLoggedIn(getState)) return null;
|
if (!isLoggedIn(getState)) return null;
|
||||||
const nextLinkName = getNextLinkName(getState);
|
const nextLinkName = getNextLinkName(getState);
|
||||||
|
|
||||||
|
@ -53,11 +54,11 @@ function fetchBlocksFail(error: AxiosError) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const expandBlocks = () => (dispatch: React.Dispatch<AnyAction>, getState: any) => {
|
const expandBlocks = () => (dispatch: React.Dispatch<AnyAction>, getState: () => RootState) => {
|
||||||
if (!isLoggedIn(getState)) return null;
|
if (!isLoggedIn(getState)) return null;
|
||||||
const nextLinkName = getNextLinkName(getState);
|
const nextLinkName = getNextLinkName(getState);
|
||||||
|
|
||||||
const url = getState().getIn(['user_lists', 'blocks', 'next']);
|
const url = getState().user_lists.getIn(['blocks', 'next']);
|
||||||
|
|
||||||
if (url === null) {
|
if (url === null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
import api, { getLinks } from '../api';
|
|
||||||
|
|
||||||
import { importFetchedStatuses } from './importer';
|
|
||||||
|
|
||||||
export const BOOKMARKED_STATUSES_FETCH_REQUEST = 'BOOKMARKED_STATUSES_FETCH_REQUEST';
|
|
||||||
export const BOOKMARKED_STATUSES_FETCH_SUCCESS = 'BOOKMARKED_STATUSES_FETCH_SUCCESS';
|
|
||||||
export const BOOKMARKED_STATUSES_FETCH_FAIL = 'BOOKMARKED_STATUSES_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const BOOKMARKED_STATUSES_EXPAND_REQUEST = 'BOOKMARKED_STATUSES_EXPAND_REQUEST';
|
|
||||||
export const BOOKMARKED_STATUSES_EXPAND_SUCCESS = 'BOOKMARKED_STATUSES_EXPAND_SUCCESS';
|
|
||||||
export const BOOKMARKED_STATUSES_EXPAND_FAIL = 'BOOKMARKED_STATUSES_EXPAND_FAIL';
|
|
||||||
|
|
||||||
const noOp = () => new Promise(f => f());
|
|
||||||
|
|
||||||
export function fetchBookmarkedStatuses() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) {
|
|
||||||
return dispatch(noOp);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchBookmarkedStatusesRequest());
|
|
||||||
|
|
||||||
return api(getState).get('/api/v1/bookmarks').then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedStatuses(response.data));
|
|
||||||
dispatch(fetchBookmarkedStatusesSuccess(response.data, next ? next.uri : null));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchBookmarkedStatusesFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchBookmarkedStatusesRequest() {
|
|
||||||
return {
|
|
||||||
type: BOOKMARKED_STATUSES_FETCH_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchBookmarkedStatusesSuccess(statuses, next) {
|
|
||||||
return {
|
|
||||||
type: BOOKMARKED_STATUSES_FETCH_SUCCESS,
|
|
||||||
statuses,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchBookmarkedStatusesFail(error) {
|
|
||||||
return {
|
|
||||||
type: BOOKMARKED_STATUSES_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandBookmarkedStatuses() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const url = getState().getIn(['status_lists', 'bookmarks', 'next'], null);
|
|
||||||
|
|
||||||
if (url === null || getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) {
|
|
||||||
return dispatch(noOp);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandBookmarkedStatusesRequest());
|
|
||||||
|
|
||||||
return api(getState).get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedStatuses(response.data));
|
|
||||||
dispatch(expandBookmarkedStatusesSuccess(response.data, next ? next.uri : null));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(expandBookmarkedStatusesFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandBookmarkedStatusesRequest() {
|
|
||||||
return {
|
|
||||||
type: BOOKMARKED_STATUSES_EXPAND_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandBookmarkedStatusesSuccess(statuses, next) {
|
|
||||||
return {
|
|
||||||
type: BOOKMARKED_STATUSES_EXPAND_SUCCESS,
|
|
||||||
statuses,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandBookmarkedStatusesFail(error) {
|
|
||||||
return {
|
|
||||||
type: BOOKMARKED_STATUSES_EXPAND_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
|
import { importFetchedStatuses } from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const BOOKMARKED_STATUSES_FETCH_REQUEST = 'BOOKMARKED_STATUSES_FETCH_REQUEST';
|
||||||
|
const BOOKMARKED_STATUSES_FETCH_SUCCESS = 'BOOKMARKED_STATUSES_FETCH_SUCCESS';
|
||||||
|
const BOOKMARKED_STATUSES_FETCH_FAIL = 'BOOKMARKED_STATUSES_FETCH_FAIL';
|
||||||
|
|
||||||
|
const BOOKMARKED_STATUSES_EXPAND_REQUEST = 'BOOKMARKED_STATUSES_EXPAND_REQUEST';
|
||||||
|
const BOOKMARKED_STATUSES_EXPAND_SUCCESS = 'BOOKMARKED_STATUSES_EXPAND_SUCCESS';
|
||||||
|
const BOOKMARKED_STATUSES_EXPAND_FAIL = 'BOOKMARKED_STATUSES_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const noOp = () => new Promise(f => f(undefined));
|
||||||
|
|
||||||
|
const fetchBookmarkedStatuses = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (getState().status_lists.get('bookmarks')?.isLoading) {
|
||||||
|
return dispatch(noOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchBookmarkedStatusesRequest());
|
||||||
|
|
||||||
|
return api(getState).get('/api/v1/bookmarks').then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
return dispatch(fetchBookmarkedStatusesSuccess(response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchBookmarkedStatusesFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchBookmarkedStatusesRequest = () => ({
|
||||||
|
type: BOOKMARKED_STATUSES_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchBookmarkedStatusesSuccess = (statuses: APIEntity[], next: string | null) => ({
|
||||||
|
type: BOOKMARKED_STATUSES_FETCH_SUCCESS,
|
||||||
|
statuses,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchBookmarkedStatusesFail = (error: AxiosError) => ({
|
||||||
|
type: BOOKMARKED_STATUSES_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandBookmarkedStatuses = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const url = getState().status_lists.get('bookmarks')?.next || null;
|
||||||
|
|
||||||
|
if (url === null || getState().status_lists.get('bookmarks')?.isLoading) {
|
||||||
|
return dispatch(noOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandBookmarkedStatusesRequest());
|
||||||
|
|
||||||
|
return api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
return dispatch(expandBookmarkedStatusesSuccess(response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandBookmarkedStatusesFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandBookmarkedStatusesRequest = () => ({
|
||||||
|
type: BOOKMARKED_STATUSES_EXPAND_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandBookmarkedStatusesSuccess = (statuses: APIEntity[], next: string | null) => ({
|
||||||
|
type: BOOKMARKED_STATUSES_EXPAND_SUCCESS,
|
||||||
|
statuses,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandBookmarkedStatusesFail = (error: AxiosError) => ({
|
||||||
|
type: BOOKMARKED_STATUSES_EXPAND_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
BOOKMARKED_STATUSES_FETCH_REQUEST,
|
||||||
|
BOOKMARKED_STATUSES_FETCH_SUCCESS,
|
||||||
|
BOOKMARKED_STATUSES_FETCH_FAIL,
|
||||||
|
BOOKMARKED_STATUSES_EXPAND_REQUEST,
|
||||||
|
BOOKMARKED_STATUSES_EXPAND_SUCCESS,
|
||||||
|
BOOKMARKED_STATUSES_EXPAND_FAIL,
|
||||||
|
fetchBookmarkedStatuses,
|
||||||
|
fetchBookmarkedStatusesRequest,
|
||||||
|
fetchBookmarkedStatusesSuccess,
|
||||||
|
fetchBookmarkedStatusesFail,
|
||||||
|
expandBookmarkedStatuses,
|
||||||
|
expandBookmarkedStatusesRequest,
|
||||||
|
expandBookmarkedStatusesSuccess,
|
||||||
|
expandBookmarkedStatusesFail,
|
||||||
|
};
|
|
@ -1,25 +0,0 @@
|
||||||
export const BUNDLE_FETCH_REQUEST = 'BUNDLE_FETCH_REQUEST';
|
|
||||||
export const BUNDLE_FETCH_SUCCESS = 'BUNDLE_FETCH_SUCCESS';
|
|
||||||
export const BUNDLE_FETCH_FAIL = 'BUNDLE_FETCH_FAIL';
|
|
||||||
|
|
||||||
export function fetchBundleRequest(skipLoading) {
|
|
||||||
return {
|
|
||||||
type: BUNDLE_FETCH_REQUEST,
|
|
||||||
skipLoading,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchBundleSuccess(skipLoading) {
|
|
||||||
return {
|
|
||||||
type: BUNDLE_FETCH_SUCCESS,
|
|
||||||
skipLoading,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchBundleFail(error, skipLoading) {
|
|
||||||
return {
|
|
||||||
type: BUNDLE_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
skipLoading,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
const BUNDLE_FETCH_REQUEST = 'BUNDLE_FETCH_REQUEST';
|
||||||
|
const BUNDLE_FETCH_SUCCESS = 'BUNDLE_FETCH_SUCCESS';
|
||||||
|
const BUNDLE_FETCH_FAIL = 'BUNDLE_FETCH_FAIL';
|
||||||
|
|
||||||
|
const fetchBundleRequest = (skipLoading?: boolean) => ({
|
||||||
|
type: BUNDLE_FETCH_REQUEST,
|
||||||
|
skipLoading,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchBundleSuccess = (skipLoading?: boolean) => ({
|
||||||
|
type: BUNDLE_FETCH_SUCCESS,
|
||||||
|
skipLoading,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchBundleFail = (error: any, skipLoading?: boolean) => ({
|
||||||
|
type: BUNDLE_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
skipLoading,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
BUNDLE_FETCH_REQUEST,
|
||||||
|
BUNDLE_FETCH_SUCCESS,
|
||||||
|
BUNDLE_FETCH_FAIL,
|
||||||
|
fetchBundleRequest,
|
||||||
|
fetchBundleSuccess,
|
||||||
|
fetchBundleFail,
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { getSettings, changeSetting } from 'soapbox/actions/settings';
|
import { getSettings, changeSetting } from 'soapbox/actions/settings';
|
||||||
|
@ -6,47 +6,49 @@ import { getFeatures } from 'soapbox/utils/features';
|
||||||
|
|
||||||
import api, { getLinks } from '../api';
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
export const CHATS_FETCH_REQUEST = 'CHATS_FETCH_REQUEST';
|
import type { History } from 'history';
|
||||||
export const CHATS_FETCH_SUCCESS = 'CHATS_FETCH_SUCCESS';
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
export const CHATS_FETCH_FAIL = 'CHATS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const CHATS_EXPAND_REQUEST = 'CHATS_EXPAND_REQUEST';
|
const CHATS_FETCH_REQUEST = 'CHATS_FETCH_REQUEST';
|
||||||
export const CHATS_EXPAND_SUCCESS = 'CHATS_EXPAND_SUCCESS';
|
const CHATS_FETCH_SUCCESS = 'CHATS_FETCH_SUCCESS';
|
||||||
export const CHATS_EXPAND_FAIL = 'CHATS_EXPAND_FAIL';
|
const CHATS_FETCH_FAIL = 'CHATS_FETCH_FAIL';
|
||||||
|
|
||||||
export const CHAT_MESSAGES_FETCH_REQUEST = 'CHAT_MESSAGES_FETCH_REQUEST';
|
const CHATS_EXPAND_REQUEST = 'CHATS_EXPAND_REQUEST';
|
||||||
export const CHAT_MESSAGES_FETCH_SUCCESS = 'CHAT_MESSAGES_FETCH_SUCCESS';
|
const CHATS_EXPAND_SUCCESS = 'CHATS_EXPAND_SUCCESS';
|
||||||
export const CHAT_MESSAGES_FETCH_FAIL = 'CHAT_MESSAGES_FETCH_FAIL';
|
const CHATS_EXPAND_FAIL = 'CHATS_EXPAND_FAIL';
|
||||||
|
|
||||||
export const CHAT_MESSAGE_SEND_REQUEST = 'CHAT_MESSAGE_SEND_REQUEST';
|
const CHAT_MESSAGES_FETCH_REQUEST = 'CHAT_MESSAGES_FETCH_REQUEST';
|
||||||
export const CHAT_MESSAGE_SEND_SUCCESS = 'CHAT_MESSAGE_SEND_SUCCESS';
|
const CHAT_MESSAGES_FETCH_SUCCESS = 'CHAT_MESSAGES_FETCH_SUCCESS';
|
||||||
export const CHAT_MESSAGE_SEND_FAIL = 'CHAT_MESSAGE_SEND_FAIL';
|
const CHAT_MESSAGES_FETCH_FAIL = 'CHAT_MESSAGES_FETCH_FAIL';
|
||||||
|
|
||||||
export const CHAT_FETCH_REQUEST = 'CHAT_FETCH_REQUEST';
|
const CHAT_MESSAGE_SEND_REQUEST = 'CHAT_MESSAGE_SEND_REQUEST';
|
||||||
export const CHAT_FETCH_SUCCESS = 'CHAT_FETCH_SUCCESS';
|
const CHAT_MESSAGE_SEND_SUCCESS = 'CHAT_MESSAGE_SEND_SUCCESS';
|
||||||
export const CHAT_FETCH_FAIL = 'CHAT_FETCH_FAIL';
|
const CHAT_MESSAGE_SEND_FAIL = 'CHAT_MESSAGE_SEND_FAIL';
|
||||||
|
|
||||||
export const CHAT_READ_REQUEST = 'CHAT_READ_REQUEST';
|
const CHAT_FETCH_REQUEST = 'CHAT_FETCH_REQUEST';
|
||||||
export const CHAT_READ_SUCCESS = 'CHAT_READ_SUCCESS';
|
const CHAT_FETCH_SUCCESS = 'CHAT_FETCH_SUCCESS';
|
||||||
export const CHAT_READ_FAIL = 'CHAT_READ_FAIL';
|
const CHAT_FETCH_FAIL = 'CHAT_FETCH_FAIL';
|
||||||
|
|
||||||
export const CHAT_MESSAGE_DELETE_REQUEST = 'CHAT_MESSAGE_DELETE_REQUEST';
|
const CHAT_READ_REQUEST = 'CHAT_READ_REQUEST';
|
||||||
export const CHAT_MESSAGE_DELETE_SUCCESS = 'CHAT_MESSAGE_DELETE_SUCCESS';
|
const CHAT_READ_SUCCESS = 'CHAT_READ_SUCCESS';
|
||||||
export const CHAT_MESSAGE_DELETE_FAIL = 'CHAT_MESSAGE_DELETE_FAIL';
|
const CHAT_READ_FAIL = 'CHAT_READ_FAIL';
|
||||||
|
|
||||||
export function fetchChatsV1() {
|
const CHAT_MESSAGE_DELETE_REQUEST = 'CHAT_MESSAGE_DELETE_REQUEST';
|
||||||
return (dispatch, getState) =>
|
const CHAT_MESSAGE_DELETE_SUCCESS = 'CHAT_MESSAGE_DELETE_SUCCESS';
|
||||||
|
const CHAT_MESSAGE_DELETE_FAIL = 'CHAT_MESSAGE_DELETE_FAIL';
|
||||||
|
|
||||||
|
const fetchChatsV1 = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
api(getState).get('/api/v1/pleroma/chats').then((response) => {
|
api(getState).get('/api/v1/pleroma/chats').then((response) => {
|
||||||
dispatch({ type: CHATS_FETCH_SUCCESS, chats: response.data });
|
dispatch({ type: CHATS_FETCH_SUCCESS, chats: response.data });
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: CHATS_FETCH_FAIL, error });
|
dispatch({ type: CHATS_FETCH_FAIL, error });
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchChatsV2() {
|
const fetchChatsV2 = () =>
|
||||||
return (dispatch, getState) =>
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
api(getState).get('/api/v2/pleroma/chats').then((response) => {
|
api(getState).get('/api/v2/pleroma/chats').then((response) => {
|
||||||
let next = getLinks(response).refs.find(link => link.rel === 'next');
|
let next: { uri: string } | undefined = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
|
||||||
if (!next && response.data.length) {
|
if (!next && response.data.length) {
|
||||||
next = { uri: `/api/v2/pleroma/chats?max_id=${response.data[response.data.length - 1].id}&offset=0` };
|
next = { uri: `/api/v2/pleroma/chats?max_id=${response.data[response.data.length - 1].id}&offset=0` };
|
||||||
|
@ -56,10 +58,9 @@ export function fetchChatsV2() {
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: CHATS_FETCH_FAIL, error });
|
dispatch({ type: CHATS_FETCH_FAIL, error });
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchChats() {
|
const fetchChats = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const { instance } = state;
|
const { instance } = state;
|
||||||
const features = getFeatures(instance);
|
const features = getFeatures(instance);
|
||||||
|
@ -71,11 +72,10 @@ export function fetchChats() {
|
||||||
return dispatch(fetchChatsV1());
|
return dispatch(fetchChatsV1());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function expandChats() {
|
const expandChats = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const url = getState().getIn(['chats', 'next']);
|
const url = getState().chats.next;
|
||||||
|
|
||||||
if (url === null) {
|
if (url === null) {
|
||||||
return;
|
return;
|
||||||
|
@ -90,10 +90,9 @@ export function expandChats() {
|
||||||
dispatch({ type: CHATS_EXPAND_FAIL, error });
|
dispatch({ type: CHATS_EXPAND_FAIL, error });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchChatMessages(chatId, maxId = null) {
|
const fetchChatMessages = (chatId: string, maxId: string | null = null) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: CHAT_MESSAGES_FETCH_REQUEST, chatId, maxId });
|
dispatch({ type: CHAT_MESSAGES_FETCH_REQUEST, chatId, maxId });
|
||||||
return api(getState).get(`/api/v1/pleroma/chats/${chatId}/messages`, { params: { max_id: maxId } }).then(({ data }) => {
|
return api(getState).get(`/api/v1/pleroma/chats/${chatId}/messages`, { params: { max_id: maxId } }).then(({ data }) => {
|
||||||
dispatch({ type: CHAT_MESSAGES_FETCH_SUCCESS, chatId, maxId, chatMessages: data });
|
dispatch({ type: CHAT_MESSAGES_FETCH_SUCCESS, chatId, maxId, chatMessages: data });
|
||||||
|
@ -101,12 +100,11 @@ export function fetchChatMessages(chatId, maxId = null) {
|
||||||
dispatch({ type: CHAT_MESSAGES_FETCH_FAIL, chatId, maxId, error });
|
dispatch({ type: CHAT_MESSAGES_FETCH_FAIL, chatId, maxId, error });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function sendChatMessage(chatId, params) {
|
const sendChatMessage = (chatId: string, params: Record<string, any>) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const uuid = `末_${Date.now()}_${uuidv4()}`;
|
const uuid = `末_${Date.now()}_${uuidv4()}`;
|
||||||
const me = getState().get('me');
|
const me = getState().me;
|
||||||
dispatch({ type: CHAT_MESSAGE_SEND_REQUEST, chatId, params, uuid, me });
|
dispatch({ type: CHAT_MESSAGE_SEND_REQUEST, chatId, params, uuid, me });
|
||||||
return api(getState).post(`/api/v1/pleroma/chats/${chatId}/messages`, params).then(({ data }) => {
|
return api(getState).post(`/api/v1/pleroma/chats/${chatId}/messages`, params).then(({ data }) => {
|
||||||
dispatch({ type: CHAT_MESSAGE_SEND_SUCCESS, chatId, chatMessage: data, uuid });
|
dispatch({ type: CHAT_MESSAGE_SEND_SUCCESS, chatId, chatMessage: data, uuid });
|
||||||
|
@ -114,28 +112,26 @@ export function sendChatMessage(chatId, params) {
|
||||||
dispatch({ type: CHAT_MESSAGE_SEND_FAIL, chatId, error, uuid });
|
dispatch({ type: CHAT_MESSAGE_SEND_FAIL, chatId, error, uuid });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function openChat(chatId) {
|
const openChat = (chatId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const panes = getSettings(state).getIn(['chats', 'panes']);
|
const panes = getSettings(state).getIn(['chats', 'panes']) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
const idx = panes.findIndex(pane => pane.get('chat_id') === chatId);
|
const idx = panes.findIndex(pane => pane.get('chat_id') === chatId);
|
||||||
|
|
||||||
dispatch(markChatRead(chatId));
|
dispatch(markChatRead(chatId));
|
||||||
|
|
||||||
if (idx > -1) {
|
if (idx > -1) {
|
||||||
return dispatch(changeSetting(['chats', 'panes', idx, 'state'], 'open'));
|
return dispatch(changeSetting(['chats', 'panes', idx as any, 'state'], 'open'));
|
||||||
} else {
|
} else {
|
||||||
const newPane = ImmutableMap({ chat_id: chatId, state: 'open' });
|
const newPane = ImmutableMap({ chat_id: chatId, state: 'open' });
|
||||||
return dispatch(changeSetting(['chats', 'panes'], panes.push(newPane)));
|
return dispatch(changeSetting(['chats', 'panes'], panes.push(newPane)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function closeChat(chatId) {
|
const closeChat = (chatId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const panes = getSettings(getState()).getIn(['chats', 'panes']);
|
const panes = getSettings(getState()).getIn(['chats', 'panes']) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
const idx = panes.findIndex(pane => pane.get('chat_id') === chatId);
|
const idx = panes.findIndex(pane => pane.get('chat_id') === chatId);
|
||||||
|
|
||||||
if (idx > -1) {
|
if (idx > -1) {
|
||||||
|
@ -144,33 +140,30 @@ export function closeChat(chatId) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleChat(chatId) {
|
const toggleChat = (chatId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const panes = getSettings(getState()).getIn(['chats', 'panes']);
|
const panes = getSettings(getState()).getIn(['chats', 'panes']) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
const [idx, pane] = panes.findEntry(pane => pane.get('chat_id') === chatId);
|
const [idx, pane] = panes.findEntry(pane => pane.get('chat_id') === chatId)!;
|
||||||
|
|
||||||
if (idx > -1) {
|
if (idx > -1) {
|
||||||
const state = pane.get('state') === 'minimized' ? 'open' : 'minimized';
|
const state = pane.get('state') === 'minimized' ? 'open' : 'minimized';
|
||||||
if (state === 'open') dispatch(markChatRead(chatId));
|
if (state === 'open') dispatch(markChatRead(chatId));
|
||||||
return dispatch(changeSetting(['chats', 'panes', idx, 'state'], state));
|
return dispatch(changeSetting(['chats', 'panes', idx as any, 'state'], state));
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleMainWindow() {
|
const toggleMainWindow = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const main = getSettings(getState()).getIn(['chats', 'mainWindow']);
|
const main = getSettings(getState()).getIn(['chats', 'mainWindow']) as 'minimized' | 'open';
|
||||||
const state = main === 'minimized' ? 'open' : 'minimized';
|
const state = main === 'minimized' ? 'open' : 'minimized';
|
||||||
return dispatch(changeSetting(['chats', 'mainWindow'], state));
|
return dispatch(changeSetting(['chats', 'mainWindow'], state));
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchChat(chatId) {
|
const fetchChat = (chatId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: CHAT_FETCH_REQUEST, chatId });
|
dispatch({ type: CHAT_FETCH_REQUEST, chatId });
|
||||||
return api(getState).get(`/api/v1/pleroma/chats/${chatId}`).then(({ data }) => {
|
return api(getState).get(`/api/v1/pleroma/chats/${chatId}`).then(({ data }) => {
|
||||||
dispatch({ type: CHAT_FETCH_SUCCESS, chat: data });
|
dispatch({ type: CHAT_FETCH_SUCCESS, chat: data });
|
||||||
|
@ -178,10 +171,9 @@ export function fetchChat(chatId) {
|
||||||
dispatch({ type: CHAT_FETCH_FAIL, chatId, error });
|
dispatch({ type: CHAT_FETCH_FAIL, chatId, error });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function startChat(accountId) {
|
const startChat = (accountId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: CHAT_FETCH_REQUEST, accountId });
|
dispatch({ type: CHAT_FETCH_REQUEST, accountId });
|
||||||
return api(getState).post(`/api/v1/pleroma/chats/by-account-id/${accountId}`).then(({ data }) => {
|
return api(getState).post(`/api/v1/pleroma/chats/by-account-id/${accountId}`).then(({ data }) => {
|
||||||
dispatch({ type: CHAT_FETCH_SUCCESS, chat: data });
|
dispatch({ type: CHAT_FETCH_SUCCESS, chat: data });
|
||||||
|
@ -190,12 +182,11 @@ export function startChat(accountId) {
|
||||||
dispatch({ type: CHAT_FETCH_FAIL, accountId, error });
|
dispatch({ type: CHAT_FETCH_FAIL, accountId, error });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function markChatRead(chatId, lastReadId) {
|
const markChatRead = (chatId: string, lastReadId?: string | null) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const chat = getState().getIn(['chats', 'items', chatId]);
|
const chat = getState().chats.items.get(chatId)!;
|
||||||
if (!lastReadId) lastReadId = chat.get('last_message');
|
if (!lastReadId) lastReadId = chat.last_message;
|
||||||
|
|
||||||
if (chat.get('unread') < 1) return;
|
if (chat.get('unread') < 1) return;
|
||||||
if (!lastReadId) return;
|
if (!lastReadId) return;
|
||||||
|
@ -207,10 +198,9 @@ export function markChatRead(chatId, lastReadId) {
|
||||||
dispatch({ type: CHAT_READ_FAIL, chatId, error, lastReadId });
|
dispatch({ type: CHAT_READ_FAIL, chatId, error, lastReadId });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteChatMessage(chatId, messageId) {
|
const deleteChatMessage = (chatId: string, messageId: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
dispatch({ type: CHAT_MESSAGE_DELETE_REQUEST, chatId, messageId });
|
dispatch({ type: CHAT_MESSAGE_DELETE_REQUEST, chatId, messageId });
|
||||||
api(getState).delete(`/api/v1/pleroma/chats/${chatId}/messages/${messageId}`).then(({ data }) => {
|
api(getState).delete(`/api/v1/pleroma/chats/${chatId}/messages/${messageId}`).then(({ data }) => {
|
||||||
dispatch({ type: CHAT_MESSAGE_DELETE_SUCCESS, chatId, messageId, chatMessage: data });
|
dispatch({ type: CHAT_MESSAGE_DELETE_SUCCESS, chatId, messageId, chatMessage: data });
|
||||||
|
@ -218,13 +208,12 @@ export function deleteChatMessage(chatId, messageId) {
|
||||||
dispatch({ type: CHAT_MESSAGE_DELETE_FAIL, chatId, messageId, error });
|
dispatch({ type: CHAT_MESSAGE_DELETE_FAIL, chatId, messageId, error });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/** Start a chat and launch it in the UI */
|
/** Start a chat and launch it in the UI */
|
||||||
export function launchChat(accountId, router, forceNavigate = false) {
|
const launchChat = (accountId: string, router: History, forceNavigate = false) => {
|
||||||
const isMobile = width => width <= 1190;
|
const isMobile = (width: number) => width <= 1190;
|
||||||
|
|
||||||
return (dispatch, getState) => {
|
return (dispatch: AppDispatch) => {
|
||||||
// TODO: make this faster
|
// TODO: make this faster
|
||||||
return dispatch(startChat(accountId)).then(chat => {
|
return dispatch(startChat(accountId)).then(chat => {
|
||||||
if (forceNavigate || isMobile(window.innerWidth)) {
|
if (forceNavigate || isMobile(window.innerWidth)) {
|
||||||
|
@ -234,4 +223,43 @@ export function launchChat(accountId, router, forceNavigate = false) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
CHATS_FETCH_REQUEST,
|
||||||
|
CHATS_FETCH_SUCCESS,
|
||||||
|
CHATS_FETCH_FAIL,
|
||||||
|
CHATS_EXPAND_REQUEST,
|
||||||
|
CHATS_EXPAND_SUCCESS,
|
||||||
|
CHATS_EXPAND_FAIL,
|
||||||
|
CHAT_MESSAGES_FETCH_REQUEST,
|
||||||
|
CHAT_MESSAGES_FETCH_SUCCESS,
|
||||||
|
CHAT_MESSAGES_FETCH_FAIL,
|
||||||
|
CHAT_MESSAGE_SEND_REQUEST,
|
||||||
|
CHAT_MESSAGE_SEND_SUCCESS,
|
||||||
|
CHAT_MESSAGE_SEND_FAIL,
|
||||||
|
CHAT_FETCH_REQUEST,
|
||||||
|
CHAT_FETCH_SUCCESS,
|
||||||
|
CHAT_FETCH_FAIL,
|
||||||
|
CHAT_READ_REQUEST,
|
||||||
|
CHAT_READ_SUCCESS,
|
||||||
|
CHAT_READ_FAIL,
|
||||||
|
CHAT_MESSAGE_DELETE_REQUEST,
|
||||||
|
CHAT_MESSAGE_DELETE_SUCCESS,
|
||||||
|
CHAT_MESSAGE_DELETE_FAIL,
|
||||||
|
fetchChatsV1,
|
||||||
|
fetchChatsV2,
|
||||||
|
fetchChats,
|
||||||
|
expandChats,
|
||||||
|
fetchChatMessages,
|
||||||
|
sendChatMessage,
|
||||||
|
openChat,
|
||||||
|
closeChat,
|
||||||
|
toggleChat,
|
||||||
|
toggleMainWindow,
|
||||||
|
fetchChat,
|
||||||
|
startChat,
|
||||||
|
markChatRead,
|
||||||
|
deleteChatMessage,
|
||||||
|
launchChat,
|
||||||
|
};
|
|
@ -1,760 +0,0 @@
|
||||||
import { CancelToken, isCancel } from 'axios';
|
|
||||||
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
|
||||||
import { throttle } from 'lodash';
|
|
||||||
import { defineMessages } from 'react-intl';
|
|
||||||
|
|
||||||
import snackbar from 'soapbox/actions/snackbar';
|
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
import { getFeatures, parseVersion } from 'soapbox/utils/features';
|
|
||||||
import { formatBytes } from 'soapbox/utils/media';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';
|
|
||||||
import { tagHistory } from '../settings';
|
|
||||||
import resizeImage from '../utils/resize_image';
|
|
||||||
|
|
||||||
import { showAlert, showAlertForError } from './alerts';
|
|
||||||
import { useEmoji } from './emojis';
|
|
||||||
import { importFetchedAccounts } from './importer';
|
|
||||||
import { uploadMedia, fetchMedia, updateMedia } from './media';
|
|
||||||
import { openModal, closeModal } from './modals';
|
|
||||||
import { getSettings } from './settings';
|
|
||||||
import { createStatus } from './statuses';
|
|
||||||
|
|
||||||
let cancelFetchComposeSuggestionsAccounts;
|
|
||||||
|
|
||||||
export const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
|
|
||||||
export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
|
|
||||||
export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
|
|
||||||
export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
|
|
||||||
export const COMPOSE_REPLY = 'COMPOSE_REPLY';
|
|
||||||
export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
|
|
||||||
export const COMPOSE_QUOTE = 'COMPOSE_QUOTE';
|
|
||||||
export const COMPOSE_QUOTE_CANCEL = 'COMPOSE_QUOTE_CANCEL';
|
|
||||||
export const COMPOSE_DIRECT = 'COMPOSE_DIRECT';
|
|
||||||
export const COMPOSE_MENTION = 'COMPOSE_MENTION';
|
|
||||||
export const COMPOSE_RESET = 'COMPOSE_RESET';
|
|
||||||
export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST';
|
|
||||||
export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS';
|
|
||||||
export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL';
|
|
||||||
export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS';
|
|
||||||
export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO';
|
|
||||||
|
|
||||||
export const COMPOSE_SUGGESTIONS_CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR';
|
|
||||||
export const COMPOSE_SUGGESTIONS_READY = 'COMPOSE_SUGGESTIONS_READY';
|
|
||||||
export const COMPOSE_SUGGESTION_SELECT = 'COMPOSE_SUGGESTION_SELECT';
|
|
||||||
export const COMPOSE_SUGGESTION_TAGS_UPDATE = 'COMPOSE_SUGGESTION_TAGS_UPDATE';
|
|
||||||
|
|
||||||
export const COMPOSE_TAG_HISTORY_UPDATE = 'COMPOSE_TAG_HISTORY_UPDATE';
|
|
||||||
|
|
||||||
export const COMPOSE_MOUNT = 'COMPOSE_MOUNT';
|
|
||||||
export const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT';
|
|
||||||
|
|
||||||
export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE';
|
|
||||||
export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE';
|
|
||||||
export const COMPOSE_TYPE_CHANGE = 'COMPOSE_TYPE_CHANGE';
|
|
||||||
export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
|
|
||||||
export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
|
|
||||||
export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';
|
|
||||||
export const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE';
|
|
||||||
|
|
||||||
export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';
|
|
||||||
|
|
||||||
export const COMPOSE_UPLOAD_CHANGE_REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST';
|
|
||||||
export const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS';
|
|
||||||
export const COMPOSE_UPLOAD_CHANGE_FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL';
|
|
||||||
|
|
||||||
export const COMPOSE_POLL_ADD = 'COMPOSE_POLL_ADD';
|
|
||||||
export const COMPOSE_POLL_REMOVE = 'COMPOSE_POLL_REMOVE';
|
|
||||||
export const COMPOSE_POLL_OPTION_ADD = 'COMPOSE_POLL_OPTION_ADD';
|
|
||||||
export const COMPOSE_POLL_OPTION_CHANGE = 'COMPOSE_POLL_OPTION_CHANGE';
|
|
||||||
export const COMPOSE_POLL_OPTION_REMOVE = 'COMPOSE_POLL_OPTION_REMOVE';
|
|
||||||
export const COMPOSE_POLL_SETTINGS_CHANGE = 'COMPOSE_POLL_SETTINGS_CHANGE';
|
|
||||||
|
|
||||||
export const COMPOSE_SCHEDULE_ADD = 'COMPOSE_SCHEDULE_ADD';
|
|
||||||
export const COMPOSE_SCHEDULE_SET = 'COMPOSE_SCHEDULE_SET';
|
|
||||||
export const COMPOSE_SCHEDULE_REMOVE = 'COMPOSE_SCHEDULE_REMOVE';
|
|
||||||
|
|
||||||
export const COMPOSE_ADD_TO_MENTIONS = 'COMPOSE_ADD_TO_MENTIONS';
|
|
||||||
export const COMPOSE_REMOVE_FROM_MENTIONS = 'COMPOSE_REMOVE_FROM_MENTIONS';
|
|
||||||
|
|
||||||
export const COMPOSE_SET_STATUS = 'COMPOSE_SET_STATUS';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
exceededImageSizeLimit: { id: 'upload_error.image_size_limit', defaultMessage: 'Image exceeds the current file size limit ({limit})' },
|
|
||||||
exceededVideoSizeLimit: { id: 'upload_error.video_size_limit', defaultMessage: 'Video exceeds the current file size limit ({limit})' },
|
|
||||||
scheduleError: { id: 'compose.invalid_schedule', defaultMessage: 'You must schedule a post at least 5 minutes out.' },
|
|
||||||
success: { id: 'compose.submit_success', defaultMessage: 'Your post was sent' },
|
|
||||||
uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
|
|
||||||
uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },
|
|
||||||
view: { id: 'snackbar.view', defaultMessage: 'View' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1);
|
|
||||||
|
|
||||||
export const ensureComposeIsVisible = (getState, routerHistory) => {
|
|
||||||
if (!getState().getIn(['compose', 'mounted']) && window.innerWidth < COMPOSE_PANEL_BREAKPOINT) {
|
|
||||||
routerHistory.push('/posts/new');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export function setComposeToStatus(status, rawText, spoilerText, contentType, withRedraft) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const { instance } = getState();
|
|
||||||
const { explicitAddressing } = getFeatures(instance);
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: COMPOSE_SET_STATUS,
|
|
||||||
status,
|
|
||||||
rawText,
|
|
||||||
explicitAddressing,
|
|
||||||
spoilerText,
|
|
||||||
contentType,
|
|
||||||
v: parseVersion(instance.version),
|
|
||||||
withRedraft,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeCompose(text) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_CHANGE,
|
|
||||||
text: text,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function replyCompose(status, routerHistory) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const instance = state.get('instance');
|
|
||||||
const { explicitAddressing } = getFeatures(instance);
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: COMPOSE_REPLY,
|
|
||||||
status: status,
|
|
||||||
account: state.getIn(['accounts', state.get('me')]),
|
|
||||||
explicitAddressing,
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(openModal('COMPOSE'));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cancelReplyCompose() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_REPLY_CANCEL,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function quoteCompose(status, routerHistory) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const instance = state.get('instance');
|
|
||||||
const { explicitAddressing } = getFeatures(instance);
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: COMPOSE_QUOTE,
|
|
||||||
status: status,
|
|
||||||
account: state.getIn(['accounts', state.get('me')]),
|
|
||||||
explicitAddressing,
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(openModal('COMPOSE'));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cancelQuoteCompose() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_QUOTE_CANCEL,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resetCompose() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_RESET,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mentionCompose(account, routerHistory) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({
|
|
||||||
type: COMPOSE_MENTION,
|
|
||||||
account: account,
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(openModal('COMPOSE'));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function directCompose(account, routerHistory) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({
|
|
||||||
type: COMPOSE_DIRECT,
|
|
||||||
account: account,
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(openModal('COMPOSE'));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function directComposeById(accountId) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const account = getState().getIn(['accounts', accountId]);
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: COMPOSE_DIRECT,
|
|
||||||
account: account,
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(openModal('COMPOSE'));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function handleComposeSubmit(dispatch, getState, data, status) {
|
|
||||||
if (!dispatch || !getState) return;
|
|
||||||
|
|
||||||
dispatch(insertIntoTagHistory(data.tags || [], status));
|
|
||||||
dispatch(submitComposeSuccess({ ...data }));
|
|
||||||
dispatch(snackbar.success(messages.success, messages.view, `/@${data.account.acct}/posts/${data.id}`));
|
|
||||||
}
|
|
||||||
|
|
||||||
const needsDescriptions = state => {
|
|
||||||
const media = state.getIn(['compose', 'media_attachments']);
|
|
||||||
const missingDescriptionModal = getSettings(state).get('missingDescriptionModal');
|
|
||||||
|
|
||||||
const hasMissing = media.filter(item => !item.get('description')).size > 0;
|
|
||||||
|
|
||||||
return missingDescriptionModal && hasMissing;
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateSchedule = state => {
|
|
||||||
const schedule = state.getIn(['compose', 'schedule']);
|
|
||||||
if (!schedule) return true;
|
|
||||||
|
|
||||||
const fiveMinutesFromNow = new Date(new Date().getTime() + 300000);
|
|
||||||
|
|
||||||
return schedule.getTime() > fiveMinutesFromNow.getTime();
|
|
||||||
};
|
|
||||||
|
|
||||||
export function submitCompose(routerHistory, force = false) {
|
|
||||||
return function(dispatch, getState) {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
const state = getState();
|
|
||||||
|
|
||||||
const status = state.getIn(['compose', 'text'], '');
|
|
||||||
const media = state.getIn(['compose', 'media_attachments']);
|
|
||||||
const statusId = state.getIn(['compose', 'id'], null);
|
|
||||||
let to = state.getIn(['compose', 'to'], ImmutableOrderedSet());
|
|
||||||
|
|
||||||
if (!validateSchedule(state)) {
|
|
||||||
dispatch(snackbar.error(messages.scheduleError));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!status || !status.length) && media.size === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!force && needsDescriptions(state)) {
|
|
||||||
dispatch(openModal('MISSING_DESCRIPTION', {
|
|
||||||
onContinue: () => {
|
|
||||||
dispatch(closeModal('MISSING_DESCRIPTION'));
|
|
||||||
dispatch(submitCompose(routerHistory, true));
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (to && status) {
|
|
||||||
const mentions = status.match(/(?:^|\s|\.)@([a-z0-9_]+(?:@[a-z0-9\.\-]+)?)/gi); // not a perfect regex
|
|
||||||
|
|
||||||
if (mentions)
|
|
||||||
to = to.union(mentions.map(mention => mention.trim().slice(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(submitComposeRequest());
|
|
||||||
dispatch(closeModal());
|
|
||||||
|
|
||||||
const idempotencyKey = state.getIn(['compose', 'idempotencyKey']);
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
status,
|
|
||||||
in_reply_to_id: state.getIn(['compose', 'in_reply_to'], null),
|
|
||||||
quote_id: state.getIn(['compose', 'quote'], null),
|
|
||||||
media_ids: media.map(item => item.get('id')),
|
|
||||||
sensitive: state.getIn(['compose', 'sensitive']),
|
|
||||||
spoiler_text: state.getIn(['compose', 'spoiler_text'], ''),
|
|
||||||
visibility: state.getIn(['compose', 'privacy']),
|
|
||||||
content_type: state.getIn(['compose', 'content_type']),
|
|
||||||
poll: state.getIn(['compose', 'poll'], null),
|
|
||||||
scheduled_at: state.getIn(['compose', 'schedule'], null),
|
|
||||||
to,
|
|
||||||
};
|
|
||||||
|
|
||||||
dispatch(createStatus(params, idempotencyKey, statusId)).then(function(data) {
|
|
||||||
if (!statusId && data.visibility === 'direct' && getState().getIn(['conversations', 'mounted']) <= 0 && routerHistory) {
|
|
||||||
routerHistory.push('/messages');
|
|
||||||
}
|
|
||||||
handleComposeSubmit(dispatch, getState, data, status);
|
|
||||||
}).catch(function(error) {
|
|
||||||
dispatch(submitComposeFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function submitComposeRequest() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SUBMIT_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function submitComposeSuccess(status) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SUBMIT_SUCCESS,
|
|
||||||
status: status,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function submitComposeFail(error) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SUBMIT_FAIL,
|
|
||||||
error: error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uploadCompose(files, intl) {
|
|
||||||
return function(dispatch, getState) {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
const attachmentLimit = getState().getIn(['instance', 'configuration', 'statuses', 'max_media_attachments']);
|
|
||||||
const maxImageSize = getState().getIn(['instance', 'configuration', 'media_attachments', 'image_size_limit']);
|
|
||||||
const maxVideoSize = getState().getIn(['instance', 'configuration', 'media_attachments', 'video_size_limit']);
|
|
||||||
|
|
||||||
const media = getState().getIn(['compose', 'media_attachments']);
|
|
||||||
const progress = new Array(files.length).fill(0);
|
|
||||||
let total = Array.from(files).reduce((a, v) => a + v.size, 0);
|
|
||||||
|
|
||||||
if (files.length + media.size > attachmentLimit) {
|
|
||||||
dispatch(showAlert(undefined, messages.uploadErrorLimit, 'error'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(uploadComposeRequest());
|
|
||||||
|
|
||||||
Array.from(files).forEach((f, i) => {
|
|
||||||
if (media.size + i > attachmentLimit - 1) return;
|
|
||||||
|
|
||||||
const isImage = f.type.match(/image.*/);
|
|
||||||
const isVideo = f.type.match(/video.*/);
|
|
||||||
if (isImage && maxImageSize && (f.size > maxImageSize)) {
|
|
||||||
const limit = formatBytes(maxImageSize);
|
|
||||||
const message = intl.formatMessage(messages.exceededImageSizeLimit, { limit });
|
|
||||||
dispatch(snackbar.error(message));
|
|
||||||
dispatch(uploadComposeFail(true));
|
|
||||||
return;
|
|
||||||
} else if (isVideo && maxVideoSize && (f.size > maxVideoSize)) {
|
|
||||||
const limit = formatBytes(maxVideoSize);
|
|
||||||
const message = intl.formatMessage(messages.exceededVideoSizeLimit, { limit });
|
|
||||||
dispatch(snackbar.error(message));
|
|
||||||
dispatch(uploadComposeFail(true));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Don't define function in loop
|
|
||||||
/* eslint-disable no-loop-func */
|
|
||||||
resizeImage(f).then(file => {
|
|
||||||
const data = new FormData();
|
|
||||||
data.append('file', file);
|
|
||||||
// Account for disparity in size of original image and resized data
|
|
||||||
total += file.size - f.size;
|
|
||||||
|
|
||||||
const onUploadProgress = function({ loaded }) {
|
|
||||||
progress[i] = loaded;
|
|
||||||
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
|
||||||
};
|
|
||||||
|
|
||||||
return dispatch(uploadMedia(data, onUploadProgress))
|
|
||||||
.then(({ status, data }) => {
|
|
||||||
// If server-side processing of the media attachment has not completed yet,
|
|
||||||
// poll the server until it is, before showing the media attachment as uploaded
|
|
||||||
if (status === 200) {
|
|
||||||
dispatch(uploadComposeSuccess(data, f));
|
|
||||||
} else if (status === 202) {
|
|
||||||
const poll = () => {
|
|
||||||
dispatch(fetchMedia(data.id)).then(({ status, data }) => {
|
|
||||||
if (status === 200) {
|
|
||||||
dispatch(uploadComposeSuccess(data, f));
|
|
||||||
} else if (status === 206) {
|
|
||||||
setTimeout(() => poll(), 1000);
|
|
||||||
}
|
|
||||||
}).catch(error => dispatch(uploadComposeFail(error)));
|
|
||||||
};
|
|
||||||
|
|
||||||
poll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).catch(error => dispatch(uploadComposeFail(error)));
|
|
||||||
/* eslint-enable no-loop-func */
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeUploadCompose(id, params) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(changeUploadComposeRequest());
|
|
||||||
|
|
||||||
dispatch(updateMedia(id, params)).then(response => {
|
|
||||||
dispatch(changeUploadComposeSuccess(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(changeUploadComposeFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeUploadComposeRequest() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_UPLOAD_CHANGE_REQUEST,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export function changeUploadComposeSuccess(media) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_UPLOAD_CHANGE_SUCCESS,
|
|
||||||
media: media,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeUploadComposeFail(error) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_UPLOAD_CHANGE_FAIL,
|
|
||||||
error: error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uploadComposeRequest() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_UPLOAD_REQUEST,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uploadComposeProgress(loaded, total) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_UPLOAD_PROGRESS,
|
|
||||||
loaded: loaded,
|
|
||||||
total: total,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uploadComposeSuccess(media) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_UPLOAD_SUCCESS,
|
|
||||||
media: media,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uploadComposeFail(error) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_UPLOAD_FAIL,
|
|
||||||
error: error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function undoUploadCompose(media_id) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_UPLOAD_UNDO,
|
|
||||||
media_id: media_id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearComposeSuggestions() {
|
|
||||||
if (cancelFetchComposeSuggestionsAccounts) {
|
|
||||||
cancelFetchComposeSuggestionsAccounts();
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SUGGESTIONS_CLEAR,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => {
|
|
||||||
if (cancelFetchComposeSuggestionsAccounts) {
|
|
||||||
cancelFetchComposeSuggestionsAccounts();
|
|
||||||
}
|
|
||||||
api(getState).get('/api/v1/accounts/search', {
|
|
||||||
cancelToken: new CancelToken(cancel => {
|
|
||||||
cancelFetchComposeSuggestionsAccounts = cancel;
|
|
||||||
}),
|
|
||||||
params: {
|
|
||||||
q: token.slice(1),
|
|
||||||
resolve: false,
|
|
||||||
limit: 4,
|
|
||||||
},
|
|
||||||
}).then(response => {
|
|
||||||
dispatch(importFetchedAccounts(response.data));
|
|
||||||
dispatch(readyComposeSuggestionsAccounts(token, response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
if (!isCancel(error)) {
|
|
||||||
dispatch(showAlertForError(error));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 200, { leading: true, trailing: true });
|
|
||||||
|
|
||||||
const fetchComposeSuggestionsEmojis = (dispatch, getState, token) => {
|
|
||||||
const results = emojiSearch(token.replace(':', ''), { maxResults: 5 });
|
|
||||||
dispatch(readyComposeSuggestionsEmojis(token, results));
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchComposeSuggestionsTags = (dispatch, getState, token) => {
|
|
||||||
dispatch(updateSuggestionTags(token));
|
|
||||||
};
|
|
||||||
|
|
||||||
export function fetchComposeSuggestions(token) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
switch (token[0]) {
|
|
||||||
case ':':
|
|
||||||
fetchComposeSuggestionsEmojis(dispatch, getState, token);
|
|
||||||
break;
|
|
||||||
case '#':
|
|
||||||
fetchComposeSuggestionsTags(dispatch, getState, token);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fetchComposeSuggestionsAccounts(dispatch, getState, token);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readyComposeSuggestionsEmojis(token, emojis) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SUGGESTIONS_READY,
|
|
||||||
token,
|
|
||||||
emojis,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readyComposeSuggestionsAccounts(token, accounts) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SUGGESTIONS_READY,
|
|
||||||
token,
|
|
||||||
accounts,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function selectComposeSuggestion(position, token, suggestion, path) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
let completion, startPosition;
|
|
||||||
|
|
||||||
if (typeof suggestion === 'object' && suggestion.id) {
|
|
||||||
completion = suggestion.native || suggestion.colons;
|
|
||||||
startPosition = position - 1;
|
|
||||||
|
|
||||||
dispatch(useEmoji(suggestion));
|
|
||||||
} else if (suggestion[0] === '#') {
|
|
||||||
completion = suggestion;
|
|
||||||
startPosition = position - 1;
|
|
||||||
} else {
|
|
||||||
completion = getState().getIn(['accounts', suggestion, 'acct']);
|
|
||||||
startPosition = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: COMPOSE_SUGGESTION_SELECT,
|
|
||||||
position: startPosition,
|
|
||||||
token,
|
|
||||||
completion,
|
|
||||||
path,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateSuggestionTags(token) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SUGGESTION_TAGS_UPDATE,
|
|
||||||
token,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateTagHistory(tags) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_TAG_HISTORY_UPDATE,
|
|
||||||
tags,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertIntoTagHistory(recognizedTags, text) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const oldHistory = state.getIn(['compose', 'tagHistory']);
|
|
||||||
const me = state.get('me');
|
|
||||||
const names = recognizedTags
|
|
||||||
.filter(tag => text.match(new RegExp(`#${tag.name}`, 'i')))
|
|
||||||
.map(tag => tag.name);
|
|
||||||
const intersectedOldHistory = oldHistory.filter(name => names.findIndex(newName => newName.toLowerCase() === name.toLowerCase()) === -1);
|
|
||||||
|
|
||||||
names.push(...intersectedOldHistory.toJS());
|
|
||||||
|
|
||||||
const newHistory = names.slice(0, 1000);
|
|
||||||
|
|
||||||
tagHistory.set(me, newHistory);
|
|
||||||
dispatch(updateTagHistory(newHistory));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mountCompose() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_MOUNT,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unmountCompose() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_UNMOUNT,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeComposeSensitivity() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SENSITIVITY_CHANGE,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeComposeSpoilerness() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SPOILERNESS_CHANGE,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeComposeContentType(value) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_TYPE_CHANGE,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeComposeSpoilerText(text) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SPOILER_TEXT_CHANGE,
|
|
||||||
text,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeComposeVisibility(value) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_VISIBILITY_CHANGE,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function insertEmojiCompose(position, emoji, needsSpace) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_EMOJI_INSERT,
|
|
||||||
position,
|
|
||||||
emoji,
|
|
||||||
needsSpace,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeComposing(value) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_COMPOSING_CHANGE,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addPoll() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_POLL_ADD,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removePoll() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_POLL_REMOVE,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addSchedule() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SCHEDULE_ADD,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setSchedule(date) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SCHEDULE_SET,
|
|
||||||
date: date,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeSchedule() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_SCHEDULE_REMOVE,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addPollOption(title) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_POLL_OPTION_ADD,
|
|
||||||
title,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changePollOption(index, title) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_POLL_OPTION_CHANGE,
|
|
||||||
index,
|
|
||||||
title,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removePollOption(index) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_POLL_OPTION_REMOVE,
|
|
||||||
index,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changePollSettings(expiresIn, isMultiple) {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_POLL_SETTINGS_CHANGE,
|
|
||||||
expiresIn,
|
|
||||||
isMultiple,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function openComposeWithText(text = '') {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch(resetCompose());
|
|
||||||
dispatch(openModal('COMPOSE'));
|
|
||||||
dispatch(changeCompose(text));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addToMentions(accountId) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
|
||||||
|
|
||||||
return dispatch({
|
|
||||||
type: COMPOSE_ADD_TO_MENTIONS,
|
|
||||||
account: acct,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeFromMentions(accountId) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
|
||||||
|
|
||||||
return dispatch({
|
|
||||||
type: COMPOSE_REMOVE_FROM_MENTIONS,
|
|
||||||
account: acct,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,792 @@
|
||||||
|
import axios, { AxiosError, Canceler } from 'axios';
|
||||||
|
import throttle from 'lodash/throttle';
|
||||||
|
import { defineMessages, IntlShape } from 'react-intl';
|
||||||
|
|
||||||
|
import snackbar from 'soapbox/actions/snackbar';
|
||||||
|
import api from 'soapbox/api';
|
||||||
|
import { search as emojiSearch } from 'soapbox/features/emoji/emoji_mart_search_light';
|
||||||
|
import { tagHistory } from 'soapbox/settings';
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
import { getFeatures, parseVersion } from 'soapbox/utils/features';
|
||||||
|
import { formatBytes, getVideoDuration } from 'soapbox/utils/media';
|
||||||
|
import resizeImage from 'soapbox/utils/resize_image';
|
||||||
|
|
||||||
|
import { showAlert, showAlertForError } from './alerts';
|
||||||
|
import { useEmoji } from './emojis';
|
||||||
|
import { importFetchedAccounts } from './importer';
|
||||||
|
import { uploadMedia, fetchMedia, updateMedia } from './media';
|
||||||
|
import { openModal, closeModal } from './modals';
|
||||||
|
import { getSettings } from './settings';
|
||||||
|
import { createStatus } from './statuses';
|
||||||
|
|
||||||
|
import type { History } from 'history';
|
||||||
|
import type { Emoji } from 'soapbox/components/autosuggest_emoji';
|
||||||
|
import type { AutoSuggestion } from 'soapbox/components/autosuggest_input';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { Account, APIEntity, Status } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const { CancelToken, isCancel } = axios;
|
||||||
|
|
||||||
|
let cancelFetchComposeSuggestionsAccounts: Canceler;
|
||||||
|
|
||||||
|
const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
|
||||||
|
const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
|
||||||
|
const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
|
||||||
|
const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
|
||||||
|
const COMPOSE_REPLY = 'COMPOSE_REPLY';
|
||||||
|
const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
|
||||||
|
const COMPOSE_QUOTE = 'COMPOSE_QUOTE';
|
||||||
|
const COMPOSE_QUOTE_CANCEL = 'COMPOSE_QUOTE_CANCEL';
|
||||||
|
const COMPOSE_DIRECT = 'COMPOSE_DIRECT';
|
||||||
|
const COMPOSE_MENTION = 'COMPOSE_MENTION';
|
||||||
|
const COMPOSE_RESET = 'COMPOSE_RESET';
|
||||||
|
const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST';
|
||||||
|
const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS';
|
||||||
|
const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL';
|
||||||
|
const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS';
|
||||||
|
const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO';
|
||||||
|
|
||||||
|
const COMPOSE_SUGGESTIONS_CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR';
|
||||||
|
const COMPOSE_SUGGESTIONS_READY = 'COMPOSE_SUGGESTIONS_READY';
|
||||||
|
const COMPOSE_SUGGESTION_SELECT = 'COMPOSE_SUGGESTION_SELECT';
|
||||||
|
const COMPOSE_SUGGESTION_TAGS_UPDATE = 'COMPOSE_SUGGESTION_TAGS_UPDATE';
|
||||||
|
|
||||||
|
const COMPOSE_TAG_HISTORY_UPDATE = 'COMPOSE_TAG_HISTORY_UPDATE';
|
||||||
|
|
||||||
|
const COMPOSE_MOUNT = 'COMPOSE_MOUNT';
|
||||||
|
const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT';
|
||||||
|
|
||||||
|
const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE';
|
||||||
|
const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE';
|
||||||
|
const COMPOSE_TYPE_CHANGE = 'COMPOSE_TYPE_CHANGE';
|
||||||
|
const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
|
||||||
|
const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
|
||||||
|
const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';
|
||||||
|
const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE';
|
||||||
|
|
||||||
|
const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';
|
||||||
|
|
||||||
|
const COMPOSE_UPLOAD_CHANGE_REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST';
|
||||||
|
const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS';
|
||||||
|
const COMPOSE_UPLOAD_CHANGE_FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL';
|
||||||
|
|
||||||
|
const COMPOSE_POLL_ADD = 'COMPOSE_POLL_ADD';
|
||||||
|
const COMPOSE_POLL_REMOVE = 'COMPOSE_POLL_REMOVE';
|
||||||
|
const COMPOSE_POLL_OPTION_ADD = 'COMPOSE_POLL_OPTION_ADD';
|
||||||
|
const COMPOSE_POLL_OPTION_CHANGE = 'COMPOSE_POLL_OPTION_CHANGE';
|
||||||
|
const COMPOSE_POLL_OPTION_REMOVE = 'COMPOSE_POLL_OPTION_REMOVE';
|
||||||
|
const COMPOSE_POLL_SETTINGS_CHANGE = 'COMPOSE_POLL_SETTINGS_CHANGE';
|
||||||
|
|
||||||
|
const COMPOSE_SCHEDULE_ADD = 'COMPOSE_SCHEDULE_ADD';
|
||||||
|
const COMPOSE_SCHEDULE_SET = 'COMPOSE_SCHEDULE_SET';
|
||||||
|
const COMPOSE_SCHEDULE_REMOVE = 'COMPOSE_SCHEDULE_REMOVE';
|
||||||
|
|
||||||
|
const COMPOSE_ADD_TO_MENTIONS = 'COMPOSE_ADD_TO_MENTIONS';
|
||||||
|
const COMPOSE_REMOVE_FROM_MENTIONS = 'COMPOSE_REMOVE_FROM_MENTIONS';
|
||||||
|
|
||||||
|
const COMPOSE_SET_STATUS = 'COMPOSE_SET_STATUS';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
exceededImageSizeLimit: { id: 'upload_error.image_size_limit', defaultMessage: 'Image exceeds the current file size limit ({limit})' },
|
||||||
|
exceededVideoSizeLimit: { id: 'upload_error.video_size_limit', defaultMessage: 'Video exceeds the current file size limit ({limit})' },
|
||||||
|
exceededVideoDurationLimit: { id: 'upload_error.video_duration_limit', defaultMessage: 'Video exceeds the current duration limit ({limit} seconds)' },
|
||||||
|
scheduleError: { id: 'compose.invalid_schedule', defaultMessage: 'You must schedule a post at least 5 minutes out.' },
|
||||||
|
success: { id: 'compose.submit_success', defaultMessage: 'Your post was sent' },
|
||||||
|
uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
|
||||||
|
uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },
|
||||||
|
view: { id: 'snackbar.view', defaultMessage: 'View' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1);
|
||||||
|
|
||||||
|
const ensureComposeIsVisible = (getState: () => RootState, routerHistory: History) => {
|
||||||
|
if (!getState().compose.mounted && window.innerWidth < COMPOSE_PANEL_BREAKPOINT) {
|
||||||
|
routerHistory.push('/posts/new');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setComposeToStatus = (status: Status, rawText: string, spoilerText?: string, contentType?: string | false, withRedraft?: boolean) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const { instance } = getState();
|
||||||
|
const { explicitAddressing } = getFeatures(instance);
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: COMPOSE_SET_STATUS,
|
||||||
|
status,
|
||||||
|
rawText,
|
||||||
|
explicitAddressing,
|
||||||
|
spoilerText,
|
||||||
|
contentType,
|
||||||
|
v: parseVersion(instance.version),
|
||||||
|
withRedraft,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeCompose = (text: string) => ({
|
||||||
|
type: COMPOSE_CHANGE,
|
||||||
|
text: text,
|
||||||
|
});
|
||||||
|
|
||||||
|
const replyCompose = (status: Status) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
const instance = state.instance;
|
||||||
|
const { explicitAddressing } = getFeatures(instance);
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: COMPOSE_REPLY,
|
||||||
|
status: status,
|
||||||
|
account: state.accounts.get(state.me),
|
||||||
|
explicitAddressing,
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(openModal('COMPOSE'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelReplyCompose = () => ({
|
||||||
|
type: COMPOSE_REPLY_CANCEL,
|
||||||
|
});
|
||||||
|
|
||||||
|
const quoteCompose = (status: Status) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
const instance = state.instance;
|
||||||
|
const { explicitAddressing } = getFeatures(instance);
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: COMPOSE_QUOTE,
|
||||||
|
status: status,
|
||||||
|
account: state.accounts.get(state.me),
|
||||||
|
explicitAddressing,
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(openModal('COMPOSE'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelQuoteCompose = () => ({
|
||||||
|
type: COMPOSE_QUOTE_CANCEL,
|
||||||
|
});
|
||||||
|
|
||||||
|
const resetCompose = () => ({
|
||||||
|
type: COMPOSE_RESET,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mentionCompose = (account: Account) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: COMPOSE_MENTION,
|
||||||
|
account: account,
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(openModal('COMPOSE'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const directCompose = (account: Account) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: COMPOSE_DIRECT,
|
||||||
|
account: account,
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(openModal('COMPOSE'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const directComposeById = (accountId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const account = getState().accounts.get(accountId);
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: COMPOSE_DIRECT,
|
||||||
|
account: account,
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(openModal('COMPOSE'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleComposeSubmit = (dispatch: AppDispatch, getState: () => RootState, data: APIEntity, status: string) => {
|
||||||
|
if (!dispatch || !getState) return;
|
||||||
|
|
||||||
|
dispatch(insertIntoTagHistory(data.tags || [], status));
|
||||||
|
dispatch(submitComposeSuccess({ ...data }));
|
||||||
|
dispatch(snackbar.success(messages.success, messages.view, `/@${data.account.acct}/posts/${data.id}`));
|
||||||
|
};
|
||||||
|
|
||||||
|
const needsDescriptions = (state: RootState) => {
|
||||||
|
const media = state.compose.media_attachments;
|
||||||
|
const missingDescriptionModal = getSettings(state).get('missingDescriptionModal');
|
||||||
|
|
||||||
|
const hasMissing = media.filter(item => !item.description).size > 0;
|
||||||
|
|
||||||
|
return missingDescriptionModal && hasMissing;
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateSchedule = (state: RootState) => {
|
||||||
|
const schedule = state.compose.schedule;
|
||||||
|
if (!schedule) return true;
|
||||||
|
|
||||||
|
const fiveMinutesFromNow = new Date(new Date().getTime() + 300000);
|
||||||
|
|
||||||
|
return schedule.getTime() > fiveMinutesFromNow.getTime();
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitCompose = (routerHistory: History, force = false) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
const state = getState();
|
||||||
|
|
||||||
|
const status = state.compose.text;
|
||||||
|
const media = state.compose.media_attachments;
|
||||||
|
const statusId = state.compose.id;
|
||||||
|
let to = state.compose.to;
|
||||||
|
|
||||||
|
if (!validateSchedule(state)) {
|
||||||
|
dispatch(snackbar.error(messages.scheduleError));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!status || !status.length) && media.size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!force && needsDescriptions(state)) {
|
||||||
|
dispatch(openModal('MISSING_DESCRIPTION', {
|
||||||
|
onContinue: () => {
|
||||||
|
dispatch(closeModal('MISSING_DESCRIPTION'));
|
||||||
|
dispatch(submitCompose(routerHistory, true));
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to && status) {
|
||||||
|
const mentions: string[] | null = status.match(/(?:^|\s|\.)@([a-z0-9_]+(?:@[a-z0-9\.\-]+)?)/gi); // not a perfect regex
|
||||||
|
|
||||||
|
if (mentions)
|
||||||
|
to = to.union(mentions.map(mention => mention.trim().slice(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(submitComposeRequest());
|
||||||
|
dispatch(closeModal());
|
||||||
|
|
||||||
|
const idempotencyKey = state.compose.idempotencyKey;
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
status,
|
||||||
|
in_reply_to_id: state.compose.in_reply_to,
|
||||||
|
quote_id: state.compose.quote,
|
||||||
|
media_ids: media.map(item => item.id),
|
||||||
|
sensitive: state.compose.sensitive,
|
||||||
|
spoiler_text: state.compose.spoiler_text,
|
||||||
|
visibility: state.compose.privacy,
|
||||||
|
content_type: state.compose.content_type,
|
||||||
|
poll: state.compose.poll,
|
||||||
|
scheduled_at: state.compose.schedule,
|
||||||
|
to,
|
||||||
|
};
|
||||||
|
|
||||||
|
dispatch(createStatus(params, idempotencyKey, statusId)).then(function(data) {
|
||||||
|
if (!statusId && data.visibility === 'direct' && getState().conversations.get('mounted') <= 0 && routerHistory) {
|
||||||
|
routerHistory.push('/messages');
|
||||||
|
}
|
||||||
|
handleComposeSubmit(dispatch, getState, data, status);
|
||||||
|
}).catch(function(error) {
|
||||||
|
dispatch(submitComposeFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitComposeRequest = () => ({
|
||||||
|
type: COMPOSE_SUBMIT_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitComposeSuccess = (status: APIEntity) => ({
|
||||||
|
type: COMPOSE_SUBMIT_SUCCESS,
|
||||||
|
status: status,
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitComposeFail = (error: AxiosError) => ({
|
||||||
|
type: COMPOSE_SUBMIT_FAIL,
|
||||||
|
error: error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadCompose = (files: FileList, intl: IntlShape) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
const attachmentLimit = getState().instance.configuration.getIn(['statuses', 'max_media_attachments']) as number;
|
||||||
|
const maxImageSize = getState().instance.configuration.getIn(['media_attachments', 'image_size_limit']) as number | undefined;
|
||||||
|
const maxVideoSize = getState().instance.configuration.getIn(['media_attachments', 'video_size_limit']) as number | undefined;
|
||||||
|
const maxVideoDuration = getState().instance.configuration.getIn(['media_attachments', 'video_duration_limit']) as number | undefined;
|
||||||
|
|
||||||
|
const media = getState().compose.media_attachments;
|
||||||
|
const progress = new Array(files.length).fill(0);
|
||||||
|
let total = Array.from(files).reduce((a, v) => a + v.size, 0);
|
||||||
|
|
||||||
|
if (files.length + media.size > attachmentLimit) {
|
||||||
|
dispatch(showAlert(undefined, messages.uploadErrorLimit, 'error'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(uploadComposeRequest());
|
||||||
|
|
||||||
|
Array.from(files).forEach(async(f, i) => {
|
||||||
|
if (media.size + i > attachmentLimit - 1) return;
|
||||||
|
|
||||||
|
const isImage = f.type.match(/image.*/);
|
||||||
|
const isVideo = f.type.match(/video.*/);
|
||||||
|
const videoDurationInSeconds = (isVideo && maxVideoDuration) ? await getVideoDuration(f) : 0;
|
||||||
|
|
||||||
|
if (isImage && maxImageSize && (f.size > maxImageSize)) {
|
||||||
|
const limit = formatBytes(maxImageSize);
|
||||||
|
const message = intl.formatMessage(messages.exceededImageSizeLimit, { limit });
|
||||||
|
dispatch(snackbar.error(message));
|
||||||
|
dispatch(uploadComposeFail(true));
|
||||||
|
return;
|
||||||
|
} else if (isVideo && maxVideoSize && (f.size > maxVideoSize)) {
|
||||||
|
const limit = formatBytes(maxVideoSize);
|
||||||
|
const message = intl.formatMessage(messages.exceededVideoSizeLimit, { limit });
|
||||||
|
dispatch(snackbar.error(message));
|
||||||
|
dispatch(uploadComposeFail(true));
|
||||||
|
return;
|
||||||
|
} else if (isVideo && maxVideoDuration && (videoDurationInSeconds > maxVideoDuration)) {
|
||||||
|
const message = intl.formatMessage(messages.exceededVideoDurationLimit, { limit: maxVideoDuration });
|
||||||
|
dispatch(snackbar.error(message));
|
||||||
|
dispatch(uploadComposeFail(true));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Don't define const in loop
|
||||||
|
/* eslint-disable no-loop-func */
|
||||||
|
resizeImage(f).then(file => {
|
||||||
|
const data = new FormData();
|
||||||
|
data.append('file', file);
|
||||||
|
// Account for disparity in size of original image and resized data
|
||||||
|
total += file.size - f.size;
|
||||||
|
|
||||||
|
const onUploadProgress = ({ loaded }: any) => {
|
||||||
|
progress[i] = loaded;
|
||||||
|
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
||||||
|
};
|
||||||
|
|
||||||
|
return dispatch(uploadMedia(data, onUploadProgress))
|
||||||
|
.then(({ status, data }) => {
|
||||||
|
// If server-side processing of the media attachment has not completed yet,
|
||||||
|
// poll the server until it is, before showing the media attachment as uploaded
|
||||||
|
if (status === 200) {
|
||||||
|
dispatch(uploadComposeSuccess(data, f));
|
||||||
|
} else if (status === 202) {
|
||||||
|
const poll = () => {
|
||||||
|
dispatch(fetchMedia(data.id)).then(({ status, data }) => {
|
||||||
|
if (status === 200) {
|
||||||
|
dispatch(uploadComposeSuccess(data, f));
|
||||||
|
} else if (status === 206) {
|
||||||
|
setTimeout(() => poll(), 1000);
|
||||||
|
}
|
||||||
|
}).catch(error => dispatch(uploadComposeFail(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
poll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(error => dispatch(uploadComposeFail(error)));
|
||||||
|
/* eslint-enable no-loop-func */
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeUploadCompose = (id: string, params: Record<string, any>) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(changeUploadComposeRequest());
|
||||||
|
|
||||||
|
dispatch(updateMedia(id, params)).then(response => {
|
||||||
|
dispatch(changeUploadComposeSuccess(response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(changeUploadComposeFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeUploadComposeRequest = () => ({
|
||||||
|
type: COMPOSE_UPLOAD_CHANGE_REQUEST,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeUploadComposeSuccess = (media: APIEntity) => ({
|
||||||
|
type: COMPOSE_UPLOAD_CHANGE_SUCCESS,
|
||||||
|
media: media,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeUploadComposeFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: COMPOSE_UPLOAD_CHANGE_FAIL,
|
||||||
|
id,
|
||||||
|
error: error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadComposeRequest = () => ({
|
||||||
|
type: COMPOSE_UPLOAD_REQUEST,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadComposeProgress = (loaded: number, total: number) => ({
|
||||||
|
type: COMPOSE_UPLOAD_PROGRESS,
|
||||||
|
loaded: loaded,
|
||||||
|
total: total,
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadComposeSuccess = (media: APIEntity, file: File) => ({
|
||||||
|
type: COMPOSE_UPLOAD_SUCCESS,
|
||||||
|
media: media,
|
||||||
|
file,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadComposeFail = (error: AxiosError | true) => ({
|
||||||
|
type: COMPOSE_UPLOAD_FAIL,
|
||||||
|
error: error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const undoUploadCompose = (media_id: string) => ({
|
||||||
|
type: COMPOSE_UPLOAD_UNDO,
|
||||||
|
media_id: media_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const clearComposeSuggestions = () => {
|
||||||
|
if (cancelFetchComposeSuggestionsAccounts) {
|
||||||
|
cancelFetchComposeSuggestionsAccounts();
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: COMPOSE_SUGGESTIONS_CLEAR,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => {
|
||||||
|
if (cancelFetchComposeSuggestionsAccounts) {
|
||||||
|
cancelFetchComposeSuggestionsAccounts();
|
||||||
|
}
|
||||||
|
api(getState).get('/api/v1/accounts/search', {
|
||||||
|
cancelToken: new CancelToken(cancel => {
|
||||||
|
cancelFetchComposeSuggestionsAccounts = cancel;
|
||||||
|
}),
|
||||||
|
params: {
|
||||||
|
q: token.slice(1),
|
||||||
|
resolve: false,
|
||||||
|
limit: 4,
|
||||||
|
},
|
||||||
|
}).then(response => {
|
||||||
|
dispatch(importFetchedAccounts(response.data));
|
||||||
|
dispatch(readyComposeSuggestionsAccounts(token, response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
if (!isCancel(error)) {
|
||||||
|
dispatch(showAlertForError(error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 200, { leading: true, trailing: true });
|
||||||
|
|
||||||
|
const fetchComposeSuggestionsEmojis = (dispatch: AppDispatch, getState: () => RootState, token: string) => {
|
||||||
|
const results = emojiSearch(token.replace(':', ''), { maxResults: 5 } as any);
|
||||||
|
dispatch(readyComposeSuggestionsEmojis(token, results));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchComposeSuggestionsTags = (dispatch: AppDispatch, getState: () => RootState, token: string) => {
|
||||||
|
dispatch(updateSuggestionTags(token));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchComposeSuggestions = (token: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
switch (token[0]) {
|
||||||
|
case ':':
|
||||||
|
fetchComposeSuggestionsEmojis(dispatch, getState, token);
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
fetchComposeSuggestionsTags(dispatch, getState, token);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fetchComposeSuggestionsAccounts(dispatch, getState, token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const readyComposeSuggestionsEmojis = (token: string, emojis: Emoji[]) => ({
|
||||||
|
type: COMPOSE_SUGGESTIONS_READY,
|
||||||
|
token,
|
||||||
|
emojis,
|
||||||
|
});
|
||||||
|
|
||||||
|
const readyComposeSuggestionsAccounts = (token: string, accounts: APIEntity[]) => ({
|
||||||
|
type: COMPOSE_SUGGESTIONS_READY,
|
||||||
|
token,
|
||||||
|
accounts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectComposeSuggestion = (position: number, token: string | null, suggestion: AutoSuggestion, path: Array<string | number>) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
let completion, startPosition;
|
||||||
|
|
||||||
|
if (typeof suggestion === 'object' && suggestion.id) {
|
||||||
|
completion = suggestion.native || suggestion.colons;
|
||||||
|
startPosition = position - 1;
|
||||||
|
|
||||||
|
dispatch(useEmoji(suggestion));
|
||||||
|
} else if (typeof suggestion === 'string' && suggestion[0] === '#') {
|
||||||
|
completion = suggestion;
|
||||||
|
startPosition = position - 1;
|
||||||
|
} else {
|
||||||
|
completion = getState().accounts.get(suggestion)!.acct;
|
||||||
|
startPosition = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: COMPOSE_SUGGESTION_SELECT,
|
||||||
|
position: startPosition,
|
||||||
|
token,
|
||||||
|
completion,
|
||||||
|
path,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSuggestionTags = (token: string) => ({
|
||||||
|
type: COMPOSE_SUGGESTION_TAGS_UPDATE,
|
||||||
|
token,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateTagHistory = (tags: string[]) => ({
|
||||||
|
type: COMPOSE_TAG_HISTORY_UPDATE,
|
||||||
|
tags,
|
||||||
|
});
|
||||||
|
|
||||||
|
const insertIntoTagHistory = (recognizedTags: APIEntity[], text: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
const oldHistory = state.compose.tagHistory;
|
||||||
|
const me = state.me;
|
||||||
|
const names = recognizedTags
|
||||||
|
.filter(tag => text.match(new RegExp(`#${tag.name}`, 'i')))
|
||||||
|
.map(tag => tag.name);
|
||||||
|
const intersectedOldHistory = oldHistory.filter(name => names.findIndex(newName => newName.toLowerCase() === name.toLowerCase()) === -1);
|
||||||
|
|
||||||
|
names.push(...intersectedOldHistory.toJS());
|
||||||
|
|
||||||
|
const newHistory = names.slice(0, 1000);
|
||||||
|
|
||||||
|
tagHistory.set(me as string, newHistory);
|
||||||
|
dispatch(updateTagHistory(newHistory));
|
||||||
|
};
|
||||||
|
|
||||||
|
const mountCompose = () => ({
|
||||||
|
type: COMPOSE_MOUNT,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unmountCompose = () => ({
|
||||||
|
type: COMPOSE_UNMOUNT,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeComposeSensitivity = () => ({
|
||||||
|
type: COMPOSE_SENSITIVITY_CHANGE,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeComposeSpoilerness = () => ({
|
||||||
|
type: COMPOSE_SPOILERNESS_CHANGE,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeComposeContentType = (value: string) => ({
|
||||||
|
type: COMPOSE_TYPE_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeComposeSpoilerText = (text: string) => ({
|
||||||
|
type: COMPOSE_SPOILER_TEXT_CHANGE,
|
||||||
|
text,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeComposeVisibility = (value: string) => ({
|
||||||
|
type: COMPOSE_VISIBILITY_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const insertEmojiCompose = (position: number, emoji: string, needsSpace: boolean) => ({
|
||||||
|
type: COMPOSE_EMOJI_INSERT,
|
||||||
|
position,
|
||||||
|
emoji,
|
||||||
|
needsSpace,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeComposing = (value: string) => ({
|
||||||
|
type: COMPOSE_COMPOSING_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addPoll = () => ({
|
||||||
|
type: COMPOSE_POLL_ADD,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removePoll = () => ({
|
||||||
|
type: COMPOSE_POLL_REMOVE,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addSchedule = () => ({
|
||||||
|
type: COMPOSE_SCHEDULE_ADD,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setSchedule = (date: Date) => ({
|
||||||
|
type: COMPOSE_SCHEDULE_SET,
|
||||||
|
date: date,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeSchedule = () => ({
|
||||||
|
type: COMPOSE_SCHEDULE_REMOVE,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addPollOption = (title: string) => ({
|
||||||
|
type: COMPOSE_POLL_OPTION_ADD,
|
||||||
|
title,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changePollOption = (index: number, title: string) => ({
|
||||||
|
type: COMPOSE_POLL_OPTION_CHANGE,
|
||||||
|
index,
|
||||||
|
title,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removePollOption = (index: number) => ({
|
||||||
|
type: COMPOSE_POLL_OPTION_REMOVE,
|
||||||
|
index,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changePollSettings = (expiresIn?: string | number, isMultiple?: boolean) => ({
|
||||||
|
type: COMPOSE_POLL_SETTINGS_CHANGE,
|
||||||
|
expiresIn,
|
||||||
|
isMultiple,
|
||||||
|
});
|
||||||
|
|
||||||
|
const openComposeWithText = (text = '') =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
dispatch(resetCompose());
|
||||||
|
dispatch(openModal('COMPOSE'));
|
||||||
|
dispatch(changeCompose(text));
|
||||||
|
};
|
||||||
|
|
||||||
|
const addToMentions = (accountId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
const acct = state.accounts.get(accountId)!.acct;
|
||||||
|
|
||||||
|
return dispatch({
|
||||||
|
type: COMPOSE_ADD_TO_MENTIONS,
|
||||||
|
account: acct,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeFromMentions = (accountId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
const acct = state.accounts.get(accountId)!.acct;
|
||||||
|
|
||||||
|
return dispatch({
|
||||||
|
type: COMPOSE_REMOVE_FROM_MENTIONS,
|
||||||
|
account: acct,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
COMPOSE_CHANGE,
|
||||||
|
COMPOSE_SUBMIT_REQUEST,
|
||||||
|
COMPOSE_SUBMIT_SUCCESS,
|
||||||
|
COMPOSE_SUBMIT_FAIL,
|
||||||
|
COMPOSE_REPLY,
|
||||||
|
COMPOSE_REPLY_CANCEL,
|
||||||
|
COMPOSE_QUOTE,
|
||||||
|
COMPOSE_QUOTE_CANCEL,
|
||||||
|
COMPOSE_DIRECT,
|
||||||
|
COMPOSE_MENTION,
|
||||||
|
COMPOSE_RESET,
|
||||||
|
COMPOSE_UPLOAD_REQUEST,
|
||||||
|
COMPOSE_UPLOAD_SUCCESS,
|
||||||
|
COMPOSE_UPLOAD_FAIL,
|
||||||
|
COMPOSE_UPLOAD_PROGRESS,
|
||||||
|
COMPOSE_UPLOAD_UNDO,
|
||||||
|
COMPOSE_SUGGESTIONS_CLEAR,
|
||||||
|
COMPOSE_SUGGESTIONS_READY,
|
||||||
|
COMPOSE_SUGGESTION_SELECT,
|
||||||
|
COMPOSE_SUGGESTION_TAGS_UPDATE,
|
||||||
|
COMPOSE_TAG_HISTORY_UPDATE,
|
||||||
|
COMPOSE_MOUNT,
|
||||||
|
COMPOSE_UNMOUNT,
|
||||||
|
COMPOSE_SENSITIVITY_CHANGE,
|
||||||
|
COMPOSE_SPOILERNESS_CHANGE,
|
||||||
|
COMPOSE_TYPE_CHANGE,
|
||||||
|
COMPOSE_SPOILER_TEXT_CHANGE,
|
||||||
|
COMPOSE_VISIBILITY_CHANGE,
|
||||||
|
COMPOSE_LISTABILITY_CHANGE,
|
||||||
|
COMPOSE_COMPOSING_CHANGE,
|
||||||
|
COMPOSE_EMOJI_INSERT,
|
||||||
|
COMPOSE_UPLOAD_CHANGE_REQUEST,
|
||||||
|
COMPOSE_UPLOAD_CHANGE_SUCCESS,
|
||||||
|
COMPOSE_UPLOAD_CHANGE_FAIL,
|
||||||
|
COMPOSE_POLL_ADD,
|
||||||
|
COMPOSE_POLL_REMOVE,
|
||||||
|
COMPOSE_POLL_OPTION_ADD,
|
||||||
|
COMPOSE_POLL_OPTION_CHANGE,
|
||||||
|
COMPOSE_POLL_OPTION_REMOVE,
|
||||||
|
COMPOSE_POLL_SETTINGS_CHANGE,
|
||||||
|
COMPOSE_SCHEDULE_ADD,
|
||||||
|
COMPOSE_SCHEDULE_SET,
|
||||||
|
COMPOSE_SCHEDULE_REMOVE,
|
||||||
|
COMPOSE_ADD_TO_MENTIONS,
|
||||||
|
COMPOSE_REMOVE_FROM_MENTIONS,
|
||||||
|
COMPOSE_SET_STATUS,
|
||||||
|
ensureComposeIsVisible,
|
||||||
|
setComposeToStatus,
|
||||||
|
changeCompose,
|
||||||
|
replyCompose,
|
||||||
|
cancelReplyCompose,
|
||||||
|
quoteCompose,
|
||||||
|
cancelQuoteCompose,
|
||||||
|
resetCompose,
|
||||||
|
mentionCompose,
|
||||||
|
directCompose,
|
||||||
|
directComposeById,
|
||||||
|
handleComposeSubmit,
|
||||||
|
submitCompose,
|
||||||
|
submitComposeRequest,
|
||||||
|
submitComposeSuccess,
|
||||||
|
submitComposeFail,
|
||||||
|
uploadCompose,
|
||||||
|
changeUploadCompose,
|
||||||
|
changeUploadComposeRequest,
|
||||||
|
changeUploadComposeSuccess,
|
||||||
|
changeUploadComposeFail,
|
||||||
|
uploadComposeRequest,
|
||||||
|
uploadComposeProgress,
|
||||||
|
uploadComposeSuccess,
|
||||||
|
uploadComposeFail,
|
||||||
|
undoUploadCompose,
|
||||||
|
clearComposeSuggestions,
|
||||||
|
fetchComposeSuggestions,
|
||||||
|
readyComposeSuggestionsEmojis,
|
||||||
|
readyComposeSuggestionsAccounts,
|
||||||
|
selectComposeSuggestion,
|
||||||
|
updateSuggestionTags,
|
||||||
|
updateTagHistory,
|
||||||
|
mountCompose,
|
||||||
|
unmountCompose,
|
||||||
|
changeComposeSensitivity,
|
||||||
|
changeComposeSpoilerness,
|
||||||
|
changeComposeContentType,
|
||||||
|
changeComposeSpoilerText,
|
||||||
|
changeComposeVisibility,
|
||||||
|
insertEmojiCompose,
|
||||||
|
changeComposing,
|
||||||
|
addPoll,
|
||||||
|
removePoll,
|
||||||
|
addSchedule,
|
||||||
|
setSchedule,
|
||||||
|
removeSchedule,
|
||||||
|
addPollOption,
|
||||||
|
changePollOption,
|
||||||
|
removePollOption,
|
||||||
|
changePollSettings,
|
||||||
|
openComposeWithText,
|
||||||
|
addToMentions,
|
||||||
|
removeFromMentions,
|
||||||
|
};
|
|
@ -1,91 +0,0 @@
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api, { getLinks } from '../api';
|
|
||||||
|
|
||||||
import {
|
|
||||||
importFetchedAccounts,
|
|
||||||
importFetchedStatuses,
|
|
||||||
importFetchedStatus,
|
|
||||||
} from './importer';
|
|
||||||
|
|
||||||
export const CONVERSATIONS_MOUNT = 'CONVERSATIONS_MOUNT';
|
|
||||||
export const CONVERSATIONS_UNMOUNT = 'CONVERSATIONS_UNMOUNT';
|
|
||||||
|
|
||||||
export const CONVERSATIONS_FETCH_REQUEST = 'CONVERSATIONS_FETCH_REQUEST';
|
|
||||||
export const CONVERSATIONS_FETCH_SUCCESS = 'CONVERSATIONS_FETCH_SUCCESS';
|
|
||||||
export const CONVERSATIONS_FETCH_FAIL = 'CONVERSATIONS_FETCH_FAIL';
|
|
||||||
export const CONVERSATIONS_UPDATE = 'CONVERSATIONS_UPDATE';
|
|
||||||
|
|
||||||
export const CONVERSATIONS_READ = 'CONVERSATIONS_READ';
|
|
||||||
|
|
||||||
export const mountConversations = () => ({
|
|
||||||
type: CONVERSATIONS_MOUNT,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const unmountConversations = () => ({
|
|
||||||
type: CONVERSATIONS_UNMOUNT,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const markConversationRead = conversationId => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: CONVERSATIONS_READ,
|
|
||||||
id: conversationId,
|
|
||||||
});
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/conversations/${conversationId}/read`);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(expandConversationsRequest());
|
|
||||||
|
|
||||||
const params = { max_id: maxId };
|
|
||||||
|
|
||||||
if (!maxId) {
|
|
||||||
params.since_id = getState().getIn(['conversations', 'items', 0, 'id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isLoadingRecent = !!params.since_id;
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/conversations', { params })
|
|
||||||
.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));
|
|
||||||
})
|
|
||||||
.catch(err => dispatch(expandConversationsFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const expandConversationsRequest = () => ({
|
|
||||||
type: CONVERSATIONS_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandConversationsSuccess = (conversations, next, isLoadingRecent) => ({
|
|
||||||
type: CONVERSATIONS_FETCH_SUCCESS,
|
|
||||||
conversations,
|
|
||||||
next,
|
|
||||||
isLoadingRecent,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandConversationsFail = error => ({
|
|
||||||
type: CONVERSATIONS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const updateConversations = conversation => dispatch => {
|
|
||||||
dispatch(importFetchedAccounts(conversation.accounts));
|
|
||||||
|
|
||||||
if (conversation.last_status) {
|
|
||||||
dispatch(importFetchedStatus(conversation.last_status));
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: CONVERSATIONS_UPDATE,
|
|
||||||
conversation,
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
|
import {
|
||||||
|
importFetchedAccounts,
|
||||||
|
importFetchedStatuses,
|
||||||
|
importFetchedStatus,
|
||||||
|
} from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const CONVERSATIONS_MOUNT = 'CONVERSATIONS_MOUNT';
|
||||||
|
const CONVERSATIONS_UNMOUNT = 'CONVERSATIONS_UNMOUNT';
|
||||||
|
|
||||||
|
const CONVERSATIONS_FETCH_REQUEST = 'CONVERSATIONS_FETCH_REQUEST';
|
||||||
|
const CONVERSATIONS_FETCH_SUCCESS = 'CONVERSATIONS_FETCH_SUCCESS';
|
||||||
|
const CONVERSATIONS_FETCH_FAIL = 'CONVERSATIONS_FETCH_FAIL';
|
||||||
|
const CONVERSATIONS_UPDATE = 'CONVERSATIONS_UPDATE';
|
||||||
|
|
||||||
|
const CONVERSATIONS_READ = 'CONVERSATIONS_READ';
|
||||||
|
|
||||||
|
const mountConversations = () => ({
|
||||||
|
type: CONVERSATIONS_MOUNT,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unmountConversations = () => ({
|
||||||
|
type: CONVERSATIONS_UNMOUNT,
|
||||||
|
});
|
||||||
|
|
||||||
|
const markConversationRead = (conversationId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: CONVERSATIONS_READ,
|
||||||
|
id: conversationId,
|
||||||
|
});
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/conversations/${conversationId}/read`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandConversations = ({ maxId }: Record<string, any> = {}) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(expandConversationsRequest());
|
||||||
|
|
||||||
|
const params: Record<string, any> = { max_id: maxId };
|
||||||
|
|
||||||
|
if (!maxId) {
|
||||||
|
params.since_id = getState().conversations.getIn(['items', 0, 'id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLoadingRecent = !!params.since_id;
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/conversations', { params })
|
||||||
|
.then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
|
||||||
|
dispatch(importFetchedAccounts(response.data.reduce((aggr: Array<APIEntity>, item: APIEntity) => aggr.concat(item.accounts), [])));
|
||||||
|
dispatch(importFetchedStatuses(response.data.map((item: Record<string, any>) => item.last_status).filter((x?: APIEntity) => !!x)));
|
||||||
|
dispatch(expandConversationsSuccess(response.data, next ? next.uri : null, isLoadingRecent));
|
||||||
|
})
|
||||||
|
.catch(err => dispatch(expandConversationsFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandConversationsRequest = () => ({
|
||||||
|
type: CONVERSATIONS_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandConversationsSuccess = (conversations: APIEntity[], next: string | null, isLoadingRecent: boolean) => ({
|
||||||
|
type: CONVERSATIONS_FETCH_SUCCESS,
|
||||||
|
conversations,
|
||||||
|
next,
|
||||||
|
isLoadingRecent,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandConversationsFail = (error: AxiosError) => ({
|
||||||
|
type: CONVERSATIONS_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateConversations = (conversation: APIEntity) => (dispatch: AppDispatch) => {
|
||||||
|
dispatch(importFetchedAccounts(conversation.accounts));
|
||||||
|
|
||||||
|
if (conversation.last_status) {
|
||||||
|
dispatch(importFetchedStatus(conversation.last_status));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dispatch({
|
||||||
|
type: CONVERSATIONS_UPDATE,
|
||||||
|
conversation,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
CONVERSATIONS_MOUNT,
|
||||||
|
CONVERSATIONS_UNMOUNT,
|
||||||
|
CONVERSATIONS_FETCH_REQUEST,
|
||||||
|
CONVERSATIONS_FETCH_SUCCESS,
|
||||||
|
CONVERSATIONS_FETCH_FAIL,
|
||||||
|
CONVERSATIONS_UPDATE,
|
||||||
|
CONVERSATIONS_READ,
|
||||||
|
mountConversations,
|
||||||
|
unmountConversations,
|
||||||
|
markConversationRead,
|
||||||
|
expandConversations,
|
||||||
|
expandConversationsRequest,
|
||||||
|
expandConversationsSuccess,
|
||||||
|
expandConversationsFail,
|
||||||
|
updateConversations,
|
||||||
|
};
|
|
@ -1,43 +0,0 @@
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
export const CUSTOM_EMOJIS_FETCH_REQUEST = 'CUSTOM_EMOJIS_FETCH_REQUEST';
|
|
||||||
export const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS';
|
|
||||||
export const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export function fetchCustomEmojis() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const me = getState().get('me');
|
|
||||||
if (!me) return;
|
|
||||||
|
|
||||||
dispatch(fetchCustomEmojisRequest());
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/custom_emojis').then(response => {
|
|
||||||
dispatch(fetchCustomEmojisSuccess(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchCustomEmojisFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchCustomEmojisRequest() {
|
|
||||||
return {
|
|
||||||
type: CUSTOM_EMOJIS_FETCH_REQUEST,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchCustomEmojisSuccess(custom_emojis) {
|
|
||||||
return {
|
|
||||||
type: CUSTOM_EMOJIS_FETCH_SUCCESS,
|
|
||||||
custom_emojis,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchCustomEmojisFail(error) {
|
|
||||||
return {
|
|
||||||
type: CUSTOM_EMOJIS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const CUSTOM_EMOJIS_FETCH_REQUEST = 'CUSTOM_EMOJIS_FETCH_REQUEST';
|
||||||
|
const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS';
|
||||||
|
const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const fetchCustomEmojis = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const me = getState().me;
|
||||||
|
if (!me) return;
|
||||||
|
|
||||||
|
dispatch(fetchCustomEmojisRequest());
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/custom_emojis').then(response => {
|
||||||
|
dispatch(fetchCustomEmojisSuccess(response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchCustomEmojisFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchCustomEmojisRequest = () => ({
|
||||||
|
type: CUSTOM_EMOJIS_FETCH_REQUEST,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchCustomEmojisSuccess = (custom_emojis: APIEntity[]) => ({
|
||||||
|
type: CUSTOM_EMOJIS_FETCH_SUCCESS,
|
||||||
|
custom_emojis,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchCustomEmojisFail = (error: AxiosError) => ({
|
||||||
|
type: CUSTOM_EMOJIS_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
CUSTOM_EMOJIS_FETCH_REQUEST,
|
||||||
|
CUSTOM_EMOJIS_FETCH_SUCCESS,
|
||||||
|
CUSTOM_EMOJIS_FETCH_FAIL,
|
||||||
|
fetchCustomEmojis,
|
||||||
|
fetchCustomEmojisRequest,
|
||||||
|
fetchCustomEmojisSuccess,
|
||||||
|
fetchCustomEmojisFail,
|
||||||
|
};
|
|
@ -1,62 +0,0 @@
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
import { fetchRelationships } from './accounts';
|
|
||||||
import { importFetchedAccounts } from './importer';
|
|
||||||
|
|
||||||
export const DIRECTORY_FETCH_REQUEST = 'DIRECTORY_FETCH_REQUEST';
|
|
||||||
export const DIRECTORY_FETCH_SUCCESS = 'DIRECTORY_FETCH_SUCCESS';
|
|
||||||
export const DIRECTORY_FETCH_FAIL = 'DIRECTORY_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const DIRECTORY_EXPAND_REQUEST = 'DIRECTORY_EXPAND_REQUEST';
|
|
||||||
export const DIRECTORY_EXPAND_SUCCESS = 'DIRECTORY_EXPAND_SUCCESS';
|
|
||||||
export const DIRECTORY_EXPAND_FAIL = 'DIRECTORY_EXPAND_FAIL';
|
|
||||||
|
|
||||||
export const fetchDirectory = params => (dispatch, getState) => {
|
|
||||||
dispatch(fetchDirectoryRequest());
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/directory', { params: { ...params, limit: 20 } }).then(({ data }) => {
|
|
||||||
dispatch(importFetchedAccounts(data));
|
|
||||||
dispatch(fetchDirectorySuccess(data));
|
|
||||||
dispatch(fetchRelationships(data.map(x => x.id)));
|
|
||||||
}).catch(error => dispatch(fetchDirectoryFail(error)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchDirectoryRequest = () => ({
|
|
||||||
type: DIRECTORY_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchDirectorySuccess = accounts => ({
|
|
||||||
type: DIRECTORY_FETCH_SUCCESS,
|
|
||||||
accounts,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchDirectoryFail = error => ({
|
|
||||||
type: DIRECTORY_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandDirectory = params => (dispatch, getState) => {
|
|
||||||
dispatch(expandDirectoryRequest());
|
|
||||||
|
|
||||||
const loadedItems = getState().getIn(['user_lists', 'directory', 'items']).size;
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/directory', { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => {
|
|
||||||
dispatch(importFetchedAccounts(data));
|
|
||||||
dispatch(expandDirectorySuccess(data));
|
|
||||||
dispatch(fetchRelationships(data.map(x => x.id)));
|
|
||||||
}).catch(error => dispatch(expandDirectoryFail(error)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const expandDirectoryRequest = () => ({
|
|
||||||
type: DIRECTORY_EXPAND_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandDirectorySuccess = accounts => ({
|
|
||||||
type: DIRECTORY_EXPAND_SUCCESS,
|
|
||||||
accounts,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandDirectoryFail = error => ({
|
|
||||||
type: DIRECTORY_EXPAND_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import { fetchRelationships } from './accounts';
|
||||||
|
import { importFetchedAccounts } from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const DIRECTORY_FETCH_REQUEST = 'DIRECTORY_FETCH_REQUEST';
|
||||||
|
const DIRECTORY_FETCH_SUCCESS = 'DIRECTORY_FETCH_SUCCESS';
|
||||||
|
const DIRECTORY_FETCH_FAIL = 'DIRECTORY_FETCH_FAIL';
|
||||||
|
|
||||||
|
const DIRECTORY_EXPAND_REQUEST = 'DIRECTORY_EXPAND_REQUEST';
|
||||||
|
const DIRECTORY_EXPAND_SUCCESS = 'DIRECTORY_EXPAND_SUCCESS';
|
||||||
|
const DIRECTORY_EXPAND_FAIL = 'DIRECTORY_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const fetchDirectory = (params: Record<string, any>) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(fetchDirectoryRequest());
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/directory', { params: { ...params, limit: 20 } }).then(({ data }) => {
|
||||||
|
dispatch(importFetchedAccounts(data));
|
||||||
|
dispatch(fetchDirectorySuccess(data));
|
||||||
|
dispatch(fetchRelationships(data.map((x: APIEntity) => x.id)));
|
||||||
|
}).catch(error => dispatch(fetchDirectoryFail(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchDirectoryRequest = () => ({
|
||||||
|
type: DIRECTORY_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchDirectorySuccess = (accounts: APIEntity[]) => ({
|
||||||
|
type: DIRECTORY_FETCH_SUCCESS,
|
||||||
|
accounts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchDirectoryFail = (error: AxiosError) => ({
|
||||||
|
type: DIRECTORY_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandDirectory = (params: Record<string, any>) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(expandDirectoryRequest());
|
||||||
|
|
||||||
|
const loadedItems = getState().user_lists.getIn(['directory', 'items']).size;
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/directory', { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => {
|
||||||
|
dispatch(importFetchedAccounts(data));
|
||||||
|
dispatch(expandDirectorySuccess(data));
|
||||||
|
dispatch(fetchRelationships(data.map((x: APIEntity) => x.id)));
|
||||||
|
}).catch(error => dispatch(expandDirectoryFail(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandDirectoryRequest = () => ({
|
||||||
|
type: DIRECTORY_EXPAND_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandDirectorySuccess = (accounts: APIEntity[]) => ({
|
||||||
|
type: DIRECTORY_EXPAND_SUCCESS,
|
||||||
|
accounts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandDirectoryFail = (error: AxiosError) => ({
|
||||||
|
type: DIRECTORY_EXPAND_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
DIRECTORY_FETCH_REQUEST,
|
||||||
|
DIRECTORY_FETCH_SUCCESS,
|
||||||
|
DIRECTORY_FETCH_FAIL,
|
||||||
|
DIRECTORY_EXPAND_REQUEST,
|
||||||
|
DIRECTORY_EXPAND_SUCCESS,
|
||||||
|
DIRECTORY_EXPAND_FAIL,
|
||||||
|
fetchDirectory,
|
||||||
|
fetchDirectoryRequest,
|
||||||
|
fetchDirectorySuccess,
|
||||||
|
fetchDirectoryFail,
|
||||||
|
expandDirectory,
|
||||||
|
expandDirectoryRequest,
|
||||||
|
expandDirectorySuccess,
|
||||||
|
expandDirectoryFail,
|
||||||
|
};
|
|
@ -1,181 +0,0 @@
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api, { getLinks } from '../api';
|
|
||||||
|
|
||||||
export const DOMAIN_BLOCK_REQUEST = 'DOMAIN_BLOCK_REQUEST';
|
|
||||||
export const DOMAIN_BLOCK_SUCCESS = 'DOMAIN_BLOCK_SUCCESS';
|
|
||||||
export const DOMAIN_BLOCK_FAIL = 'DOMAIN_BLOCK_FAIL';
|
|
||||||
|
|
||||||
export const DOMAIN_UNBLOCK_REQUEST = 'DOMAIN_UNBLOCK_REQUEST';
|
|
||||||
export const DOMAIN_UNBLOCK_SUCCESS = 'DOMAIN_UNBLOCK_SUCCESS';
|
|
||||||
export const DOMAIN_UNBLOCK_FAIL = 'DOMAIN_UNBLOCK_FAIL';
|
|
||||||
|
|
||||||
export const DOMAIN_BLOCKS_FETCH_REQUEST = 'DOMAIN_BLOCKS_FETCH_REQUEST';
|
|
||||||
export const DOMAIN_BLOCKS_FETCH_SUCCESS = 'DOMAIN_BLOCKS_FETCH_SUCCESS';
|
|
||||||
export const DOMAIN_BLOCKS_FETCH_FAIL = 'DOMAIN_BLOCKS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const DOMAIN_BLOCKS_EXPAND_REQUEST = 'DOMAIN_BLOCKS_EXPAND_REQUEST';
|
|
||||||
export const DOMAIN_BLOCKS_EXPAND_SUCCESS = 'DOMAIN_BLOCKS_EXPAND_SUCCESS';
|
|
||||||
export const DOMAIN_BLOCKS_EXPAND_FAIL = 'DOMAIN_BLOCKS_EXPAND_FAIL';
|
|
||||||
|
|
||||||
export function blockDomain(domain) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(blockDomainRequest(domain));
|
|
||||||
|
|
||||||
api(getState).post('/api/v1/domain_blocks', { domain }).then(() => {
|
|
||||||
const at_domain = '@' + domain;
|
|
||||||
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));
|
|
||||||
dispatch(blockDomainSuccess(domain, accounts));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(blockDomainFail(domain, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function blockDomainRequest(domain) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCK_REQUEST,
|
|
||||||
domain,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function blockDomainSuccess(domain, accounts) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCK_SUCCESS,
|
|
||||||
domain,
|
|
||||||
accounts,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function blockDomainFail(domain, error) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCK_FAIL,
|
|
||||||
domain,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unblockDomain(domain) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(unblockDomainRequest(domain));
|
|
||||||
|
|
||||||
// Do it both ways for maximum compatibility
|
|
||||||
const params = {
|
|
||||||
params: { domain },
|
|
||||||
data: { domain },
|
|
||||||
};
|
|
||||||
|
|
||||||
api(getState).delete('/api/v1/domain_blocks', params).then(() => {
|
|
||||||
const at_domain = '@' + domain;
|
|
||||||
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));
|
|
||||||
dispatch(unblockDomainSuccess(domain, accounts));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(unblockDomainFail(domain, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unblockDomainRequest(domain) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_UNBLOCK_REQUEST,
|
|
||||||
domain,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unblockDomainSuccess(domain, accounts) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_UNBLOCK_SUCCESS,
|
|
||||||
domain,
|
|
||||||
accounts,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unblockDomainFail(domain, error) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_UNBLOCK_FAIL,
|
|
||||||
domain,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchDomainBlocks() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchDomainBlocksRequest());
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/domain_blocks').then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(fetchDomainBlocksFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchDomainBlocksRequest() {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_FETCH_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchDomainBlocksSuccess(domains, next) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_FETCH_SUCCESS,
|
|
||||||
domains,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchDomainBlocksFail(error) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandDomainBlocks() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const url = getState().getIn(['domain_lists', 'blocks', 'next']);
|
|
||||||
|
|
||||||
if (!url) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandDomainBlocksRequest());
|
|
||||||
|
|
||||||
api(getState).get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(expandDomainBlocksSuccess(response.data, next ? next.uri : null));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(expandDomainBlocksFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandDomainBlocksRequest() {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_EXPAND_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandDomainBlocksSuccess(domains, next) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_EXPAND_SUCCESS,
|
|
||||||
domains,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandDomainBlocksFail(error) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_EXPAND_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { List as ImmutableList } from 'immutable';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
const DOMAIN_BLOCK_REQUEST = 'DOMAIN_BLOCK_REQUEST';
|
||||||
|
const DOMAIN_BLOCK_SUCCESS = 'DOMAIN_BLOCK_SUCCESS';
|
||||||
|
const DOMAIN_BLOCK_FAIL = 'DOMAIN_BLOCK_FAIL';
|
||||||
|
|
||||||
|
const DOMAIN_UNBLOCK_REQUEST = 'DOMAIN_UNBLOCK_REQUEST';
|
||||||
|
const DOMAIN_UNBLOCK_SUCCESS = 'DOMAIN_UNBLOCK_SUCCESS';
|
||||||
|
const DOMAIN_UNBLOCK_FAIL = 'DOMAIN_UNBLOCK_FAIL';
|
||||||
|
|
||||||
|
const DOMAIN_BLOCKS_FETCH_REQUEST = 'DOMAIN_BLOCKS_FETCH_REQUEST';
|
||||||
|
const DOMAIN_BLOCKS_FETCH_SUCCESS = 'DOMAIN_BLOCKS_FETCH_SUCCESS';
|
||||||
|
const DOMAIN_BLOCKS_FETCH_FAIL = 'DOMAIN_BLOCKS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const DOMAIN_BLOCKS_EXPAND_REQUEST = 'DOMAIN_BLOCKS_EXPAND_REQUEST';
|
||||||
|
const DOMAIN_BLOCKS_EXPAND_SUCCESS = 'DOMAIN_BLOCKS_EXPAND_SUCCESS';
|
||||||
|
const DOMAIN_BLOCKS_EXPAND_FAIL = 'DOMAIN_BLOCKS_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const blockDomain = (domain: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(blockDomainRequest(domain));
|
||||||
|
|
||||||
|
api(getState).post('/api/v1/domain_blocks', { domain }).then(() => {
|
||||||
|
const at_domain = '@' + domain;
|
||||||
|
const accounts = getState().accounts.filter(item => item.acct.endsWith(at_domain)).valueSeq().map(item => item.id);
|
||||||
|
dispatch(blockDomainSuccess(domain, accounts.toList()));
|
||||||
|
}).catch(err => {
|
||||||
|
dispatch(blockDomainFail(domain, err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const blockDomainRequest = (domain: string) => ({
|
||||||
|
type: DOMAIN_BLOCK_REQUEST,
|
||||||
|
domain,
|
||||||
|
});
|
||||||
|
|
||||||
|
const blockDomainSuccess = (domain: string, accounts: ImmutableList<string>) => ({
|
||||||
|
type: DOMAIN_BLOCK_SUCCESS,
|
||||||
|
domain,
|
||||||
|
accounts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const blockDomainFail = (domain: string, error: AxiosError) => ({
|
||||||
|
type: DOMAIN_BLOCK_FAIL,
|
||||||
|
domain,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unblockDomain = (domain: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(unblockDomainRequest(domain));
|
||||||
|
|
||||||
|
// Do it both ways for maximum compatibility
|
||||||
|
const params = {
|
||||||
|
params: { domain },
|
||||||
|
data: { domain },
|
||||||
|
};
|
||||||
|
|
||||||
|
api(getState).delete('/api/v1/domain_blocks', params).then(() => {
|
||||||
|
const at_domain = '@' + domain;
|
||||||
|
const accounts = getState().accounts.filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));
|
||||||
|
dispatch(unblockDomainSuccess(domain, accounts.toList()));
|
||||||
|
}).catch(err => {
|
||||||
|
dispatch(unblockDomainFail(domain, err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const unblockDomainRequest = (domain: string) => ({
|
||||||
|
type: DOMAIN_UNBLOCK_REQUEST,
|
||||||
|
domain,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unblockDomainSuccess = (domain: string, accounts: ImmutableList<string>) => ({
|
||||||
|
type: DOMAIN_UNBLOCK_SUCCESS,
|
||||||
|
domain,
|
||||||
|
accounts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unblockDomainFail = (domain: string, error: AxiosError) => ({
|
||||||
|
type: DOMAIN_UNBLOCK_FAIL,
|
||||||
|
domain,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchDomainBlocks = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(fetchDomainBlocksRequest());
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/domain_blocks').then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null));
|
||||||
|
}).catch(err => {
|
||||||
|
dispatch(fetchDomainBlocksFail(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchDomainBlocksRequest = () => ({
|
||||||
|
type: DOMAIN_BLOCKS_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchDomainBlocksSuccess = (domains: string[], next: string | null) => ({
|
||||||
|
type: DOMAIN_BLOCKS_FETCH_SUCCESS,
|
||||||
|
domains,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchDomainBlocksFail = (error: AxiosError) => ({
|
||||||
|
type: DOMAIN_BLOCKS_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandDomainBlocks = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
const url = getState().domain_lists.blocks.next;
|
||||||
|
|
||||||
|
if (!url) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandDomainBlocksRequest());
|
||||||
|
|
||||||
|
api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(expandDomainBlocksSuccess(response.data, next ? next.uri : null));
|
||||||
|
}).catch(err => {
|
||||||
|
dispatch(expandDomainBlocksFail(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandDomainBlocksRequest = () => ({
|
||||||
|
type: DOMAIN_BLOCKS_EXPAND_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandDomainBlocksSuccess = (domains: string[], next: string | null) => ({
|
||||||
|
type: DOMAIN_BLOCKS_EXPAND_SUCCESS,
|
||||||
|
domains,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandDomainBlocksFail = (error: AxiosError) => ({
|
||||||
|
type: DOMAIN_BLOCKS_EXPAND_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
DOMAIN_BLOCK_REQUEST,
|
||||||
|
DOMAIN_BLOCK_SUCCESS,
|
||||||
|
DOMAIN_BLOCK_FAIL,
|
||||||
|
DOMAIN_UNBLOCK_REQUEST,
|
||||||
|
DOMAIN_UNBLOCK_SUCCESS,
|
||||||
|
DOMAIN_UNBLOCK_FAIL,
|
||||||
|
DOMAIN_BLOCKS_FETCH_REQUEST,
|
||||||
|
DOMAIN_BLOCKS_FETCH_SUCCESS,
|
||||||
|
DOMAIN_BLOCKS_FETCH_FAIL,
|
||||||
|
DOMAIN_BLOCKS_EXPAND_REQUEST,
|
||||||
|
DOMAIN_BLOCKS_EXPAND_SUCCESS,
|
||||||
|
DOMAIN_BLOCKS_EXPAND_FAIL,
|
||||||
|
blockDomain,
|
||||||
|
blockDomainRequest,
|
||||||
|
blockDomainSuccess,
|
||||||
|
blockDomainFail,
|
||||||
|
unblockDomain,
|
||||||
|
unblockDomainRequest,
|
||||||
|
unblockDomainSuccess,
|
||||||
|
unblockDomainFail,
|
||||||
|
fetchDomainBlocks,
|
||||||
|
fetchDomainBlocksRequest,
|
||||||
|
fetchDomainBlocksSuccess,
|
||||||
|
fetchDomainBlocksFail,
|
||||||
|
expandDomainBlocks,
|
||||||
|
expandDomainBlocksRequest,
|
||||||
|
expandDomainBlocksSuccess,
|
||||||
|
expandDomainBlocksFail,
|
||||||
|
};
|
|
@ -1,10 +0,0 @@
|
||||||
export const DROPDOWN_MENU_OPEN = 'DROPDOWN_MENU_OPEN';
|
|
||||||
export const DROPDOWN_MENU_CLOSE = 'DROPDOWN_MENU_CLOSE';
|
|
||||||
|
|
||||||
export function openDropdownMenu(id, placement, keyboard) {
|
|
||||||
return { type: DROPDOWN_MENU_OPEN, id, placement, keyboard };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function closeDropdownMenu(id) {
|
|
||||||
return { type: DROPDOWN_MENU_CLOSE, id };
|
|
||||||
}
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import type { DropdownPlacement } from 'soapbox/components/dropdown_menu';
|
||||||
|
|
||||||
|
const DROPDOWN_MENU_OPEN = 'DROPDOWN_MENU_OPEN';
|
||||||
|
const DROPDOWN_MENU_CLOSE = 'DROPDOWN_MENU_CLOSE';
|
||||||
|
|
||||||
|
const openDropdownMenu = (id: number, placement: DropdownPlacement, keyboard: boolean) =>
|
||||||
|
({ type: DROPDOWN_MENU_OPEN, id, placement, keyboard });
|
||||||
|
|
||||||
|
const closeDropdownMenu = (id: number) =>
|
||||||
|
({ type: DROPDOWN_MENU_CLOSE, id });
|
||||||
|
|
||||||
|
export {
|
||||||
|
DROPDOWN_MENU_OPEN,
|
||||||
|
DROPDOWN_MENU_CLOSE,
|
||||||
|
openDropdownMenu,
|
||||||
|
closeDropdownMenu,
|
||||||
|
};
|
|
@ -1,19 +0,0 @@
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
export function getSubscribersCsv() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
return api(getState).get('/api/v1/pleroma/admin/email_list/subscribers.csv');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getUnsubscribersCsv() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
return api(getState).get('/api/v1/pleroma/admin/email_list/unsubscribers.csv');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCombinedCsv() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
return api(getState).get('/api/v1/pleroma/admin/email_list/combined.csv');
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import type { RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
const getSubscribersCsv = () =>
|
||||||
|
(dispatch: any, getState: () => RootState) =>
|
||||||
|
api(getState).get('/api/v1/pleroma/admin/email_list/subscribers.csv');
|
||||||
|
|
||||||
|
const getUnsubscribersCsv = () =>
|
||||||
|
(dispatch: any, getState: () => RootState) =>
|
||||||
|
api(getState).get('/api/v1/pleroma/admin/email_list/unsubscribers.csv');
|
||||||
|
|
||||||
|
const getCombinedCsv = () =>
|
||||||
|
(dispatch: any, getState: () => RootState) =>
|
||||||
|
api(getState).get('/api/v1/pleroma/admin/email_list/combined.csv');
|
||||||
|
|
||||||
|
export {
|
||||||
|
getSubscribersCsv,
|
||||||
|
getUnsubscribersCsv,
|
||||||
|
getCombinedCsv,
|
||||||
|
};
|
|
@ -1,182 +0,0 @@
|
||||||
import { List as ImmutableList } from 'immutable';
|
|
||||||
|
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
|
||||||
import { favourite, unfavourite } from './interactions';
|
|
||||||
|
|
||||||
export const EMOJI_REACT_REQUEST = 'EMOJI_REACT_REQUEST';
|
|
||||||
export const EMOJI_REACT_SUCCESS = 'EMOJI_REACT_SUCCESS';
|
|
||||||
export const EMOJI_REACT_FAIL = 'EMOJI_REACT_FAIL';
|
|
||||||
|
|
||||||
export const UNEMOJI_REACT_REQUEST = 'UNEMOJI_REACT_REQUEST';
|
|
||||||
export const UNEMOJI_REACT_SUCCESS = 'UNEMOJI_REACT_SUCCESS';
|
|
||||||
export const UNEMOJI_REACT_FAIL = 'UNEMOJI_REACT_FAIL';
|
|
||||||
|
|
||||||
export const EMOJI_REACTS_FETCH_REQUEST = 'EMOJI_REACTS_FETCH_REQUEST';
|
|
||||||
export const EMOJI_REACTS_FETCH_SUCCESS = 'EMOJI_REACTS_FETCH_SUCCESS';
|
|
||||||
export const EMOJI_REACTS_FETCH_FAIL = 'EMOJI_REACTS_FETCH_FAIL';
|
|
||||||
|
|
||||||
const noOp = () => () => new Promise(f => f());
|
|
||||||
|
|
||||||
export const simpleEmojiReact = (status, emoji) => {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const emojiReacts = status.getIn(['pleroma', 'emoji_reactions'], ImmutableList());
|
|
||||||
|
|
||||||
if (emoji === '👍' && status.get('favourited')) return dispatch(unfavourite(status));
|
|
||||||
|
|
||||||
const undo = emojiReacts.filter(e => e.get('me') === true && e.get('name') === emoji).count() > 0;
|
|
||||||
if (undo) return dispatch(unEmojiReact(status, emoji));
|
|
||||||
|
|
||||||
return Promise.all(
|
|
||||||
emojiReacts
|
|
||||||
.filter(emojiReact => emojiReact.get('me') === true)
|
|
||||||
.map(emojiReact => dispatch(unEmojiReact(status, emojiReact.get('name')))),
|
|
||||||
status.get('favourited') && dispatch(unfavourite(status)),
|
|
||||||
).then(() => {
|
|
||||||
if (emoji === '👍') {
|
|
||||||
dispatch(favourite(status));
|
|
||||||
} else {
|
|
||||||
dispatch(emojiReact(status, emoji));
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export function fetchEmojiReacts(id, emoji) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return dispatch(noOp());
|
|
||||||
|
|
||||||
dispatch(fetchEmojiReactsRequest(id, emoji));
|
|
||||||
|
|
||||||
const url = emoji
|
|
||||||
? `/api/v1/pleroma/statuses/${id}/reactions/${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));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function emojiReact(status, emoji) {
|
|
||||||
return function(dispatch, getState) {
|
|
||||||
if (!isLoggedIn(getState)) return dispatch(noOp());
|
|
||||||
|
|
||||||
dispatch(emojiReactRequest(status, emoji));
|
|
||||||
|
|
||||||
return api(getState)
|
|
||||||
.put(`/api/v1/pleroma/statuses/${status.get('id')}/reactions/${emoji}`)
|
|
||||||
.then(function(response) {
|
|
||||||
dispatch(importFetchedStatus(response.data));
|
|
||||||
dispatch(emojiReactSuccess(status, emoji));
|
|
||||||
}).catch(function(error) {
|
|
||||||
dispatch(emojiReactFail(status, emoji, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unEmojiReact(status, emoji) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return dispatch(noOp());
|
|
||||||
|
|
||||||
dispatch(unEmojiReactRequest(status, emoji));
|
|
||||||
|
|
||||||
return api(getState)
|
|
||||||
.delete(`/api/v1/pleroma/statuses/${status.get('id')}/reactions/${emoji}`)
|
|
||||||
.then(response => {
|
|
||||||
dispatch(importFetchedStatus(response.data));
|
|
||||||
dispatch(unEmojiReactSuccess(status, emoji));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(unEmojiReactFail(status, emoji, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchEmojiReactsRequest(id, emoji) {
|
|
||||||
return {
|
|
||||||
type: EMOJI_REACTS_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
emoji,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchEmojiReactsSuccess(id, emojiReacts) {
|
|
||||||
return {
|
|
||||||
type: EMOJI_REACTS_FETCH_SUCCESS,
|
|
||||||
id,
|
|
||||||
emojiReacts,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchEmojiReactsFail(id, error) {
|
|
||||||
return {
|
|
||||||
type: EMOJI_REACTS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function emojiReactRequest(status, emoji) {
|
|
||||||
return {
|
|
||||||
type: EMOJI_REACT_REQUEST,
|
|
||||||
status,
|
|
||||||
emoji,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function emojiReactSuccess(status, emoji) {
|
|
||||||
return {
|
|
||||||
type: EMOJI_REACT_SUCCESS,
|
|
||||||
status,
|
|
||||||
emoji,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function emojiReactFail(status, emoji, error) {
|
|
||||||
return {
|
|
||||||
type: EMOJI_REACT_FAIL,
|
|
||||||
status,
|
|
||||||
emoji,
|
|
||||||
error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unEmojiReactRequest(status, emoji) {
|
|
||||||
return {
|
|
||||||
type: UNEMOJI_REACT_REQUEST,
|
|
||||||
status,
|
|
||||||
emoji,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unEmojiReactSuccess(status, emoji) {
|
|
||||||
return {
|
|
||||||
type: UNEMOJI_REACT_SUCCESS,
|
|
||||||
status,
|
|
||||||
emoji,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unEmojiReactFail(status, emoji, error) {
|
|
||||||
return {
|
|
||||||
type: UNEMOJI_REACT_FAIL,
|
|
||||||
status,
|
|
||||||
emoji,
|
|
||||||
error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||||
|
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||||
|
import { favourite, unfavourite } from './interactions';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity, Status } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const EMOJI_REACT_REQUEST = 'EMOJI_REACT_REQUEST';
|
||||||
|
const EMOJI_REACT_SUCCESS = 'EMOJI_REACT_SUCCESS';
|
||||||
|
const EMOJI_REACT_FAIL = 'EMOJI_REACT_FAIL';
|
||||||
|
|
||||||
|
const UNEMOJI_REACT_REQUEST = 'UNEMOJI_REACT_REQUEST';
|
||||||
|
const UNEMOJI_REACT_SUCCESS = 'UNEMOJI_REACT_SUCCESS';
|
||||||
|
const UNEMOJI_REACT_FAIL = 'UNEMOJI_REACT_FAIL';
|
||||||
|
|
||||||
|
const EMOJI_REACTS_FETCH_REQUEST = 'EMOJI_REACTS_FETCH_REQUEST';
|
||||||
|
const EMOJI_REACTS_FETCH_SUCCESS = 'EMOJI_REACTS_FETCH_SUCCESS';
|
||||||
|
const EMOJI_REACTS_FETCH_FAIL = 'EMOJI_REACTS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const noOp = () => () => new Promise(f => f(undefined));
|
||||||
|
|
||||||
|
const simpleEmojiReact = (status: Status, emoji: string) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
const emojiReacts: ImmutableList<ImmutableMap<string, any>> = status.pleroma.get('emoji_reactions') || ImmutableList();
|
||||||
|
|
||||||
|
if (emoji === '👍' && status.favourited) return dispatch(unfavourite(status));
|
||||||
|
|
||||||
|
const undo = emojiReacts.filter(e => e.get('me') === true && e.get('name') === emoji).count() > 0;
|
||||||
|
if (undo) return dispatch(unEmojiReact(status, emoji));
|
||||||
|
|
||||||
|
return Promise.all([
|
||||||
|
...emojiReacts
|
||||||
|
.filter((emojiReact) => emojiReact.get('me') === true)
|
||||||
|
.map(emojiReact => dispatch(unEmojiReact(status, emojiReact.get('name')))).toArray(),
|
||||||
|
status.favourited && dispatch(unfavourite(status)),
|
||||||
|
]).then(() => {
|
||||||
|
if (emoji === '👍') {
|
||||||
|
dispatch(favourite(status));
|
||||||
|
} else {
|
||||||
|
dispatch(emojiReact(status, emoji));
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchEmojiReacts = (id: string, emoji: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return dispatch(noOp());
|
||||||
|
|
||||||
|
dispatch(fetchEmojiReactsRequest(id, emoji));
|
||||||
|
|
||||||
|
const url = emoji
|
||||||
|
? `/api/v1/pleroma/statuses/${id}/reactions/${emoji}`
|
||||||
|
: `/api/v1/pleroma/statuses/${id}/reactions`;
|
||||||
|
|
||||||
|
return api(getState).get(url).then(response => {
|
||||||
|
response.data.forEach((emojiReact: APIEntity) => {
|
||||||
|
dispatch(importFetchedAccounts(emojiReact.accounts));
|
||||||
|
});
|
||||||
|
dispatch(fetchEmojiReactsSuccess(id, response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchEmojiReactsFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const emojiReact = (status: Status, emoji: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return dispatch(noOp());
|
||||||
|
|
||||||
|
dispatch(emojiReactRequest(status, emoji));
|
||||||
|
|
||||||
|
return api(getState)
|
||||||
|
.put(`/api/v1/pleroma/statuses/${status.get('id')}/reactions/${emoji}`)
|
||||||
|
.then(function(response) {
|
||||||
|
dispatch(importFetchedStatus(response.data));
|
||||||
|
dispatch(emojiReactSuccess(status, emoji));
|
||||||
|
}).catch(function(error) {
|
||||||
|
dispatch(emojiReactFail(status, emoji, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const unEmojiReact = (status: Status, emoji: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return dispatch(noOp());
|
||||||
|
|
||||||
|
dispatch(unEmojiReactRequest(status, emoji));
|
||||||
|
|
||||||
|
return api(getState)
|
||||||
|
.delete(`/api/v1/pleroma/statuses/${status.get('id')}/reactions/${emoji}`)
|
||||||
|
.then(response => {
|
||||||
|
dispatch(importFetchedStatus(response.data));
|
||||||
|
dispatch(unEmojiReactSuccess(status, emoji));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(unEmojiReactFail(status, emoji, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchEmojiReactsRequest = (id: string, emoji: string) => ({
|
||||||
|
type: EMOJI_REACTS_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
emoji,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchEmojiReactsSuccess = (id: string, emojiReacts: APIEntity[]) => ({
|
||||||
|
type: EMOJI_REACTS_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
emojiReacts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchEmojiReactsFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: EMOJI_REACTS_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emojiReactRequest = (status: Status, emoji: string) => ({
|
||||||
|
type: EMOJI_REACT_REQUEST,
|
||||||
|
status,
|
||||||
|
emoji,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emojiReactSuccess = (status: Status, emoji: string) => ({
|
||||||
|
type: EMOJI_REACT_SUCCESS,
|
||||||
|
status,
|
||||||
|
emoji,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emojiReactFail = (status: Status, emoji: string, error: AxiosError) => ({
|
||||||
|
type: EMOJI_REACT_FAIL,
|
||||||
|
status,
|
||||||
|
emoji,
|
||||||
|
error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unEmojiReactRequest = (status: Status, emoji: string) => ({
|
||||||
|
type: UNEMOJI_REACT_REQUEST,
|
||||||
|
status,
|
||||||
|
emoji,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unEmojiReactSuccess = (status: Status, emoji: string) => ({
|
||||||
|
type: UNEMOJI_REACT_SUCCESS,
|
||||||
|
status,
|
||||||
|
emoji,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unEmojiReactFail = (status: Status, emoji: string, error: AxiosError) => ({
|
||||||
|
type: UNEMOJI_REACT_FAIL,
|
||||||
|
status,
|
||||||
|
emoji,
|
||||||
|
error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
EMOJI_REACT_REQUEST,
|
||||||
|
EMOJI_REACT_SUCCESS,
|
||||||
|
EMOJI_REACT_FAIL,
|
||||||
|
UNEMOJI_REACT_REQUEST,
|
||||||
|
UNEMOJI_REACT_SUCCESS,
|
||||||
|
UNEMOJI_REACT_FAIL,
|
||||||
|
EMOJI_REACTS_FETCH_REQUEST,
|
||||||
|
EMOJI_REACTS_FETCH_SUCCESS,
|
||||||
|
EMOJI_REACTS_FETCH_FAIL,
|
||||||
|
simpleEmojiReact,
|
||||||
|
fetchEmojiReacts,
|
||||||
|
emojiReact,
|
||||||
|
unEmojiReact,
|
||||||
|
fetchEmojiReactsRequest,
|
||||||
|
fetchEmojiReactsSuccess,
|
||||||
|
fetchEmojiReactsFail,
|
||||||
|
emojiReactRequest,
|
||||||
|
emojiReactSuccess,
|
||||||
|
emojiReactFail,
|
||||||
|
unEmojiReactRequest,
|
||||||
|
unEmojiReactSuccess,
|
||||||
|
unEmojiReactFail,
|
||||||
|
};
|
|
@ -1,14 +0,0 @@
|
||||||
import { saveSettings } from './settings';
|
|
||||||
|
|
||||||
export const EMOJI_USE = 'EMOJI_USE';
|
|
||||||
|
|
||||||
export function useEmoji(emoji) {
|
|
||||||
return dispatch => {
|
|
||||||
dispatch({
|
|
||||||
type: EMOJI_USE,
|
|
||||||
emoji,
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(saveSettings());
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { saveSettings } from './settings';
|
||||||
|
|
||||||
|
import type { Emoji } from 'soapbox/components/autosuggest_emoji';
|
||||||
|
import type { AppDispatch } from 'soapbox/store';
|
||||||
|
|
||||||
|
const EMOJI_USE = 'EMOJI_USE';
|
||||||
|
|
||||||
|
const useEmoji = (emoji: Emoji) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: EMOJI_USE,
|
||||||
|
emoji,
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(saveSettings());
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
EMOJI_USE,
|
||||||
|
useEmoji,
|
||||||
|
};
|
|
@ -18,7 +18,10 @@ import { getQuirks } from 'soapbox/utils/quirks';
|
||||||
|
|
||||||
import { baseClient } from '../api';
|
import { baseClient } from '../api';
|
||||||
|
|
||||||
const fetchExternalInstance = baseURL => {
|
import type { AppDispatch } from 'soapbox/store';
|
||||||
|
import type { Instance } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const fetchExternalInstance = (baseURL?: string) => {
|
||||||
return baseClient(null, baseURL)
|
return baseClient(null, baseURL)
|
||||||
.get('/api/v1/instance')
|
.get('/api/v1/instance')
|
||||||
.then(({ data: instance }) => normalizeInstance(instance))
|
.then(({ data: instance }) => normalizeInstance(instance))
|
||||||
|
@ -33,8 +36,8 @@ const fetchExternalInstance = baseURL => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function createExternalApp(instance, baseURL) {
|
const createExternalApp = (instance: Instance, baseURL?: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => {
|
||||||
// Mitra: skip creating the auth app
|
// Mitra: skip creating the auth app
|
||||||
if (getQuirks(instance).noApps) return new Promise(f => f({}));
|
if (getQuirks(instance).noApps) return new Promise(f => f({}));
|
||||||
|
|
||||||
|
@ -49,14 +52,13 @@ function createExternalApp(instance, baseURL) {
|
||||||
|
|
||||||
return dispatch(createApp(params, baseURL));
|
return dispatch(createApp(params, baseURL));
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function externalAuthorize(instance, baseURL) {
|
const externalAuthorize = (instance: Instance, baseURL: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => {
|
||||||
const { scopes } = getFeatures(instance);
|
const { scopes } = getFeatures(instance);
|
||||||
|
|
||||||
return dispatch(createExternalApp(instance, baseURL)).then(app => {
|
return dispatch(createExternalApp(instance, baseURL)).then((app) => {
|
||||||
const { client_id, redirect_uri } = app;
|
const { client_id, redirect_uri } = app as Record<string, string>;
|
||||||
|
|
||||||
const query = new URLSearchParams({
|
const query = new URLSearchParams({
|
||||||
client_id,
|
client_id,
|
||||||
|
@ -72,58 +74,56 @@ function externalAuthorize(instance, baseURL) {
|
||||||
window.location.href = `${baseURL}/oauth/authorize?${query.toString()}`;
|
window.location.href = `${baseURL}/oauth/authorize?${query.toString()}`;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function externalEthereumLogin(instance, baseURL) {
|
const externalEthereumLogin = (instance: Instance, baseURL?: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => {
|
||||||
const loginMessage = instance.get('login_message');
|
const loginMessage = instance.login_message;
|
||||||
|
|
||||||
return getWalletAndSign(loginMessage).then(({ wallet, signature }) => {
|
return getWalletAndSign(loginMessage).then(({ wallet, signature }) => {
|
||||||
return dispatch(createExternalApp(instance, baseURL)).then(app => {
|
return dispatch(createExternalApp(instance, baseURL)).then((app) => {
|
||||||
|
const { client_id, client_secret } = app as Record<string, string>;
|
||||||
const params = {
|
const params = {
|
||||||
grant_type: 'ethereum',
|
grant_type: 'ethereum',
|
||||||
wallet_address: wallet.toLowerCase(),
|
wallet_address: wallet.toLowerCase(),
|
||||||
client_id: app.client_id,
|
client_id: client_id,
|
||||||
client_secret: app.client_secret,
|
client_secret: client_secret,
|
||||||
password: signature,
|
password: signature as string,
|
||||||
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
|
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
|
||||||
scope: getFeatures(instance).scopes,
|
scope: getFeatures(instance).scopes,
|
||||||
};
|
};
|
||||||
|
|
||||||
return dispatch(obtainOAuthToken(params, baseURL))
|
return dispatch(obtainOAuthToken(params, baseURL))
|
||||||
.then(token => dispatch(authLoggedIn(token)))
|
.then((token: Record<string, string | number>) => dispatch(authLoggedIn(token)))
|
||||||
.then(({ access_token }) => dispatch(verifyCredentials(access_token, baseURL)))
|
.then(({ access_token }: any) => dispatch(verifyCredentials(access_token, baseURL)))
|
||||||
.then(account => dispatch(switchAccount(account.id)))
|
.then((account: { id: string }) => dispatch(switchAccount(account.id)))
|
||||||
.then(() => window.location.href = '/');
|
.then(() => window.location.href = '/');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function externalLogin(host) {
|
export const externalLogin = (host: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => {
|
||||||
const baseURL = parseBaseURL(host) || parseBaseURL(`https://${host}`);
|
const baseURL = parseBaseURL(host) || parseBaseURL(`https://${host}`);
|
||||||
|
|
||||||
return fetchExternalInstance(baseURL).then(instance => {
|
return fetchExternalInstance(baseURL).then((instance) => {
|
||||||
const features = getFeatures(instance);
|
const features = getFeatures(instance);
|
||||||
const quirks = getQuirks(instance);
|
const quirks = getQuirks(instance);
|
||||||
|
|
||||||
if (features.ethereumLogin && quirks.noOAuthForm) {
|
if (features.ethereumLogin && quirks.noOAuthForm) {
|
||||||
return dispatch(externalEthereumLogin(instance, baseURL));
|
dispatch(externalEthereumLogin(instance, baseURL));
|
||||||
} else {
|
} else {
|
||||||
return dispatch(externalAuthorize(instance, baseURL));
|
dispatch(externalAuthorize(instance, baseURL));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function loginWithCode(code) {
|
export const loginWithCode = (code: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => {
|
||||||
const { client_id, client_secret, redirect_uri } = JSON.parse(localStorage.getItem('soapbox:external:app'));
|
const { client_id, client_secret, redirect_uri } = JSON.parse(localStorage.getItem('soapbox:external:app')!);
|
||||||
const baseURL = localStorage.getItem('soapbox:external:baseurl');
|
const baseURL = localStorage.getItem('soapbox:external:baseurl')!;
|
||||||
const scope = localStorage.getItem('soapbox:external:scopes');
|
const scope = localStorage.getItem('soapbox:external:scopes')!;
|
||||||
|
|
||||||
const params = {
|
const params: Record<string, string> = {
|
||||||
client_id,
|
client_id,
|
||||||
client_secret,
|
client_secret,
|
||||||
redirect_uri,
|
redirect_uri,
|
||||||
|
@ -133,9 +133,8 @@ export function loginWithCode(code) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return dispatch(obtainOAuthToken(params, baseURL))
|
return dispatch(obtainOAuthToken(params, baseURL))
|
||||||
.then(token => dispatch(authLoggedIn(token)))
|
.then((token: Record<string, string | number>) => dispatch(authLoggedIn(token)))
|
||||||
.then(({ access_token }) => dispatch(verifyCredentials(access_token, baseURL)))
|
.then(({ access_token }: any) => dispatch(verifyCredentials(access_token as string, baseURL)))
|
||||||
.then(account => dispatch(switchAccount(account.id)))
|
.then((account: { id: string }) => dispatch(switchAccount(account.id)))
|
||||||
.then(() => window.location.href = '/');
|
.then(() => window.location.href = '/');
|
||||||
};
|
};
|
||||||
}
|
|
|
@ -1,201 +0,0 @@
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api, { getLinks } from '../api';
|
|
||||||
|
|
||||||
import { importFetchedStatuses } from './importer';
|
|
||||||
|
|
||||||
export const FAVOURITED_STATUSES_FETCH_REQUEST = 'FAVOURITED_STATUSES_FETCH_REQUEST';
|
|
||||||
export const FAVOURITED_STATUSES_FETCH_SUCCESS = 'FAVOURITED_STATUSES_FETCH_SUCCESS';
|
|
||||||
export const FAVOURITED_STATUSES_FETCH_FAIL = 'FAVOURITED_STATUSES_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const FAVOURITED_STATUSES_EXPAND_REQUEST = 'FAVOURITED_STATUSES_EXPAND_REQUEST';
|
|
||||||
export const FAVOURITED_STATUSES_EXPAND_SUCCESS = 'FAVOURITED_STATUSES_EXPAND_SUCCESS';
|
|
||||||
export const FAVOURITED_STATUSES_EXPAND_FAIL = 'FAVOURITED_STATUSES_EXPAND_FAIL';
|
|
||||||
|
|
||||||
export const ACCOUNT_FAVOURITED_STATUSES_FETCH_REQUEST = 'ACCOUNT_FAVOURITED_STATUSES_FETCH_REQUEST';
|
|
||||||
export const ACCOUNT_FAVOURITED_STATUSES_FETCH_SUCCESS = 'ACCOUNT_FAVOURITED_STATUSES_FETCH_SUCCESS';
|
|
||||||
export const ACCOUNT_FAVOURITED_STATUSES_FETCH_FAIL = 'ACCOUNT_FAVOURITED_STATUSES_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const ACCOUNT_FAVOURITED_STATUSES_EXPAND_REQUEST = 'ACCOUNT_FAVOURITED_STATUSES_EXPAND_REQUEST';
|
|
||||||
export const ACCOUNT_FAVOURITED_STATUSES_EXPAND_SUCCESS = 'ACCOUNT_FAVOURITED_STATUSES_EXPAND_SUCCESS';
|
|
||||||
export const ACCOUNT_FAVOURITED_STATUSES_EXPAND_FAIL = 'ACCOUNT_FAVOURITED_STATUSES_EXPAND_FAIL';
|
|
||||||
|
|
||||||
export function fetchFavouritedStatuses() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
if (getState().getIn(['status_lists', 'favourites', 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchFavouritedStatusesRequest());
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/favourites').then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedStatuses(response.data));
|
|
||||||
dispatch(fetchFavouritedStatusesSuccess(response.data, next ? next.uri : null));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchFavouritedStatusesFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchFavouritedStatusesRequest() {
|
|
||||||
return {
|
|
||||||
type: FAVOURITED_STATUSES_FETCH_REQUEST,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchFavouritedStatusesSuccess(statuses, next) {
|
|
||||||
return {
|
|
||||||
type: FAVOURITED_STATUSES_FETCH_SUCCESS,
|
|
||||||
statuses,
|
|
||||||
next,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchFavouritedStatusesFail(error) {
|
|
||||||
return {
|
|
||||||
type: FAVOURITED_STATUSES_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandFavouritedStatuses() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const url = getState().getIn(['status_lists', 'favourites', 'next'], null);
|
|
||||||
|
|
||||||
if (url === null || getState().getIn(['status_lists', 'favourites', 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandFavouritedStatusesRequest());
|
|
||||||
|
|
||||||
api(getState).get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedStatuses(response.data));
|
|
||||||
dispatch(expandFavouritedStatusesSuccess(response.data, next ? next.uri : null));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(expandFavouritedStatusesFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandFavouritedStatusesRequest() {
|
|
||||||
return {
|
|
||||||
type: FAVOURITED_STATUSES_EXPAND_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandFavouritedStatusesSuccess(statuses, next) {
|
|
||||||
return {
|
|
||||||
type: FAVOURITED_STATUSES_EXPAND_SUCCESS,
|
|
||||||
statuses,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandFavouritedStatusesFail(error) {
|
|
||||||
return {
|
|
||||||
type: FAVOURITED_STATUSES_EXPAND_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchAccountFavouritedStatuses(accountId) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
if (getState().getIn(['status_lists', `favourites:${accountId}`, 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchAccountFavouritedStatusesRequest(accountId));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/pleroma/accounts/${accountId}/favourites`).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedStatuses(response.data));
|
|
||||||
dispatch(fetchAccountFavouritedStatusesSuccess(accountId, response.data, next ? next.uri : null));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchAccountFavouritedStatusesFail(accountId, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchAccountFavouritedStatusesRequest(accountId) {
|
|
||||||
return {
|
|
||||||
type: ACCOUNT_FAVOURITED_STATUSES_FETCH_REQUEST,
|
|
||||||
accountId,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchAccountFavouritedStatusesSuccess(accountId, statuses, next) {
|
|
||||||
return {
|
|
||||||
type: ACCOUNT_FAVOURITED_STATUSES_FETCH_SUCCESS,
|
|
||||||
accountId,
|
|
||||||
statuses,
|
|
||||||
next,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchAccountFavouritedStatusesFail(accountId, error) {
|
|
||||||
return {
|
|
||||||
type: ACCOUNT_FAVOURITED_STATUSES_FETCH_FAIL,
|
|
||||||
accountId,
|
|
||||||
error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandAccountFavouritedStatuses(accountId) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const url = getState().getIn(['status_lists', `favourites:${accountId}`, 'next'], null);
|
|
||||||
|
|
||||||
if (url === null || getState().getIn(['status_lists', `favourites:${accountId}`, 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandAccountFavouritedStatusesRequest(accountId));
|
|
||||||
|
|
||||||
api(getState).get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedStatuses(response.data));
|
|
||||||
dispatch(expandAccountFavouritedStatusesSuccess(accountId, response.data, next ? next.uri : null));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(expandAccountFavouritedStatusesFail(accountId, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandAccountFavouritedStatusesRequest(accountId) {
|
|
||||||
return {
|
|
||||||
type: ACCOUNT_FAVOURITED_STATUSES_EXPAND_REQUEST,
|
|
||||||
accountId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandAccountFavouritedStatusesSuccess(accountId, statuses, next) {
|
|
||||||
return {
|
|
||||||
type: ACCOUNT_FAVOURITED_STATUSES_EXPAND_SUCCESS,
|
|
||||||
accountId,
|
|
||||||
statuses,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandAccountFavouritedStatusesFail(accountId, error) {
|
|
||||||
return {
|
|
||||||
type: ACCOUNT_FAVOURITED_STATUSES_EXPAND_FAIL,
|
|
||||||
accountId,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,208 @@
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
|
import { importFetchedStatuses } from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const FAVOURITED_STATUSES_FETCH_REQUEST = 'FAVOURITED_STATUSES_FETCH_REQUEST';
|
||||||
|
const FAVOURITED_STATUSES_FETCH_SUCCESS = 'FAVOURITED_STATUSES_FETCH_SUCCESS';
|
||||||
|
const FAVOURITED_STATUSES_FETCH_FAIL = 'FAVOURITED_STATUSES_FETCH_FAIL';
|
||||||
|
|
||||||
|
const FAVOURITED_STATUSES_EXPAND_REQUEST = 'FAVOURITED_STATUSES_EXPAND_REQUEST';
|
||||||
|
const FAVOURITED_STATUSES_EXPAND_SUCCESS = 'FAVOURITED_STATUSES_EXPAND_SUCCESS';
|
||||||
|
const FAVOURITED_STATUSES_EXPAND_FAIL = 'FAVOURITED_STATUSES_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const ACCOUNT_FAVOURITED_STATUSES_FETCH_REQUEST = 'ACCOUNT_FAVOURITED_STATUSES_FETCH_REQUEST';
|
||||||
|
const ACCOUNT_FAVOURITED_STATUSES_FETCH_SUCCESS = 'ACCOUNT_FAVOURITED_STATUSES_FETCH_SUCCESS';
|
||||||
|
const ACCOUNT_FAVOURITED_STATUSES_FETCH_FAIL = 'ACCOUNT_FAVOURITED_STATUSES_FETCH_FAIL';
|
||||||
|
|
||||||
|
const ACCOUNT_FAVOURITED_STATUSES_EXPAND_REQUEST = 'ACCOUNT_FAVOURITED_STATUSES_EXPAND_REQUEST';
|
||||||
|
const ACCOUNT_FAVOURITED_STATUSES_EXPAND_SUCCESS = 'ACCOUNT_FAVOURITED_STATUSES_EXPAND_SUCCESS';
|
||||||
|
const ACCOUNT_FAVOURITED_STATUSES_EXPAND_FAIL = 'ACCOUNT_FAVOURITED_STATUSES_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const fetchFavouritedStatuses = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
if (getState().status_lists.get('favourites')?.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchFavouritedStatusesRequest());
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/favourites').then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch(fetchFavouritedStatusesSuccess(response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchFavouritedStatusesFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchFavouritedStatusesRequest = () => ({
|
||||||
|
type: FAVOURITED_STATUSES_FETCH_REQUEST,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchFavouritedStatusesSuccess = (statuses: APIEntity[], next: string | null) => ({
|
||||||
|
type: FAVOURITED_STATUSES_FETCH_SUCCESS,
|
||||||
|
statuses,
|
||||||
|
next,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchFavouritedStatusesFail = (error: AxiosError) => ({
|
||||||
|
type: FAVOURITED_STATUSES_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandFavouritedStatuses = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
const url = getState().status_lists.get('favourites')?.next || null;
|
||||||
|
|
||||||
|
if (url === null || getState().status_lists.get('favourites')?.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandFavouritedStatusesRequest());
|
||||||
|
|
||||||
|
api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch(expandFavouritedStatusesSuccess(response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandFavouritedStatusesFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandFavouritedStatusesRequest = () => ({
|
||||||
|
type: FAVOURITED_STATUSES_EXPAND_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandFavouritedStatusesSuccess = (statuses: APIEntity[], next: string | null) => ({
|
||||||
|
type: FAVOURITED_STATUSES_EXPAND_SUCCESS,
|
||||||
|
statuses,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandFavouritedStatusesFail = (error: AxiosError) => ({
|
||||||
|
type: FAVOURITED_STATUSES_EXPAND_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchAccountFavouritedStatuses = (accountId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
if (getState().status_lists.get(`favourites:${accountId}`)?.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchAccountFavouritedStatusesRequest(accountId));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/pleroma/accounts/${accountId}/favourites`).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch(fetchAccountFavouritedStatusesSuccess(accountId, response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchAccountFavouritedStatusesFail(accountId, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchAccountFavouritedStatusesRequest = (accountId: string) => ({
|
||||||
|
type: ACCOUNT_FAVOURITED_STATUSES_FETCH_REQUEST,
|
||||||
|
accountId,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchAccountFavouritedStatusesSuccess = (accountId: string, statuses: APIEntity, next: string | null) => ({
|
||||||
|
type: ACCOUNT_FAVOURITED_STATUSES_FETCH_SUCCESS,
|
||||||
|
accountId,
|
||||||
|
statuses,
|
||||||
|
next,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchAccountFavouritedStatusesFail = (accountId: string, error: AxiosError) => ({
|
||||||
|
type: ACCOUNT_FAVOURITED_STATUSES_FETCH_FAIL,
|
||||||
|
accountId,
|
||||||
|
error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandAccountFavouritedStatuses = (accountId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
const url = getState().status_lists.get(`favourites:${accountId}`)?.next || null;
|
||||||
|
|
||||||
|
if (url === null || getState().status_lists.get(`favourites:${accountId}`)?.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandAccountFavouritedStatusesRequest(accountId));
|
||||||
|
|
||||||
|
api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch(expandAccountFavouritedStatusesSuccess(accountId, response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandAccountFavouritedStatusesFail(accountId, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandAccountFavouritedStatusesRequest = (accountId: string) => ({
|
||||||
|
type: ACCOUNT_FAVOURITED_STATUSES_EXPAND_REQUEST,
|
||||||
|
accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandAccountFavouritedStatusesSuccess = (accountId: string, statuses: APIEntity[], next: string | null) => ({
|
||||||
|
type: ACCOUNT_FAVOURITED_STATUSES_EXPAND_SUCCESS,
|
||||||
|
accountId,
|
||||||
|
statuses,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandAccountFavouritedStatusesFail = (accountId: string, error: AxiosError) => ({
|
||||||
|
type: ACCOUNT_FAVOURITED_STATUSES_EXPAND_FAIL,
|
||||||
|
accountId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
FAVOURITED_STATUSES_FETCH_REQUEST,
|
||||||
|
FAVOURITED_STATUSES_FETCH_SUCCESS,
|
||||||
|
FAVOURITED_STATUSES_FETCH_FAIL,
|
||||||
|
FAVOURITED_STATUSES_EXPAND_REQUEST,
|
||||||
|
FAVOURITED_STATUSES_EXPAND_SUCCESS,
|
||||||
|
FAVOURITED_STATUSES_EXPAND_FAIL,
|
||||||
|
ACCOUNT_FAVOURITED_STATUSES_FETCH_REQUEST,
|
||||||
|
ACCOUNT_FAVOURITED_STATUSES_FETCH_SUCCESS,
|
||||||
|
ACCOUNT_FAVOURITED_STATUSES_FETCH_FAIL,
|
||||||
|
ACCOUNT_FAVOURITED_STATUSES_EXPAND_REQUEST,
|
||||||
|
ACCOUNT_FAVOURITED_STATUSES_EXPAND_SUCCESS,
|
||||||
|
ACCOUNT_FAVOURITED_STATUSES_EXPAND_FAIL,
|
||||||
|
fetchFavouritedStatuses,
|
||||||
|
fetchFavouritedStatusesRequest,
|
||||||
|
fetchFavouritedStatusesSuccess,
|
||||||
|
fetchFavouritedStatusesFail,
|
||||||
|
expandFavouritedStatuses,
|
||||||
|
expandFavouritedStatusesRequest,
|
||||||
|
expandFavouritedStatusesSuccess,
|
||||||
|
expandFavouritedStatusesFail,
|
||||||
|
fetchAccountFavouritedStatuses,
|
||||||
|
fetchAccountFavouritedStatusesRequest,
|
||||||
|
fetchAccountFavouritedStatusesSuccess,
|
||||||
|
fetchAccountFavouritedStatusesFail,
|
||||||
|
expandAccountFavouritedStatuses,
|
||||||
|
expandAccountFavouritedStatusesRequest,
|
||||||
|
expandAccountFavouritedStatusesSuccess,
|
||||||
|
expandAccountFavouritedStatusesFail,
|
||||||
|
};
|
|
@ -1,77 +0,0 @@
|
||||||
import { defineMessages } from 'react-intl';
|
|
||||||
|
|
||||||
import snackbar from 'soapbox/actions/snackbar';
|
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
export const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';
|
|
||||||
export const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS';
|
|
||||||
export const FILTERS_FETCH_FAIL = 'FILTERS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const FILTERS_CREATE_REQUEST = 'FILTERS_CREATE_REQUEST';
|
|
||||||
export const FILTERS_CREATE_SUCCESS = 'FILTERS_CREATE_SUCCESS';
|
|
||||||
export const FILTERS_CREATE_FAIL = 'FILTERS_CREATE_FAIL';
|
|
||||||
|
|
||||||
export const FILTERS_DELETE_REQUEST = 'FILTERS_DELETE_REQUEST';
|
|
||||||
export const FILTERS_DELETE_SUCCESS = 'FILTERS_DELETE_SUCCESS';
|
|
||||||
export const FILTERS_DELETE_FAIL = 'FILTERS_DELETE_FAIL';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
added: { id: 'filters.added', defaultMessage: 'Filter added.' },
|
|
||||||
removed: { id: 'filters.removed', defaultMessage: 'Filter deleted.' },
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchFilters = () => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: FILTERS_FETCH_REQUEST,
|
|
||||||
skipLoading: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
api(getState)
|
|
||||||
.get('/api/v1/filters')
|
|
||||||
.then(({ data }) => dispatch({
|
|
||||||
type: FILTERS_FETCH_SUCCESS,
|
|
||||||
filters: data,
|
|
||||||
skipLoading: true,
|
|
||||||
}))
|
|
||||||
.catch(err => dispatch({
|
|
||||||
type: FILTERS_FETCH_FAIL,
|
|
||||||
err,
|
|
||||||
skipLoading: true,
|
|
||||||
skipAlert: true,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
export function createFilter(intl, phrase, expires_at, context, whole_word, irreversible) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: FILTERS_CREATE_REQUEST });
|
|
||||||
return api(getState).post('/api/v1/filters', {
|
|
||||||
phrase,
|
|
||||||
context,
|
|
||||||
irreversible,
|
|
||||||
whole_word,
|
|
||||||
expires_at,
|
|
||||||
}).then(response => {
|
|
||||||
dispatch({ type: FILTERS_CREATE_SUCCESS, filter: response.data });
|
|
||||||
dispatch(snackbar.success(intl.formatMessage(messages.added)));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: FILTERS_CREATE_FAIL, error });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function deleteFilter(intl, id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: FILTERS_DELETE_REQUEST });
|
|
||||||
return api(getState).delete('/api/v1/filters/' + id).then(response => {
|
|
||||||
dispatch({ type: FILTERS_DELETE_SUCCESS, filter: response.data });
|
|
||||||
dispatch(snackbar.success(intl.formatMessage(messages.removed)));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: FILTERS_DELETE_FAIL, error });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
|
import snackbar from 'soapbox/actions/snackbar';
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';
|
||||||
|
const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS';
|
||||||
|
const FILTERS_FETCH_FAIL = 'FILTERS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const FILTERS_CREATE_REQUEST = 'FILTERS_CREATE_REQUEST';
|
||||||
|
const FILTERS_CREATE_SUCCESS = 'FILTERS_CREATE_SUCCESS';
|
||||||
|
const FILTERS_CREATE_FAIL = 'FILTERS_CREATE_FAIL';
|
||||||
|
|
||||||
|
const FILTERS_DELETE_REQUEST = 'FILTERS_DELETE_REQUEST';
|
||||||
|
const FILTERS_DELETE_SUCCESS = 'FILTERS_DELETE_SUCCESS';
|
||||||
|
const FILTERS_DELETE_FAIL = 'FILTERS_DELETE_FAIL';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
added: { id: 'filters.added', defaultMessage: 'Filter added.' },
|
||||||
|
removed: { id: 'filters.removed', defaultMessage: 'Filter deleted.' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchFilters = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: FILTERS_FETCH_REQUEST,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
api(getState)
|
||||||
|
.get('/api/v1/filters')
|
||||||
|
.then(({ data }) => dispatch({
|
||||||
|
type: FILTERS_FETCH_SUCCESS,
|
||||||
|
filters: data,
|
||||||
|
skipLoading: true,
|
||||||
|
}))
|
||||||
|
.catch(err => dispatch({
|
||||||
|
type: FILTERS_FETCH_FAIL,
|
||||||
|
err,
|
||||||
|
skipLoading: true,
|
||||||
|
skipAlert: true,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const createFilter = (phrase: string, expires_at: string, context: Array<string>, whole_word: boolean, irreversible: boolean) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: FILTERS_CREATE_REQUEST });
|
||||||
|
return api(getState).post('/api/v1/filters', {
|
||||||
|
phrase,
|
||||||
|
context,
|
||||||
|
irreversible,
|
||||||
|
whole_word,
|
||||||
|
expires_at,
|
||||||
|
}).then(response => {
|
||||||
|
dispatch({ type: FILTERS_CREATE_SUCCESS, filter: response.data });
|
||||||
|
dispatch(snackbar.success(messages.added));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({ type: FILTERS_CREATE_FAIL, error });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const deleteFilter = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: FILTERS_DELETE_REQUEST });
|
||||||
|
return api(getState).delete(`/api/v1/filters/${id}`).then(response => {
|
||||||
|
dispatch({ type: FILTERS_DELETE_SUCCESS, filter: response.data });
|
||||||
|
dispatch(snackbar.success(messages.removed));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({ type: FILTERS_DELETE_FAIL, error });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
FILTERS_FETCH_REQUEST,
|
||||||
|
FILTERS_FETCH_SUCCESS,
|
||||||
|
FILTERS_FETCH_FAIL,
|
||||||
|
FILTERS_CREATE_REQUEST,
|
||||||
|
FILTERS_CREATE_SUCCESS,
|
||||||
|
FILTERS_CREATE_FAIL,
|
||||||
|
FILTERS_DELETE_REQUEST,
|
||||||
|
FILTERS_DELETE_SUCCESS,
|
||||||
|
FILTERS_DELETE_FAIL,
|
||||||
|
fetchFilters,
|
||||||
|
createFilter,
|
||||||
|
deleteFilter,
|
||||||
|
};
|
|
@ -1,114 +0,0 @@
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
export const GROUP_CREATE_REQUEST = 'GROUP_CREATE_REQUEST';
|
|
||||||
export const GROUP_CREATE_SUCCESS = 'GROUP_CREATE_SUCCESS';
|
|
||||||
export const GROUP_CREATE_FAIL = 'GROUP_CREATE_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_UPDATE_REQUEST = 'GROUP_UPDATE_REQUEST';
|
|
||||||
export const GROUP_UPDATE_SUCCESS = 'GROUP_UPDATE_SUCCESS';
|
|
||||||
export const GROUP_UPDATE_FAIL = 'GROUP_UPDATE_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_EDITOR_VALUE_CHANGE = 'GROUP_EDITOR_VALUE_CHANGE';
|
|
||||||
export const GROUP_EDITOR_RESET = 'GROUP_EDITOR_RESET';
|
|
||||||
export const GROUP_EDITOR_SETUP = 'GROUP_EDITOR_SETUP';
|
|
||||||
|
|
||||||
export const submit = (routerHistory) => (dispatch, getState) => {
|
|
||||||
const groupId = getState().getIn(['group_editor', 'groupId']);
|
|
||||||
const title = getState().getIn(['group_editor', 'title']);
|
|
||||||
const description = getState().getIn(['group_editor', 'description']);
|
|
||||||
const coverImage = getState().getIn(['group_editor', 'coverImage']);
|
|
||||||
|
|
||||||
if (groupId === null) {
|
|
||||||
dispatch(create(title, description, coverImage, routerHistory));
|
|
||||||
} else {
|
|
||||||
dispatch(update(groupId, title, description, coverImage, routerHistory));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const create = (title, description, coverImage, routerHistory) => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(createRequest());
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('title', title);
|
|
||||||
formData.append('description', description);
|
|
||||||
|
|
||||||
if (coverImage !== null) {
|
|
||||||
formData.append('cover_image', coverImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
api(getState).post('/api/v1/groups', formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(({ data }) => {
|
|
||||||
dispatch(createSuccess(data));
|
|
||||||
routerHistory.push(`/groups/${data.id}`);
|
|
||||||
}).catch(err => dispatch(createFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const createRequest = id => ({
|
|
||||||
type: GROUP_CREATE_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const createSuccess = group => ({
|
|
||||||
type: GROUP_CREATE_SUCCESS,
|
|
||||||
group,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const createFail = error => ({
|
|
||||||
type: GROUP_CREATE_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const update = (groupId, title, description, coverImage, routerHistory) => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(updateRequest());
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('title', title);
|
|
||||||
formData.append('description', description);
|
|
||||||
|
|
||||||
if (coverImage !== null) {
|
|
||||||
formData.append('cover_image', coverImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
api(getState).put(`/api/v1/groups/${groupId}`, formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(({ data }) => {
|
|
||||||
dispatch(updateSuccess(data));
|
|
||||||
routerHistory.push(`/groups/${data.id}`);
|
|
||||||
}).catch(err => dispatch(updateFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const updateRequest = id => ({
|
|
||||||
type: GROUP_UPDATE_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const updateSuccess = group => ({
|
|
||||||
type: GROUP_UPDATE_SUCCESS,
|
|
||||||
group,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const updateFail = error => ({
|
|
||||||
type: GROUP_UPDATE_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const changeValue = (field, value) => ({
|
|
||||||
type: GROUP_EDITOR_VALUE_CHANGE,
|
|
||||||
field,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const reset = () => ({
|
|
||||||
type: GROUP_EDITOR_RESET,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setUp = (group) => ({
|
|
||||||
type: GROUP_EDITOR_SETUP,
|
|
||||||
group,
|
|
||||||
});
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { History } from 'history';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const GROUP_CREATE_REQUEST = 'GROUP_CREATE_REQUEST';
|
||||||
|
const GROUP_CREATE_SUCCESS = 'GROUP_CREATE_SUCCESS';
|
||||||
|
const GROUP_CREATE_FAIL = 'GROUP_CREATE_FAIL';
|
||||||
|
|
||||||
|
const GROUP_UPDATE_REQUEST = 'GROUP_UPDATE_REQUEST';
|
||||||
|
const GROUP_UPDATE_SUCCESS = 'GROUP_UPDATE_SUCCESS';
|
||||||
|
const GROUP_UPDATE_FAIL = 'GROUP_UPDATE_FAIL';
|
||||||
|
|
||||||
|
const GROUP_EDITOR_VALUE_CHANGE = 'GROUP_EDITOR_VALUE_CHANGE';
|
||||||
|
const GROUP_EDITOR_RESET = 'GROUP_EDITOR_RESET';
|
||||||
|
const GROUP_EDITOR_SETUP = 'GROUP_EDITOR_SETUP';
|
||||||
|
|
||||||
|
const submit = (routerHistory: History) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const groupId = getState().group_editor.get('groupId') as string;
|
||||||
|
const title = getState().group_editor.get('title') as string;
|
||||||
|
const description = getState().group_editor.get('description') as string;
|
||||||
|
const coverImage = getState().group_editor.get('coverImage') as any;
|
||||||
|
|
||||||
|
if (groupId === null) {
|
||||||
|
dispatch(create(title, description, coverImage, routerHistory));
|
||||||
|
} else {
|
||||||
|
dispatch(update(groupId, title, description, coverImage, routerHistory));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const create = (title: string, description: string, coverImage: File, routerHistory: History) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(createRequest());
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('title', title);
|
||||||
|
formData.append('description', description);
|
||||||
|
|
||||||
|
if (coverImage !== null) {
|
||||||
|
formData.append('cover_image', coverImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
api(getState).post('/api/v1/groups', formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(({ data }) => {
|
||||||
|
dispatch(createSuccess(data));
|
||||||
|
routerHistory.push(`/groups/${data.id}`);
|
||||||
|
}).catch(err => dispatch(createFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const createRequest = (id?: string) => ({
|
||||||
|
type: GROUP_CREATE_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createSuccess = (group: APIEntity) => ({
|
||||||
|
type: GROUP_CREATE_SUCCESS,
|
||||||
|
group,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createFail = (error: AxiosError) => ({
|
||||||
|
type: GROUP_CREATE_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const update = (groupId: string, title: string, description: string, coverImage: File, routerHistory: History) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(updateRequest(groupId));
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('title', title);
|
||||||
|
formData.append('description', description);
|
||||||
|
|
||||||
|
if (coverImage !== null) {
|
||||||
|
formData.append('cover_image', coverImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
api(getState).put(`/api/v1/groups/${groupId}`, formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(({ data }) => {
|
||||||
|
dispatch(updateSuccess(data));
|
||||||
|
routerHistory.push(`/groups/${data.id}`);
|
||||||
|
}).catch(err => dispatch(updateFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateRequest = (id: string) => ({
|
||||||
|
type: GROUP_UPDATE_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateSuccess = (group: APIEntity) => ({
|
||||||
|
type: GROUP_UPDATE_SUCCESS,
|
||||||
|
group,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateFail = (error: AxiosError) => ({
|
||||||
|
type: GROUP_UPDATE_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeValue = (field: string, value: string | File) => ({
|
||||||
|
type: GROUP_EDITOR_VALUE_CHANGE,
|
||||||
|
field,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const reset = () => ({
|
||||||
|
type: GROUP_EDITOR_RESET,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setUp = (group: string) => ({
|
||||||
|
type: GROUP_EDITOR_SETUP,
|
||||||
|
group,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
GROUP_CREATE_REQUEST,
|
||||||
|
GROUP_CREATE_SUCCESS,
|
||||||
|
GROUP_CREATE_FAIL,
|
||||||
|
GROUP_UPDATE_REQUEST,
|
||||||
|
GROUP_UPDATE_SUCCESS,
|
||||||
|
GROUP_UPDATE_FAIL,
|
||||||
|
GROUP_EDITOR_VALUE_CHANGE,
|
||||||
|
GROUP_EDITOR_RESET,
|
||||||
|
GROUP_EDITOR_SETUP,
|
||||||
|
submit,
|
||||||
|
create,
|
||||||
|
createRequest,
|
||||||
|
createSuccess,
|
||||||
|
createFail,
|
||||||
|
update,
|
||||||
|
updateRequest,
|
||||||
|
updateSuccess,
|
||||||
|
updateFail,
|
||||||
|
changeValue,
|
||||||
|
reset,
|
||||||
|
setUp,
|
||||||
|
};
|
|
@ -1,526 +0,0 @@
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api, { getLinks } from '../api';
|
|
||||||
|
|
||||||
import { fetchRelationships } from './accounts';
|
|
||||||
import { importFetchedAccounts } from './importer';
|
|
||||||
|
|
||||||
export const GROUP_FETCH_REQUEST = 'GROUP_FETCH_REQUEST';
|
|
||||||
export const GROUP_FETCH_SUCCESS = 'GROUP_FETCH_SUCCESS';
|
|
||||||
export const GROUP_FETCH_FAIL = 'GROUP_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_RELATIONSHIPS_FETCH_REQUEST = 'GROUP_RELATIONSHIPS_FETCH_REQUEST';
|
|
||||||
export const GROUP_RELATIONSHIPS_FETCH_SUCCESS = 'GROUP_RELATIONSHIPS_FETCH_SUCCESS';
|
|
||||||
export const GROUP_RELATIONSHIPS_FETCH_FAIL = 'GROUP_RELATIONSHIPS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const GROUPS_FETCH_REQUEST = 'GROUPS_FETCH_REQUEST';
|
|
||||||
export const GROUPS_FETCH_SUCCESS = 'GROUPS_FETCH_SUCCESS';
|
|
||||||
export const GROUPS_FETCH_FAIL = 'GROUPS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_JOIN_REQUEST = 'GROUP_JOIN_REQUEST';
|
|
||||||
export const GROUP_JOIN_SUCCESS = 'GROUP_JOIN_SUCCESS';
|
|
||||||
export const GROUP_JOIN_FAIL = 'GROUP_JOIN_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_LEAVE_REQUEST = 'GROUP_LEAVE_REQUEST';
|
|
||||||
export const GROUP_LEAVE_SUCCESS = 'GROUP_LEAVE_SUCCESS';
|
|
||||||
export const GROUP_LEAVE_FAIL = 'GROUP_LEAVE_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_MEMBERS_FETCH_REQUEST = 'GROUP_MEMBERS_FETCH_REQUEST';
|
|
||||||
export const GROUP_MEMBERS_FETCH_SUCCESS = 'GROUP_MEMBERS_FETCH_SUCCESS';
|
|
||||||
export const GROUP_MEMBERS_FETCH_FAIL = 'GROUP_MEMBERS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_MEMBERS_EXPAND_REQUEST = 'GROUP_MEMBERS_EXPAND_REQUEST';
|
|
||||||
export const GROUP_MEMBERS_EXPAND_SUCCESS = 'GROUP_MEMBERS_EXPAND_SUCCESS';
|
|
||||||
export const GROUP_MEMBERS_EXPAND_FAIL = 'GROUP_MEMBERS_EXPAND_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST = 'GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST';
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS';
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_FETCH_FAIL = 'GROUP_REMOVED_ACCOUNTS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST = 'GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST';
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS';
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL = 'GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST = 'GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST';
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS';
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL = 'GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST = 'GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST';
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS';
|
|
||||||
export const GROUP_REMOVED_ACCOUNTS_CREATE_FAIL = 'GROUP_REMOVED_ACCOUNTS_CREATE_FAIL';
|
|
||||||
|
|
||||||
export const GROUP_REMOVE_STATUS_REQUEST = 'GROUP_REMOVE_STATUS_REQUEST';
|
|
||||||
export const GROUP_REMOVE_STATUS_SUCCESS = 'GROUP_REMOVE_STATUS_SUCCESS';
|
|
||||||
export const GROUP_REMOVE_STATUS_FAIL = 'GROUP_REMOVE_STATUS_FAIL';
|
|
||||||
|
|
||||||
export const fetchGroup = id => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchGroupRelationships([id]));
|
|
||||||
|
|
||||||
if (getState().getIn(['groups', id])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchGroupRequest(id));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/groups/${id}`)
|
|
||||||
.then(({ data }) => dispatch(fetchGroupSuccess(data)))
|
|
||||||
.catch(err => dispatch(fetchGroupFail(id, err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchGroupRequest = id => ({
|
|
||||||
type: GROUP_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchGroupSuccess = group => ({
|
|
||||||
type: GROUP_FETCH_SUCCESS,
|
|
||||||
group,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchGroupFail = (id, error) => ({
|
|
||||||
type: GROUP_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export function fetchGroupRelationships(groupIds) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const loadedRelationships = getState().get('group_relationships');
|
|
||||||
const newGroupIds = groupIds.filter(id => loadedRelationships.get(id, null) === null);
|
|
||||||
|
|
||||||
if (newGroupIds.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchGroupRelationshipsRequest(newGroupIds));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/groups/${newGroupIds[0]}/relationships?${newGroupIds.map(id => `id[]=${id}`).join('&')}`).then(response => {
|
|
||||||
dispatch(fetchGroupRelationshipsSuccess(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchGroupRelationshipsFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchGroupRelationshipsRequest(ids) {
|
|
||||||
return {
|
|
||||||
type: GROUP_RELATIONSHIPS_FETCH_REQUEST,
|
|
||||||
ids,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchGroupRelationshipsSuccess(relationships) {
|
|
||||||
return {
|
|
||||||
type: GROUP_RELATIONSHIPS_FETCH_SUCCESS,
|
|
||||||
relationships,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchGroupRelationshipsFail(error) {
|
|
||||||
return {
|
|
||||||
type: GROUP_RELATIONSHIPS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const fetchGroups = (tab) => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchGroupsRequest());
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/groups?tab=' + tab)
|
|
||||||
.then(({ data }) => {
|
|
||||||
dispatch(fetchGroupsSuccess(data, tab));
|
|
||||||
dispatch(fetchGroupRelationships(data.map(item => item.id)));
|
|
||||||
})
|
|
||||||
.catch(err => dispatch(fetchGroupsFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchGroupsRequest = () => ({
|
|
||||||
type: GROUPS_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchGroupsSuccess = (groups, tab) => ({
|
|
||||||
type: GROUPS_FETCH_SUCCESS,
|
|
||||||
groups,
|
|
||||||
tab,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchGroupsFail = error => ({
|
|
||||||
type: GROUPS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export function joinGroup(id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(joinGroupRequest(id));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/groups/${id}/accounts`).then(response => {
|
|
||||||
dispatch(joinGroupSuccess(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(joinGroupFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function leaveGroup(id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(leaveGroupRequest(id));
|
|
||||||
|
|
||||||
api(getState).delete(`/api/v1/groups/${id}/accounts`).then(response => {
|
|
||||||
dispatch(leaveGroupSuccess(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(leaveGroupFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function joinGroupRequest(id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_JOIN_REQUEST,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function joinGroupSuccess(relationship) {
|
|
||||||
return {
|
|
||||||
type: GROUP_JOIN_SUCCESS,
|
|
||||||
relationship,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function joinGroupFail(error) {
|
|
||||||
return {
|
|
||||||
type: GROUP_JOIN_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function leaveGroupRequest(id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_LEAVE_REQUEST,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function leaveGroupSuccess(relationship) {
|
|
||||||
return {
|
|
||||||
type: GROUP_LEAVE_SUCCESS,
|
|
||||||
relationship,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function leaveGroupFail(error) {
|
|
||||||
return {
|
|
||||||
type: GROUP_LEAVE_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMembers(id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchMembersRequest(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 => {
|
|
||||||
dispatch(fetchMembersFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMembersRequest(id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_MEMBERS_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMembersSuccess(id, accounts, next) {
|
|
||||||
return {
|
|
||||||
type: GROUP_MEMBERS_FETCH_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMembersFail(id, error) {
|
|
||||||
return {
|
|
||||||
type: GROUP_MEMBERS_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandMembers(id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const url = getState().getIn(['user_lists', 'groups', id, 'next']);
|
|
||||||
|
|
||||||
if (url === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandMembersRequest(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 => {
|
|
||||||
dispatch(expandMembersFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandMembersRequest(id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_MEMBERS_EXPAND_REQUEST,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandMembersSuccess(id, accounts, next) {
|
|
||||||
return {
|
|
||||||
type: GROUP_MEMBERS_EXPAND_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandMembersFail(id, error) {
|
|
||||||
return {
|
|
||||||
type: GROUP_MEMBERS_EXPAND_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchRemovedAccounts(id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchRemovedAccountsRequest(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 => {
|
|
||||||
dispatch(fetchRemovedAccountsFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchRemovedAccountsRequest(id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchRemovedAccountsSuccess(id, accounts, next) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchRemovedAccountsFail(id, error) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandRemovedAccounts(id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const url = getState().getIn(['user_lists', 'groups_removed_accounts', id, 'next']);
|
|
||||||
|
|
||||||
if (url === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandRemovedAccountsRequest(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 => {
|
|
||||||
dispatch(expandRemovedAccountsFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandRemovedAccountsRequest(id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandRemovedAccountsSuccess(id, accounts, next) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandRemovedAccountsFail(id, error) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeRemovedAccount(groupId, id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(removeRemovedAccountRequest(groupId, id));
|
|
||||||
|
|
||||||
api(getState).delete(`/api/v1/groups/${groupId}/removed_accounts?account_id=${id}`).then(response => {
|
|
||||||
dispatch(removeRemovedAccountSuccess(groupId, id));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(removeRemovedAccountFail(groupId, id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeRemovedAccountRequest(groupId, id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeRemovedAccountSuccess(groupId, id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeRemovedAccountFail(groupId, id, error) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createRemovedAccount(groupId, id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(createRemovedAccountRequest(groupId, id));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/groups/${groupId}/removed_accounts?account_id=${id}`).then(response => {
|
|
||||||
dispatch(createRemovedAccountSuccess(groupId, id));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(createRemovedAccountFail(groupId, id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createRemovedAccountRequest(groupId, id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createRemovedAccountSuccess(groupId, id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createRemovedAccountFail(groupId, id, error) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_CREATE_FAIL,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function groupRemoveStatus(groupId, id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(groupRemoveStatusRequest(groupId, id));
|
|
||||||
|
|
||||||
api(getState).delete(`/api/v1/groups/${groupId}/statuses/${id}`).then(response => {
|
|
||||||
dispatch(groupRemoveStatusSuccess(groupId, id));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(groupRemoveStatusFail(groupId, id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function groupRemoveStatusRequest(groupId, id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVE_STATUS_REQUEST,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function groupRemoveStatusSuccess(groupId, id) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVE_STATUS_SUCCESS,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function groupRemoveStatusFail(groupId, id, error) {
|
|
||||||
return {
|
|
||||||
type: GROUP_REMOVE_STATUS_FAIL,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,550 @@
|
||||||
|
import { AxiosError } from 'axios';
|
||||||
|
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
|
import { fetchRelationships } from './accounts';
|
||||||
|
import { importFetchedAccounts } from './importer';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const GROUP_FETCH_REQUEST = 'GROUP_FETCH_REQUEST';
|
||||||
|
const GROUP_FETCH_SUCCESS = 'GROUP_FETCH_SUCCESS';
|
||||||
|
const GROUP_FETCH_FAIL = 'GROUP_FETCH_FAIL';
|
||||||
|
|
||||||
|
const GROUP_RELATIONSHIPS_FETCH_REQUEST = 'GROUP_RELATIONSHIPS_FETCH_REQUEST';
|
||||||
|
const GROUP_RELATIONSHIPS_FETCH_SUCCESS = 'GROUP_RELATIONSHIPS_FETCH_SUCCESS';
|
||||||
|
const GROUP_RELATIONSHIPS_FETCH_FAIL = 'GROUP_RELATIONSHIPS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const GROUPS_FETCH_REQUEST = 'GROUPS_FETCH_REQUEST';
|
||||||
|
const GROUPS_FETCH_SUCCESS = 'GROUPS_FETCH_SUCCESS';
|
||||||
|
const GROUPS_FETCH_FAIL = 'GROUPS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const GROUP_JOIN_REQUEST = 'GROUP_JOIN_REQUEST';
|
||||||
|
const GROUP_JOIN_SUCCESS = 'GROUP_JOIN_SUCCESS';
|
||||||
|
const GROUP_JOIN_FAIL = 'GROUP_JOIN_FAIL';
|
||||||
|
|
||||||
|
const GROUP_LEAVE_REQUEST = 'GROUP_LEAVE_REQUEST';
|
||||||
|
const GROUP_LEAVE_SUCCESS = 'GROUP_LEAVE_SUCCESS';
|
||||||
|
const GROUP_LEAVE_FAIL = 'GROUP_LEAVE_FAIL';
|
||||||
|
|
||||||
|
const GROUP_MEMBERS_FETCH_REQUEST = 'GROUP_MEMBERS_FETCH_REQUEST';
|
||||||
|
const GROUP_MEMBERS_FETCH_SUCCESS = 'GROUP_MEMBERS_FETCH_SUCCESS';
|
||||||
|
const GROUP_MEMBERS_FETCH_FAIL = 'GROUP_MEMBERS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const GROUP_MEMBERS_EXPAND_REQUEST = 'GROUP_MEMBERS_EXPAND_REQUEST';
|
||||||
|
const GROUP_MEMBERS_EXPAND_SUCCESS = 'GROUP_MEMBERS_EXPAND_SUCCESS';
|
||||||
|
const GROUP_MEMBERS_EXPAND_FAIL = 'GROUP_MEMBERS_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST = 'GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST';
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS';
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_FETCH_FAIL = 'GROUP_REMOVED_ACCOUNTS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST = 'GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST';
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS';
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL = 'GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST = 'GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST';
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS';
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL = 'GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL';
|
||||||
|
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST = 'GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST';
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS';
|
||||||
|
const GROUP_REMOVED_ACCOUNTS_CREATE_FAIL = 'GROUP_REMOVED_ACCOUNTS_CREATE_FAIL';
|
||||||
|
|
||||||
|
const GROUP_REMOVE_STATUS_REQUEST = 'GROUP_REMOVE_STATUS_REQUEST';
|
||||||
|
const GROUP_REMOVE_STATUS_SUCCESS = 'GROUP_REMOVE_STATUS_SUCCESS';
|
||||||
|
const GROUP_REMOVE_STATUS_FAIL = 'GROUP_REMOVE_STATUS_FAIL';
|
||||||
|
|
||||||
|
const fetchGroup = (id: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(fetchGroupRelationships([id]));
|
||||||
|
|
||||||
|
if (getState().groups.get(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchGroupRequest(id));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/groups/${id}`)
|
||||||
|
.then(({ data }) => dispatch(fetchGroupSuccess(data)))
|
||||||
|
.catch(err => dispatch(fetchGroupFail(id, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchGroupRequest = (id: string) => ({
|
||||||
|
type: GROUP_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchGroupSuccess = (group: APIEntity) => ({
|
||||||
|
type: GROUP_FETCH_SUCCESS,
|
||||||
|
group,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchGroupFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: GROUP_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchGroupRelationships = (groupIds: string[]) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
const loadedRelationships = getState().group_relationships;
|
||||||
|
const newGroupIds = groupIds.filter(id => loadedRelationships.get(id, null) === null);
|
||||||
|
|
||||||
|
if (newGroupIds.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchGroupRelationshipsRequest(newGroupIds));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/groups/${newGroupIds[0]}/relationships?${newGroupIds.map(id => `id[]=${id}`).join('&')}`).then(response => {
|
||||||
|
dispatch(fetchGroupRelationshipsSuccess(response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchGroupRelationshipsFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchGroupRelationshipsRequest = (ids: string[]) => ({
|
||||||
|
type: GROUP_RELATIONSHIPS_FETCH_REQUEST,
|
||||||
|
ids,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchGroupRelationshipsSuccess = (relationships: APIEntity[]) => ({
|
||||||
|
type: GROUP_RELATIONSHIPS_FETCH_SUCCESS,
|
||||||
|
relationships,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchGroupRelationshipsFail = (error: AxiosError) => ({
|
||||||
|
type: GROUP_RELATIONSHIPS_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchGroups = (tab: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(fetchGroupsRequest());
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/groups?tab=' + tab)
|
||||||
|
.then(({ data }) => {
|
||||||
|
dispatch(fetchGroupsSuccess(data, tab));
|
||||||
|
dispatch(fetchGroupRelationships(data.map((item: APIEntity) => item.id)));
|
||||||
|
})
|
||||||
|
.catch(err => dispatch(fetchGroupsFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchGroupsRequest = () => ({
|
||||||
|
type: GROUPS_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchGroupsSuccess = (groups: APIEntity[], tab: string) => ({
|
||||||
|
type: GROUPS_FETCH_SUCCESS,
|
||||||
|
groups,
|
||||||
|
tab,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchGroupsFail = (error: AxiosError) => ({
|
||||||
|
type: GROUPS_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const joinGroup = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(joinGroupRequest(id));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/groups/${id}/accounts`).then(response => {
|
||||||
|
dispatch(joinGroupSuccess(response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(joinGroupFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const leaveGroup = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(leaveGroupRequest(id));
|
||||||
|
|
||||||
|
api(getState).delete(`/api/v1/groups/${id}/accounts`).then(response => {
|
||||||
|
dispatch(leaveGroupSuccess(response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(leaveGroupFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const joinGroupRequest = (id: string) => ({
|
||||||
|
type: GROUP_JOIN_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const joinGroupSuccess = (relationship: APIEntity) => ({
|
||||||
|
type: GROUP_JOIN_SUCCESS,
|
||||||
|
relationship,
|
||||||
|
});
|
||||||
|
|
||||||
|
const joinGroupFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: GROUP_JOIN_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const leaveGroupRequest = (id: string) => ({
|
||||||
|
type: GROUP_LEAVE_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const leaveGroupSuccess = (relationship: APIEntity) => ({
|
||||||
|
type: GROUP_LEAVE_SUCCESS,
|
||||||
|
relationship,
|
||||||
|
});
|
||||||
|
|
||||||
|
const leaveGroupFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: GROUP_LEAVE_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchMembers = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(fetchMembersRequest(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: APIEntity) => item.id)));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchMembersFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchMembersRequest = (id: string) => ({
|
||||||
|
type: GROUP_MEMBERS_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchMembersSuccess = (id: string, accounts: APIEntity[], next: string | null) => ({
|
||||||
|
type: GROUP_MEMBERS_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchMembersFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: GROUP_MEMBERS_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandMembers = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
const url = getState().user_lists.getIn(['groups', id, 'next']);
|
||||||
|
|
||||||
|
if (url === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandMembersRequest(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: APIEntity) => item.id)));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandMembersFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandMembersRequest = (id: string) => ({
|
||||||
|
type: GROUP_MEMBERS_EXPAND_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandMembersSuccess = (id: string, accounts: APIEntity[], next: string | null) => ({
|
||||||
|
type: GROUP_MEMBERS_EXPAND_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandMembersFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: GROUP_MEMBERS_EXPAND_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchRemovedAccounts = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(fetchRemovedAccountsRequest(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: APIEntity) => item.id)));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchRemovedAccountsFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchRemovedAccountsRequest = (id: string) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchRemovedAccountsSuccess = (id: string, accounts: APIEntity[], next: string | null) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchRemovedAccountsFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandRemovedAccounts = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
const url = getState().user_lists.getIn(['groups_removed_accounts', id, 'next']);
|
||||||
|
|
||||||
|
if (url === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandRemovedAccountsRequest(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: APIEntity) => item.id)));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandRemovedAccountsFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandRemovedAccountsRequest = (id: string) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandRemovedAccountsSuccess = (id: string, accounts: APIEntity[], next: string | null) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandRemovedAccountsFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeRemovedAccount = (groupId: string, id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(removeRemovedAccountRequest(groupId, id));
|
||||||
|
|
||||||
|
api(getState).delete(`/api/v1/groups/${groupId}/removed_accounts?account_id=${id}`).then(response => {
|
||||||
|
dispatch(removeRemovedAccountSuccess(groupId, id));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(removeRemovedAccountFail(groupId, id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeRemovedAccountRequest = (groupId: string, id: string) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST,
|
||||||
|
groupId,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeRemovedAccountSuccess = (groupId: string, id: string) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS,
|
||||||
|
groupId,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeRemovedAccountFail = (groupId: string, id: string, error: AxiosError) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL,
|
||||||
|
groupId,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createRemovedAccount = (groupId: string, id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(createRemovedAccountRequest(groupId, id));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/groups/${groupId}/removed_accounts?account_id=${id}`).then(response => {
|
||||||
|
dispatch(createRemovedAccountSuccess(groupId, id));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(createRemovedAccountFail(groupId, id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const createRemovedAccountRequest = (groupId: string, id: string) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST,
|
||||||
|
groupId,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createRemovedAccountSuccess = (groupId: string, id: string) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS,
|
||||||
|
groupId,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createRemovedAccountFail = (groupId: string, id: string, error: AxiosError) => ({
|
||||||
|
type: GROUP_REMOVED_ACCOUNTS_CREATE_FAIL,
|
||||||
|
groupId,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupRemoveStatus = (groupId: string, id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(groupRemoveStatusRequest(groupId, id));
|
||||||
|
|
||||||
|
api(getState).delete(`/api/v1/groups/${groupId}/statuses/${id}`).then(response => {
|
||||||
|
dispatch(groupRemoveStatusSuccess(groupId, id));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(groupRemoveStatusFail(groupId, id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const groupRemoveStatusRequest = (groupId: string, id: string) => ({
|
||||||
|
type: GROUP_REMOVE_STATUS_REQUEST,
|
||||||
|
groupId,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupRemoveStatusSuccess = (groupId: string, id: string) => ({
|
||||||
|
type: GROUP_REMOVE_STATUS_SUCCESS,
|
||||||
|
groupId,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupRemoveStatusFail = (groupId: string, id: string, error: AxiosError) => ({
|
||||||
|
type: GROUP_REMOVE_STATUS_FAIL,
|
||||||
|
groupId,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
GROUP_FETCH_REQUEST,
|
||||||
|
GROUP_FETCH_SUCCESS,
|
||||||
|
GROUP_FETCH_FAIL,
|
||||||
|
GROUP_RELATIONSHIPS_FETCH_REQUEST,
|
||||||
|
GROUP_RELATIONSHIPS_FETCH_SUCCESS,
|
||||||
|
GROUP_RELATIONSHIPS_FETCH_FAIL,
|
||||||
|
GROUPS_FETCH_REQUEST,
|
||||||
|
GROUPS_FETCH_SUCCESS,
|
||||||
|
GROUPS_FETCH_FAIL,
|
||||||
|
GROUP_JOIN_REQUEST,
|
||||||
|
GROUP_JOIN_SUCCESS,
|
||||||
|
GROUP_JOIN_FAIL,
|
||||||
|
GROUP_LEAVE_REQUEST,
|
||||||
|
GROUP_LEAVE_SUCCESS,
|
||||||
|
GROUP_LEAVE_FAIL,
|
||||||
|
GROUP_MEMBERS_FETCH_REQUEST,
|
||||||
|
GROUP_MEMBERS_FETCH_SUCCESS,
|
||||||
|
GROUP_MEMBERS_FETCH_FAIL,
|
||||||
|
GROUP_MEMBERS_EXPAND_REQUEST,
|
||||||
|
GROUP_MEMBERS_EXPAND_SUCCESS,
|
||||||
|
GROUP_MEMBERS_EXPAND_FAIL,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_FETCH_FAIL,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS,
|
||||||
|
GROUP_REMOVED_ACCOUNTS_CREATE_FAIL,
|
||||||
|
GROUP_REMOVE_STATUS_REQUEST,
|
||||||
|
GROUP_REMOVE_STATUS_SUCCESS,
|
||||||
|
GROUP_REMOVE_STATUS_FAIL,
|
||||||
|
fetchGroup,
|
||||||
|
fetchGroupRequest,
|
||||||
|
fetchGroupSuccess,
|
||||||
|
fetchGroupFail,
|
||||||
|
fetchGroupRelationships,
|
||||||
|
fetchGroupRelationshipsRequest,
|
||||||
|
fetchGroupRelationshipsSuccess,
|
||||||
|
fetchGroupRelationshipsFail,
|
||||||
|
fetchGroups,
|
||||||
|
fetchGroupsRequest,
|
||||||
|
fetchGroupsSuccess,
|
||||||
|
fetchGroupsFail,
|
||||||
|
joinGroup,
|
||||||
|
leaveGroup,
|
||||||
|
joinGroupRequest,
|
||||||
|
joinGroupSuccess,
|
||||||
|
joinGroupFail,
|
||||||
|
leaveGroupRequest,
|
||||||
|
leaveGroupSuccess,
|
||||||
|
leaveGroupFail,
|
||||||
|
fetchMembers,
|
||||||
|
fetchMembersRequest,
|
||||||
|
fetchMembersSuccess,
|
||||||
|
fetchMembersFail,
|
||||||
|
expandMembers,
|
||||||
|
expandMembersRequest,
|
||||||
|
expandMembersSuccess,
|
||||||
|
expandMembersFail,
|
||||||
|
fetchRemovedAccounts,
|
||||||
|
fetchRemovedAccountsRequest,
|
||||||
|
fetchRemovedAccountsSuccess,
|
||||||
|
fetchRemovedAccountsFail,
|
||||||
|
expandRemovedAccounts,
|
||||||
|
expandRemovedAccountsRequest,
|
||||||
|
expandRemovedAccountsSuccess,
|
||||||
|
expandRemovedAccountsFail,
|
||||||
|
removeRemovedAccount,
|
||||||
|
removeRemovedAccountRequest,
|
||||||
|
removeRemovedAccountSuccess,
|
||||||
|
removeRemovedAccountFail,
|
||||||
|
createRemovedAccount,
|
||||||
|
createRemovedAccountRequest,
|
||||||
|
createRemovedAccountSuccess,
|
||||||
|
createRemovedAccountFail,
|
||||||
|
groupRemoveStatus,
|
||||||
|
groupRemoveStatusRequest,
|
||||||
|
groupRemoveStatusSuccess,
|
||||||
|
groupRemoveStatusFail,
|
||||||
|
};
|
|
@ -1,38 +0,0 @@
|
||||||
import api from 'soapbox/api';
|
|
||||||
|
|
||||||
import { importFetchedAccounts } from './importer';
|
|
||||||
|
|
||||||
export const HISTORY_FETCH_REQUEST = 'HISTORY_FETCH_REQUEST';
|
|
||||||
export const HISTORY_FETCH_SUCCESS = 'HISTORY_FETCH_SUCCESS';
|
|
||||||
export const HISTORY_FETCH_FAIL = 'HISTORY_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const fetchHistory = statusId => (dispatch, getState) => {
|
|
||||||
const loading = getState().getIn(['history', statusId, 'loading']);
|
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchHistoryRequest(statusId));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/statuses/${statusId}/history`).then(({ data }) => {
|
|
||||||
dispatch(importFetchedAccounts(data.map(x => x.account)));
|
|
||||||
dispatch(fetchHistorySuccess(statusId, data));
|
|
||||||
}).catch(error => dispatch(fetchHistoryFail(error)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchHistoryRequest = statusId => ({
|
|
||||||
type: HISTORY_FETCH_REQUEST,
|
|
||||||
statusId,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchHistorySuccess = (statusId, history) => ({
|
|
||||||
type: HISTORY_FETCH_SUCCESS,
|
|
||||||
statusId,
|
|
||||||
history,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchHistoryFail = error => ({
|
|
||||||
type: HISTORY_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import api from 'soapbox/api';
|
||||||
|
|
||||||
|
import { importFetchedAccounts } from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const HISTORY_FETCH_REQUEST = 'HISTORY_FETCH_REQUEST';
|
||||||
|
const HISTORY_FETCH_SUCCESS = 'HISTORY_FETCH_SUCCESS';
|
||||||
|
const HISTORY_FETCH_FAIL = 'HISTORY_FETCH_FAIL';
|
||||||
|
|
||||||
|
const fetchHistory = (statusId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const loading = getState().history.getIn([statusId, 'loading']);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchHistoryRequest(statusId));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/statuses/${statusId}/history`).then(({ data }) => {
|
||||||
|
dispatch(importFetchedAccounts(data.map((x: APIEntity) => x.account)));
|
||||||
|
dispatch(fetchHistorySuccess(statusId, data));
|
||||||
|
}).catch(error => dispatch(fetchHistoryFail(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchHistoryRequest = (statusId: string) => ({
|
||||||
|
type: HISTORY_FETCH_REQUEST,
|
||||||
|
statusId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchHistorySuccess = (statusId: String, history: APIEntity[]) => ({
|
||||||
|
type: HISTORY_FETCH_SUCCESS,
|
||||||
|
statusId,
|
||||||
|
history,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchHistoryFail = (error: AxiosError) => ({
|
||||||
|
type: HISTORY_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
HISTORY_FETCH_REQUEST,
|
||||||
|
HISTORY_FETCH_SUCCESS,
|
||||||
|
HISTORY_FETCH_FAIL,
|
||||||
|
fetchHistory,
|
||||||
|
fetchHistoryRequest,
|
||||||
|
fetchHistorySuccess,
|
||||||
|
fetchHistoryFail,
|
||||||
|
};
|
|
@ -1,46 +1,49 @@
|
||||||
import { getSettings } from '../settings';
|
import { getSettings } from '../settings';
|
||||||
|
|
||||||
export const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT';
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
export const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT';
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
export const STATUS_IMPORT = 'STATUS_IMPORT';
|
|
||||||
export const STATUSES_IMPORT = 'STATUSES_IMPORT';
|
|
||||||
export const POLLS_IMPORT = 'POLLS_IMPORT';
|
|
||||||
export const ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP = 'ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP';
|
|
||||||
|
|
||||||
export function importAccount(account) {
|
const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT';
|
||||||
|
const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT';
|
||||||
|
const STATUS_IMPORT = 'STATUS_IMPORT';
|
||||||
|
const STATUSES_IMPORT = 'STATUSES_IMPORT';
|
||||||
|
const POLLS_IMPORT = 'POLLS_IMPORT';
|
||||||
|
const ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP = 'ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP';
|
||||||
|
|
||||||
|
export function importAccount(account: APIEntity) {
|
||||||
return { type: ACCOUNT_IMPORT, account };
|
return { type: ACCOUNT_IMPORT, account };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importAccounts(accounts) {
|
export function importAccounts(accounts: APIEntity[]) {
|
||||||
return { type: ACCOUNTS_IMPORT, accounts };
|
return { type: ACCOUNTS_IMPORT, accounts };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importStatus(status, idempotencyKey) {
|
export function importStatus(status: APIEntity, idempotencyKey?: string) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const expandSpoilers = getSettings(getState()).get('expandSpoilers');
|
const expandSpoilers = getSettings(getState()).get('expandSpoilers');
|
||||||
return dispatch({ type: STATUS_IMPORT, status, idempotencyKey, expandSpoilers });
|
return dispatch({ type: STATUS_IMPORT, status, idempotencyKey, expandSpoilers });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importStatuses(statuses) {
|
export function importStatuses(statuses: APIEntity[]) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const expandSpoilers = getSettings(getState()).get('expandSpoilers');
|
const expandSpoilers = getSettings(getState()).get('expandSpoilers');
|
||||||
return dispatch({ type: STATUSES_IMPORT, statuses, expandSpoilers });
|
return dispatch({ type: STATUSES_IMPORT, statuses, expandSpoilers });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importPolls(polls) {
|
export function importPolls(polls: APIEntity[]) {
|
||||||
return { type: POLLS_IMPORT, polls };
|
return { type: POLLS_IMPORT, polls };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importFetchedAccount(account) {
|
export function importFetchedAccount(account: APIEntity) {
|
||||||
return importFetchedAccounts([account]);
|
return importFetchedAccounts([account]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importFetchedAccounts(accounts) {
|
export function importFetchedAccounts(accounts: APIEntity[]) {
|
||||||
const normalAccounts = [];
|
const normalAccounts: APIEntity[] = [];
|
||||||
|
|
||||||
function processAccount(account) {
|
const processAccount = (account: APIEntity) => {
|
||||||
if (!account.id) return;
|
if (!account.id) return;
|
||||||
|
|
||||||
normalAccounts.push(account);
|
normalAccounts.push(account);
|
||||||
|
@ -48,15 +51,15 @@ export function importFetchedAccounts(accounts) {
|
||||||
if (account.moved) {
|
if (account.moved) {
|
||||||
processAccount(account.moved);
|
processAccount(account.moved);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
accounts.forEach(processAccount);
|
accounts.forEach(processAccount);
|
||||||
|
|
||||||
return importAccounts(normalAccounts);
|
return importAccounts(normalAccounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importFetchedStatus(status, idempotencyKey) {
|
export function importFetchedStatus(status: APIEntity, idempotencyKey?: string) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch: AppDispatch) => {
|
||||||
// Skip broken statuses
|
// Skip broken statuses
|
||||||
if (isBroken(status)) return;
|
if (isBroken(status)) return;
|
||||||
|
|
||||||
|
@ -69,10 +72,21 @@ export function importFetchedStatus(status, idempotencyKey) {
|
||||||
dispatch(importFetchedStatus(status.quote));
|
dispatch(importFetchedStatus(status.quote));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pleroma quotes
|
||||||
if (status.pleroma?.quote?.id) {
|
if (status.pleroma?.quote?.id) {
|
||||||
dispatch(importFetchedStatus(status.pleroma.quote));
|
dispatch(importFetchedStatus(status.pleroma.quote));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fedibird quote from reblog
|
||||||
|
if (status.reblog?.quote?.id) {
|
||||||
|
dispatch(importFetchedStatus(status.reblog.quote));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pleroma quote from reblog
|
||||||
|
if (status.reblog?.pleroma?.quote?.id) {
|
||||||
|
dispatch(importFetchedStatus(status.reblog.pleroma.quote));
|
||||||
|
}
|
||||||
|
|
||||||
if (status.poll?.id) {
|
if (status.poll?.id) {
|
||||||
dispatch(importFetchedPoll(status.poll));
|
dispatch(importFetchedPoll(status.poll));
|
||||||
}
|
}
|
||||||
|
@ -84,7 +98,7 @@ export function importFetchedStatus(status, idempotencyKey) {
|
||||||
|
|
||||||
// Sometimes Pleroma can return an empty account,
|
// Sometimes Pleroma can return an empty account,
|
||||||
// or a repost can appear of a deleted account. Skip these statuses.
|
// or a repost can appear of a deleted account. Skip these statuses.
|
||||||
const isBroken = status => {
|
const isBroken = (status: APIEntity) => {
|
||||||
try {
|
try {
|
||||||
// Skip empty accounts
|
// Skip empty accounts
|
||||||
// https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/424
|
// https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/424
|
||||||
|
@ -98,13 +112,13 @@ const isBroken = status => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function importFetchedStatuses(statuses) {
|
export function importFetchedStatuses(statuses: APIEntity[]) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const accounts = [];
|
const accounts: APIEntity[] = [];
|
||||||
const normalStatuses = [];
|
const normalStatuses: APIEntity[] = [];
|
||||||
const polls = [];
|
const polls: APIEntity[] = [];
|
||||||
|
|
||||||
function processStatus(status) {
|
function processStatus(status: APIEntity) {
|
||||||
// Skip broken statuses
|
// Skip broken statuses
|
||||||
if (isBroken(status)) return;
|
if (isBroken(status)) return;
|
||||||
|
|
||||||
|
@ -137,12 +151,21 @@ export function importFetchedStatuses(statuses) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importFetchedPoll(poll) {
|
export function importFetchedPoll(poll: APIEntity) {
|
||||||
return dispatch => {
|
return (dispatch: AppDispatch) => {
|
||||||
dispatch(importPolls([poll]));
|
dispatch(importPolls([poll]));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importErrorWhileFetchingAccountByUsername(username) {
|
export function importErrorWhileFetchingAccountByUsername(username: string) {
|
||||||
return { type: ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP, username };
|
return { type: ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP, username };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
ACCOUNT_IMPORT,
|
||||||
|
ACCOUNTS_IMPORT,
|
||||||
|
STATUS_IMPORT,
|
||||||
|
STATUSES_IMPORT,
|
||||||
|
POLLS_IMPORT,
|
||||||
|
ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP,
|
||||||
|
};
|
|
@ -1,5 +1,5 @@
|
||||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||||
import { get } from 'lodash';
|
import get from 'lodash/get';
|
||||||
|
|
||||||
import KVStore from 'soapbox/storage/kv_store';
|
import KVStore from 'soapbox/storage/kv_store';
|
||||||
import { RootState } from 'soapbox/store';
|
import { RootState } from 'soapbox/store';
|
||||||
|
|
|
@ -1,527 +0,0 @@
|
||||||
import { defineMessages } from 'react-intl';
|
|
||||||
|
|
||||||
import snackbar from 'soapbox/actions/snackbar';
|
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
|
||||||
|
|
||||||
export const REBLOG_REQUEST = 'REBLOG_REQUEST';
|
|
||||||
export const REBLOG_SUCCESS = 'REBLOG_SUCCESS';
|
|
||||||
export const REBLOG_FAIL = 'REBLOG_FAIL';
|
|
||||||
|
|
||||||
export const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST';
|
|
||||||
export const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS';
|
|
||||||
export const FAVOURITE_FAIL = 'FAVOURITE_FAIL';
|
|
||||||
|
|
||||||
export const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST';
|
|
||||||
export const UNREBLOG_SUCCESS = 'UNREBLOG_SUCCESS';
|
|
||||||
export const UNREBLOG_FAIL = 'UNREBLOG_FAIL';
|
|
||||||
|
|
||||||
export const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST';
|
|
||||||
export const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS';
|
|
||||||
export const UNFAVOURITE_FAIL = 'UNFAVOURITE_FAIL';
|
|
||||||
|
|
||||||
export const REBLOGS_FETCH_REQUEST = 'REBLOGS_FETCH_REQUEST';
|
|
||||||
export const REBLOGS_FETCH_SUCCESS = 'REBLOGS_FETCH_SUCCESS';
|
|
||||||
export const REBLOGS_FETCH_FAIL = 'REBLOGS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const FAVOURITES_FETCH_REQUEST = 'FAVOURITES_FETCH_REQUEST';
|
|
||||||
export const FAVOURITES_FETCH_SUCCESS = 'FAVOURITES_FETCH_SUCCESS';
|
|
||||||
export const FAVOURITES_FETCH_FAIL = 'FAVOURITES_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const REACTIONS_FETCH_REQUEST = 'REACTIONS_FETCH_REQUEST';
|
|
||||||
export const REACTIONS_FETCH_SUCCESS = 'REACTIONS_FETCH_SUCCESS';
|
|
||||||
export const REACTIONS_FETCH_FAIL = 'REACTIONS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const PIN_REQUEST = 'PIN_REQUEST';
|
|
||||||
export const PIN_SUCCESS = 'PIN_SUCCESS';
|
|
||||||
export const PIN_FAIL = 'PIN_FAIL';
|
|
||||||
|
|
||||||
export const UNPIN_REQUEST = 'UNPIN_REQUEST';
|
|
||||||
export const UNPIN_SUCCESS = 'UNPIN_SUCCESS';
|
|
||||||
export const UNPIN_FAIL = 'UNPIN_FAIL';
|
|
||||||
|
|
||||||
export const BOOKMARK_REQUEST = 'BOOKMARK_REQUEST';
|
|
||||||
export const BOOKMARK_SUCCESS = 'BOOKMARKED_SUCCESS';
|
|
||||||
export const BOOKMARK_FAIL = 'BOOKMARKED_FAIL';
|
|
||||||
|
|
||||||
export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST';
|
|
||||||
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
|
||||||
export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
|
||||||
|
|
||||||
export const REMOTE_INTERACTION_REQUEST = 'REMOTE_INTERACTION_REQUEST';
|
|
||||||
export const REMOTE_INTERACTION_SUCCESS = 'REMOTE_INTERACTION_SUCCESS';
|
|
||||||
export const REMOTE_INTERACTION_FAIL = 'REMOTE_INTERACTION_FAIL';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
bookmarkAdded: { id: 'status.bookmarked', defaultMessage: 'Bookmark added.' },
|
|
||||||
bookmarkRemoved: { id: 'status.unbookmarked', defaultMessage: 'Bookmark removed.' },
|
|
||||||
view: { id: 'snackbar.view', defaultMessage: 'View' },
|
|
||||||
});
|
|
||||||
|
|
||||||
export function reblog(status) {
|
|
||||||
return function(dispatch, getState) {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(reblogRequest(status));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then(function(response) {
|
|
||||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
|
||||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
|
||||||
dispatch(importFetchedStatus(response.data.reblog));
|
|
||||||
dispatch(reblogSuccess(status));
|
|
||||||
}).catch(function(error) {
|
|
||||||
dispatch(reblogFail(status, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unreblog(status) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(unreblogRequest(status));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => {
|
|
||||||
dispatch(unreblogSuccess(status));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(unreblogFail(status, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reblogRequest(status) {
|
|
||||||
return {
|
|
||||||
type: REBLOG_REQUEST,
|
|
||||||
status: status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reblogSuccess(status) {
|
|
||||||
return {
|
|
||||||
type: REBLOG_SUCCESS,
|
|
||||||
status: status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reblogFail(status, error) {
|
|
||||||
return {
|
|
||||||
type: REBLOG_FAIL,
|
|
||||||
status: status,
|
|
||||||
error: error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unreblogRequest(status) {
|
|
||||||
return {
|
|
||||||
type: UNREBLOG_REQUEST,
|
|
||||||
status: status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unreblogSuccess(status) {
|
|
||||||
return {
|
|
||||||
type: UNREBLOG_SUCCESS,
|
|
||||||
status: status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unreblogFail(status, error) {
|
|
||||||
return {
|
|
||||||
type: UNREBLOG_FAIL,
|
|
||||||
status: status,
|
|
||||||
error: error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function favourite(status) {
|
|
||||||
return function(dispatch, getState) {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(favouriteRequest(status));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function(response) {
|
|
||||||
dispatch(favouriteSuccess(status));
|
|
||||||
}).catch(function(error) {
|
|
||||||
dispatch(favouriteFail(status, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unfavourite(status) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(unfavouriteRequest(status));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => {
|
|
||||||
dispatch(unfavouriteSuccess(status));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(unfavouriteFail(status, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function favouriteRequest(status) {
|
|
||||||
return {
|
|
||||||
type: FAVOURITE_REQUEST,
|
|
||||||
status: status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function favouriteSuccess(status) {
|
|
||||||
return {
|
|
||||||
type: FAVOURITE_SUCCESS,
|
|
||||||
status: status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function favouriteFail(status, error) {
|
|
||||||
return {
|
|
||||||
type: FAVOURITE_FAIL,
|
|
||||||
status: status,
|
|
||||||
error: error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unfavouriteRequest(status) {
|
|
||||||
return {
|
|
||||||
type: UNFAVOURITE_REQUEST,
|
|
||||||
status: status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unfavouriteSuccess(status) {
|
|
||||||
return {
|
|
||||||
type: UNFAVOURITE_SUCCESS,
|
|
||||||
status: status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unfavouriteFail(status, error) {
|
|
||||||
return {
|
|
||||||
type: UNFAVOURITE_FAIL,
|
|
||||||
status: status,
|
|
||||||
error: error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bookmark(status) {
|
|
||||||
return function(dispatch, getState) {
|
|
||||||
dispatch(bookmarkRequest(status));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function(response) {
|
|
||||||
dispatch(importFetchedStatus(response.data));
|
|
||||||
dispatch(bookmarkSuccess(status, response.data));
|
|
||||||
dispatch(snackbar.success(messages.bookmarkAdded, messages.view, '/bookmarks'));
|
|
||||||
}).catch(function(error) {
|
|
||||||
dispatch(bookmarkFail(status, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unbookmark(status) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch(unbookmarkRequest(status));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => {
|
|
||||||
dispatch(importFetchedStatus(response.data));
|
|
||||||
dispatch(unbookmarkSuccess(status, response.data));
|
|
||||||
dispatch(snackbar.success(messages.bookmarkRemoved));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(unbookmarkFail(status, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bookmarkRequest(status) {
|
|
||||||
return {
|
|
||||||
type: BOOKMARK_REQUEST,
|
|
||||||
status: status,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bookmarkSuccess(status, response) {
|
|
||||||
return {
|
|
||||||
type: BOOKMARK_SUCCESS,
|
|
||||||
status: status,
|
|
||||||
response: response,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bookmarkFail(status, error) {
|
|
||||||
return {
|
|
||||||
type: BOOKMARK_FAIL,
|
|
||||||
status: status,
|
|
||||||
error: error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unbookmarkRequest(status) {
|
|
||||||
return {
|
|
||||||
type: UNBOOKMARK_REQUEST,
|
|
||||||
status: status,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unbookmarkSuccess(status, response) {
|
|
||||||
return {
|
|
||||||
type: UNBOOKMARK_SUCCESS,
|
|
||||||
status: status,
|
|
||||||
response: response,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unbookmarkFail(status, error) {
|
|
||||||
return {
|
|
||||||
type: UNBOOKMARK_FAIL,
|
|
||||||
status: status,
|
|
||||||
error: error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchReblogs(id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
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));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchReblogsRequest(id) {
|
|
||||||
return {
|
|
||||||
type: REBLOGS_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchReblogsSuccess(id, accounts) {
|
|
||||||
return {
|
|
||||||
type: REBLOGS_FETCH_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchReblogsFail(id, error) {
|
|
||||||
return {
|
|
||||||
type: REBLOGS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchFavourites(id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
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));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchFavouritesRequest(id) {
|
|
||||||
return {
|
|
||||||
type: FAVOURITES_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchFavouritesSuccess(id, accounts) {
|
|
||||||
return {
|
|
||||||
type: FAVOURITES_FETCH_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchFavouritesFail(id, error) {
|
|
||||||
return {
|
|
||||||
type: FAVOURITES_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchReactions(id) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch(fetchReactionsRequest(id));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/pleroma/statuses/${id}/reactions`).then(response => {
|
|
||||||
dispatch(importFetchedAccounts(response.data.map(({ accounts }) => accounts).flat()));
|
|
||||||
dispatch(fetchReactionsSuccess(id, response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchReactionsFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchReactionsRequest(id) {
|
|
||||||
return {
|
|
||||||
type: REACTIONS_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchReactionsSuccess(id, reactions) {
|
|
||||||
return {
|
|
||||||
type: REACTIONS_FETCH_SUCCESS,
|
|
||||||
id,
|
|
||||||
reactions,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchReactionsFail(id, error) {
|
|
||||||
return {
|
|
||||||
type: REACTIONS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pin(status) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(pinRequest(status));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => {
|
|
||||||
dispatch(importFetchedStatus(response.data));
|
|
||||||
dispatch(pinSuccess(status));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(pinFail(status, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pinRequest(status) {
|
|
||||||
return {
|
|
||||||
type: PIN_REQUEST,
|
|
||||||
status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pinSuccess(status) {
|
|
||||||
return {
|
|
||||||
type: PIN_SUCCESS,
|
|
||||||
status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pinFail(status, error) {
|
|
||||||
return {
|
|
||||||
type: PIN_FAIL,
|
|
||||||
status,
|
|
||||||
error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unpin(status) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(unpinRequest(status));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => {
|
|
||||||
dispatch(importFetchedStatus(response.data));
|
|
||||||
dispatch(unpinSuccess(status));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(unpinFail(status, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unpinRequest(status) {
|
|
||||||
return {
|
|
||||||
type: UNPIN_REQUEST,
|
|
||||||
status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unpinSuccess(status) {
|
|
||||||
return {
|
|
||||||
type: UNPIN_SUCCESS,
|
|
||||||
status,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unpinFail(status, error) {
|
|
||||||
return {
|
|
||||||
type: UNPIN_FAIL,
|
|
||||||
status,
|
|
||||||
error,
|
|
||||||
skipLoading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function remoteInteraction(ap_id, profile) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch(remoteInteractionRequest(ap_id, profile));
|
|
||||||
|
|
||||||
return api(getState).post('/api/v1/pleroma/remote_interaction', { ap_id, profile }).then(({ data }) => {
|
|
||||||
if (data.error) throw new Error(data.error);
|
|
||||||
|
|
||||||
dispatch(remoteInteractionSuccess(ap_id, profile, data.url));
|
|
||||||
|
|
||||||
return data.url;
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(remoteInteractionFail(ap_id, profile, error));
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function remoteInteractionRequest(ap_id, profile) {
|
|
||||||
return {
|
|
||||||
type: REMOTE_INTERACTION_REQUEST,
|
|
||||||
ap_id,
|
|
||||||
profile,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function remoteInteractionSuccess(ap_id, profile, url) {
|
|
||||||
return {
|
|
||||||
type: REMOTE_INTERACTION_SUCCESS,
|
|
||||||
ap_id,
|
|
||||||
profile,
|
|
||||||
url,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function remoteInteractionFail(ap_id, profile, error) {
|
|
||||||
return {
|
|
||||||
type: REMOTE_INTERACTION_FAIL,
|
|
||||||
ap_id,
|
|
||||||
profile,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,537 @@
|
||||||
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
|
import snackbar from 'soapbox/actions/snackbar';
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity, Status as StatusEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const REBLOG_REQUEST = 'REBLOG_REQUEST';
|
||||||
|
const REBLOG_SUCCESS = 'REBLOG_SUCCESS';
|
||||||
|
const REBLOG_FAIL = 'REBLOG_FAIL';
|
||||||
|
|
||||||
|
const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST';
|
||||||
|
const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS';
|
||||||
|
const FAVOURITE_FAIL = 'FAVOURITE_FAIL';
|
||||||
|
|
||||||
|
const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST';
|
||||||
|
const UNREBLOG_SUCCESS = 'UNREBLOG_SUCCESS';
|
||||||
|
const UNREBLOG_FAIL = 'UNREBLOG_FAIL';
|
||||||
|
|
||||||
|
const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST';
|
||||||
|
const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS';
|
||||||
|
const UNFAVOURITE_FAIL = 'UNFAVOURITE_FAIL';
|
||||||
|
|
||||||
|
const REBLOGS_FETCH_REQUEST = 'REBLOGS_FETCH_REQUEST';
|
||||||
|
const REBLOGS_FETCH_SUCCESS = 'REBLOGS_FETCH_SUCCESS';
|
||||||
|
const REBLOGS_FETCH_FAIL = 'REBLOGS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const FAVOURITES_FETCH_REQUEST = 'FAVOURITES_FETCH_REQUEST';
|
||||||
|
const FAVOURITES_FETCH_SUCCESS = 'FAVOURITES_FETCH_SUCCESS';
|
||||||
|
const FAVOURITES_FETCH_FAIL = 'FAVOURITES_FETCH_FAIL';
|
||||||
|
|
||||||
|
const REACTIONS_FETCH_REQUEST = 'REACTIONS_FETCH_REQUEST';
|
||||||
|
const REACTIONS_FETCH_SUCCESS = 'REACTIONS_FETCH_SUCCESS';
|
||||||
|
const REACTIONS_FETCH_FAIL = 'REACTIONS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const PIN_REQUEST = 'PIN_REQUEST';
|
||||||
|
const PIN_SUCCESS = 'PIN_SUCCESS';
|
||||||
|
const PIN_FAIL = 'PIN_FAIL';
|
||||||
|
|
||||||
|
const UNPIN_REQUEST = 'UNPIN_REQUEST';
|
||||||
|
const UNPIN_SUCCESS = 'UNPIN_SUCCESS';
|
||||||
|
const UNPIN_FAIL = 'UNPIN_FAIL';
|
||||||
|
|
||||||
|
const BOOKMARK_REQUEST = 'BOOKMARK_REQUEST';
|
||||||
|
const BOOKMARK_SUCCESS = 'BOOKMARKED_SUCCESS';
|
||||||
|
const BOOKMARK_FAIL = 'BOOKMARKED_FAIL';
|
||||||
|
|
||||||
|
const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST';
|
||||||
|
const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
||||||
|
const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
||||||
|
|
||||||
|
const REMOTE_INTERACTION_REQUEST = 'REMOTE_INTERACTION_REQUEST';
|
||||||
|
const REMOTE_INTERACTION_SUCCESS = 'REMOTE_INTERACTION_SUCCESS';
|
||||||
|
const REMOTE_INTERACTION_FAIL = 'REMOTE_INTERACTION_FAIL';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
bookmarkAdded: { id: 'status.bookmarked', defaultMessage: 'Bookmark added.' },
|
||||||
|
bookmarkRemoved: { id: 'status.unbookmarked', defaultMessage: 'Bookmark removed.' },
|
||||||
|
view: { id: 'snackbar.view', defaultMessage: 'View' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const reblog = (status: StatusEntity) =>
|
||||||
|
function(dispatch: AppDispatch, getState: () => RootState) {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(reblogRequest(status));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then(function(response) {
|
||||||
|
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||||
|
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||||
|
dispatch(importFetchedStatus(response.data.reblog));
|
||||||
|
dispatch(reblogSuccess(status));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(reblogFail(status, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const unreblog = (status: StatusEntity) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(unreblogRequest(status));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(() => {
|
||||||
|
dispatch(unreblogSuccess(status));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(unreblogFail(status, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const reblogRequest = (status: StatusEntity) => ({
|
||||||
|
type: REBLOG_REQUEST,
|
||||||
|
status: status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const reblogSuccess = (status: StatusEntity) => ({
|
||||||
|
type: REBLOG_SUCCESS,
|
||||||
|
status: status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const reblogFail = (status: StatusEntity, error: AxiosError) => ({
|
||||||
|
type: REBLOG_FAIL,
|
||||||
|
status: status,
|
||||||
|
error: error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unreblogRequest = (status: StatusEntity) => ({
|
||||||
|
type: UNREBLOG_REQUEST,
|
||||||
|
status: status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unreblogSuccess = (status: StatusEntity) => ({
|
||||||
|
type: UNREBLOG_SUCCESS,
|
||||||
|
status: status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unreblogFail = (status: StatusEntity, error: AxiosError) => ({
|
||||||
|
type: UNREBLOG_FAIL,
|
||||||
|
status: status,
|
||||||
|
error: error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const favourite = (status: StatusEntity) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(favouriteRequest(status));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function(response) {
|
||||||
|
dispatch(favouriteSuccess(status));
|
||||||
|
}).catch(function(error) {
|
||||||
|
dispatch(favouriteFail(status, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const unfavourite = (status: StatusEntity) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(unfavouriteRequest(status));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(() => {
|
||||||
|
dispatch(unfavouriteSuccess(status));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(unfavouriteFail(status, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const favouriteRequest = (status: StatusEntity) => ({
|
||||||
|
type: FAVOURITE_REQUEST,
|
||||||
|
status: status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const favouriteSuccess = (status: StatusEntity) => ({
|
||||||
|
type: FAVOURITE_SUCCESS,
|
||||||
|
status: status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const favouriteFail = (status: StatusEntity, error: AxiosError) => ({
|
||||||
|
type: FAVOURITE_FAIL,
|
||||||
|
status: status,
|
||||||
|
error: error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unfavouriteRequest = (status: StatusEntity) => ({
|
||||||
|
type: UNFAVOURITE_REQUEST,
|
||||||
|
status: status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unfavouriteSuccess = (status: StatusEntity) => ({
|
||||||
|
type: UNFAVOURITE_SUCCESS,
|
||||||
|
status: status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unfavouriteFail = (status: StatusEntity, error: AxiosError) => ({
|
||||||
|
type: UNFAVOURITE_FAIL,
|
||||||
|
status: status,
|
||||||
|
error: error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const bookmark = (status: StatusEntity) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(bookmarkRequest(status));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function(response) {
|
||||||
|
dispatch(importFetchedStatus(response.data));
|
||||||
|
dispatch(bookmarkSuccess(status, response.data));
|
||||||
|
dispatch(snackbar.success(messages.bookmarkAdded, messages.view, '/bookmarks'));
|
||||||
|
}).catch(function(error) {
|
||||||
|
dispatch(bookmarkFail(status, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const unbookmark = (status: StatusEntity) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(unbookmarkRequest(status));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => {
|
||||||
|
dispatch(importFetchedStatus(response.data));
|
||||||
|
dispatch(unbookmarkSuccess(status, response.data));
|
||||||
|
dispatch(snackbar.success(messages.bookmarkRemoved));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(unbookmarkFail(status, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const bookmarkRequest = (status: StatusEntity) => ({
|
||||||
|
type: BOOKMARK_REQUEST,
|
||||||
|
status: status,
|
||||||
|
});
|
||||||
|
|
||||||
|
const bookmarkSuccess = (status: StatusEntity, response: APIEntity) => ({
|
||||||
|
type: BOOKMARK_SUCCESS,
|
||||||
|
status: status,
|
||||||
|
response: response,
|
||||||
|
});
|
||||||
|
|
||||||
|
const bookmarkFail = (status: StatusEntity, error: AxiosError) => ({
|
||||||
|
type: BOOKMARK_FAIL,
|
||||||
|
status: status,
|
||||||
|
error: error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unbookmarkRequest = (status: StatusEntity) => ({
|
||||||
|
type: UNBOOKMARK_REQUEST,
|
||||||
|
status: status,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unbookmarkSuccess = (status: StatusEntity, response: APIEntity) => ({
|
||||||
|
type: UNBOOKMARK_SUCCESS,
|
||||||
|
status: status,
|
||||||
|
response: response,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unbookmarkFail = (status: StatusEntity, error: AxiosError) => ({
|
||||||
|
type: UNBOOKMARK_FAIL,
|
||||||
|
status: status,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchReblogs = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
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));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchReblogsRequest = (id: string) => ({
|
||||||
|
type: REBLOGS_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchReblogsSuccess = (id: string, accounts: APIEntity[]) => ({
|
||||||
|
type: REBLOGS_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchReblogsFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: REBLOGS_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchFavourites = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
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));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchFavouritesRequest = (id: string) => ({
|
||||||
|
type: FAVOURITES_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchFavouritesSuccess = (id: string, accounts: APIEntity[]) => ({
|
||||||
|
type: FAVOURITES_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchFavouritesFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: FAVOURITES_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchReactions = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(fetchReactionsRequest(id));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/pleroma/statuses/${id}/reactions`).then(response => {
|
||||||
|
dispatch(importFetchedAccounts((response.data as APIEntity[]).map(({ accounts }) => accounts).flat()));
|
||||||
|
dispatch(fetchReactionsSuccess(id, response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchReactionsFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchReactionsRequest = (id: string) => ({
|
||||||
|
type: REACTIONS_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchReactionsSuccess = (id: string, reactions: APIEntity[]) => ({
|
||||||
|
type: REACTIONS_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
reactions,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchReactionsFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: REACTIONS_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const pin = (status: StatusEntity) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(pinRequest(status));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => {
|
||||||
|
dispatch(importFetchedStatus(response.data));
|
||||||
|
dispatch(pinSuccess(status));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(pinFail(status, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const pinRequest = (status: StatusEntity) => ({
|
||||||
|
type: PIN_REQUEST,
|
||||||
|
status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const pinSuccess = (status: StatusEntity) => ({
|
||||||
|
type: PIN_SUCCESS,
|
||||||
|
status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const pinFail = (status: StatusEntity, error: AxiosError) => ({
|
||||||
|
type: PIN_FAIL,
|
||||||
|
status,
|
||||||
|
error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unpin = (status: StatusEntity) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(unpinRequest(status));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => {
|
||||||
|
dispatch(importFetchedStatus(response.data));
|
||||||
|
dispatch(unpinSuccess(status));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(unpinFail(status, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const unpinRequest = (status: StatusEntity) => ({
|
||||||
|
type: UNPIN_REQUEST,
|
||||||
|
status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unpinSuccess = (status: StatusEntity) => ({
|
||||||
|
type: UNPIN_SUCCESS,
|
||||||
|
status,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unpinFail = (status: StatusEntity, error: AxiosError) => ({
|
||||||
|
type: UNPIN_FAIL,
|
||||||
|
status,
|
||||||
|
error,
|
||||||
|
skipLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const remoteInteraction = (ap_id: string, profile: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(remoteInteractionRequest(ap_id, profile));
|
||||||
|
|
||||||
|
return api(getState).post('/api/v1/pleroma/remote_interaction', { ap_id, profile }).then(({ data }) => {
|
||||||
|
if (data.error) throw new Error(data.error);
|
||||||
|
|
||||||
|
dispatch(remoteInteractionSuccess(ap_id, profile, data.url));
|
||||||
|
|
||||||
|
return data.url;
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(remoteInteractionFail(ap_id, profile, error));
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const remoteInteractionRequest = (ap_id: string, profile: string) => ({
|
||||||
|
type: REMOTE_INTERACTION_REQUEST,
|
||||||
|
ap_id,
|
||||||
|
profile,
|
||||||
|
});
|
||||||
|
|
||||||
|
const remoteInteractionSuccess = (ap_id: string, profile: string, url: string) => ({
|
||||||
|
type: REMOTE_INTERACTION_SUCCESS,
|
||||||
|
ap_id,
|
||||||
|
profile,
|
||||||
|
url,
|
||||||
|
});
|
||||||
|
|
||||||
|
const remoteInteractionFail = (ap_id: string, profile: string, error: AxiosError) => ({
|
||||||
|
type: REMOTE_INTERACTION_FAIL,
|
||||||
|
ap_id,
|
||||||
|
profile,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
REBLOG_REQUEST,
|
||||||
|
REBLOG_SUCCESS,
|
||||||
|
REBLOG_FAIL,
|
||||||
|
FAVOURITE_REQUEST,
|
||||||
|
FAVOURITE_SUCCESS,
|
||||||
|
FAVOURITE_FAIL,
|
||||||
|
UNREBLOG_REQUEST,
|
||||||
|
UNREBLOG_SUCCESS,
|
||||||
|
UNREBLOG_FAIL,
|
||||||
|
UNFAVOURITE_REQUEST,
|
||||||
|
UNFAVOURITE_SUCCESS,
|
||||||
|
UNFAVOURITE_FAIL,
|
||||||
|
REBLOGS_FETCH_REQUEST,
|
||||||
|
REBLOGS_FETCH_SUCCESS,
|
||||||
|
REBLOGS_FETCH_FAIL,
|
||||||
|
FAVOURITES_FETCH_REQUEST,
|
||||||
|
FAVOURITES_FETCH_SUCCESS,
|
||||||
|
FAVOURITES_FETCH_FAIL,
|
||||||
|
REACTIONS_FETCH_REQUEST,
|
||||||
|
REACTIONS_FETCH_SUCCESS,
|
||||||
|
REACTIONS_FETCH_FAIL,
|
||||||
|
PIN_REQUEST,
|
||||||
|
PIN_SUCCESS,
|
||||||
|
PIN_FAIL,
|
||||||
|
UNPIN_REQUEST,
|
||||||
|
UNPIN_SUCCESS,
|
||||||
|
UNPIN_FAIL,
|
||||||
|
BOOKMARK_REQUEST,
|
||||||
|
BOOKMARK_SUCCESS,
|
||||||
|
BOOKMARK_FAIL,
|
||||||
|
UNBOOKMARK_REQUEST,
|
||||||
|
UNBOOKMARK_SUCCESS,
|
||||||
|
UNBOOKMARK_FAIL,
|
||||||
|
REMOTE_INTERACTION_REQUEST,
|
||||||
|
REMOTE_INTERACTION_SUCCESS,
|
||||||
|
REMOTE_INTERACTION_FAIL,
|
||||||
|
reblog,
|
||||||
|
unreblog,
|
||||||
|
reblogRequest,
|
||||||
|
reblogSuccess,
|
||||||
|
reblogFail,
|
||||||
|
unreblogRequest,
|
||||||
|
unreblogSuccess,
|
||||||
|
unreblogFail,
|
||||||
|
favourite,
|
||||||
|
unfavourite,
|
||||||
|
favouriteRequest,
|
||||||
|
favouriteSuccess,
|
||||||
|
favouriteFail,
|
||||||
|
unfavouriteRequest,
|
||||||
|
unfavouriteSuccess,
|
||||||
|
unfavouriteFail,
|
||||||
|
bookmark,
|
||||||
|
unbookmark,
|
||||||
|
bookmarkRequest,
|
||||||
|
bookmarkSuccess,
|
||||||
|
bookmarkFail,
|
||||||
|
unbookmarkRequest,
|
||||||
|
unbookmarkSuccess,
|
||||||
|
unbookmarkFail,
|
||||||
|
fetchReblogs,
|
||||||
|
fetchReblogsRequest,
|
||||||
|
fetchReblogsSuccess,
|
||||||
|
fetchReblogsFail,
|
||||||
|
fetchFavourites,
|
||||||
|
fetchFavouritesRequest,
|
||||||
|
fetchFavouritesSuccess,
|
||||||
|
fetchFavouritesFail,
|
||||||
|
fetchReactions,
|
||||||
|
fetchReactionsRequest,
|
||||||
|
fetchReactionsSuccess,
|
||||||
|
fetchReactionsFail,
|
||||||
|
pin,
|
||||||
|
pinRequest,
|
||||||
|
pinSuccess,
|
||||||
|
pinFail,
|
||||||
|
unpin,
|
||||||
|
unpinRequest,
|
||||||
|
unpinSuccess,
|
||||||
|
unpinFail,
|
||||||
|
remoteInteraction,
|
||||||
|
remoteInteractionRequest,
|
||||||
|
remoteInteractionSuccess,
|
||||||
|
remoteInteractionFail,
|
||||||
|
};
|
|
@ -1,394 +0,0 @@
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
import { showAlertForError } from './alerts';
|
|
||||||
import { importFetchedAccounts } from './importer';
|
|
||||||
|
|
||||||
export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST';
|
|
||||||
export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS';
|
|
||||||
export const LIST_FETCH_FAIL = 'LIST_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const LISTS_FETCH_REQUEST = 'LISTS_FETCH_REQUEST';
|
|
||||||
export const LISTS_FETCH_SUCCESS = 'LISTS_FETCH_SUCCESS';
|
|
||||||
export const LISTS_FETCH_FAIL = 'LISTS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE';
|
|
||||||
export const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET';
|
|
||||||
export const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP';
|
|
||||||
|
|
||||||
export const LIST_CREATE_REQUEST = 'LIST_CREATE_REQUEST';
|
|
||||||
export const LIST_CREATE_SUCCESS = 'LIST_CREATE_SUCCESS';
|
|
||||||
export const LIST_CREATE_FAIL = 'LIST_CREATE_FAIL';
|
|
||||||
|
|
||||||
export const LIST_UPDATE_REQUEST = 'LIST_UPDATE_REQUEST';
|
|
||||||
export const LIST_UPDATE_SUCCESS = 'LIST_UPDATE_SUCCESS';
|
|
||||||
export const LIST_UPDATE_FAIL = 'LIST_UPDATE_FAIL';
|
|
||||||
|
|
||||||
export const LIST_DELETE_REQUEST = 'LIST_DELETE_REQUEST';
|
|
||||||
export const LIST_DELETE_SUCCESS = 'LIST_DELETE_SUCCESS';
|
|
||||||
export const LIST_DELETE_FAIL = 'LIST_DELETE_FAIL';
|
|
||||||
|
|
||||||
export const LIST_ACCOUNTS_FETCH_REQUEST = 'LIST_ACCOUNTS_FETCH_REQUEST';
|
|
||||||
export const LIST_ACCOUNTS_FETCH_SUCCESS = 'LIST_ACCOUNTS_FETCH_SUCCESS';
|
|
||||||
export const LIST_ACCOUNTS_FETCH_FAIL = 'LIST_ACCOUNTS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const LIST_EDITOR_SUGGESTIONS_CHANGE = 'LIST_EDITOR_SUGGESTIONS_CHANGE';
|
|
||||||
export const LIST_EDITOR_SUGGESTIONS_READY = 'LIST_EDITOR_SUGGESTIONS_READY';
|
|
||||||
export const LIST_EDITOR_SUGGESTIONS_CLEAR = 'LIST_EDITOR_SUGGESTIONS_CLEAR';
|
|
||||||
|
|
||||||
export const LIST_EDITOR_ADD_REQUEST = 'LIST_EDITOR_ADD_REQUEST';
|
|
||||||
export const LIST_EDITOR_ADD_SUCCESS = 'LIST_EDITOR_ADD_SUCCESS';
|
|
||||||
export const LIST_EDITOR_ADD_FAIL = 'LIST_EDITOR_ADD_FAIL';
|
|
||||||
|
|
||||||
export const LIST_EDITOR_REMOVE_REQUEST = 'LIST_EDITOR_REMOVE_REQUEST';
|
|
||||||
export const LIST_EDITOR_REMOVE_SUCCESS = 'LIST_EDITOR_REMOVE_SUCCESS';
|
|
||||||
export const LIST_EDITOR_REMOVE_FAIL = 'LIST_EDITOR_REMOVE_FAIL';
|
|
||||||
|
|
||||||
export const LIST_ADDER_RESET = 'LIST_ADDER_RESET';
|
|
||||||
export const LIST_ADDER_SETUP = 'LIST_ADDER_SETUP';
|
|
||||||
|
|
||||||
export const LIST_ADDER_LISTS_FETCH_REQUEST = 'LIST_ADDER_LISTS_FETCH_REQUEST';
|
|
||||||
export const LIST_ADDER_LISTS_FETCH_SUCCESS = 'LIST_ADDER_LISTS_FETCH_SUCCESS';
|
|
||||||
export const LIST_ADDER_LISTS_FETCH_FAIL = 'LIST_ADDER_LISTS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const fetchList = id => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
if (getState().getIn(['lists', id])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchListRequest(id));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/lists/${id}`)
|
|
||||||
.then(({ data }) => dispatch(fetchListSuccess(data)))
|
|
||||||
.catch(err => dispatch(fetchListFail(id, err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchListRequest = id => ({
|
|
||||||
type: LIST_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchListSuccess = list => ({
|
|
||||||
type: LIST_FETCH_SUCCESS,
|
|
||||||
list,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchListFail = (id, error) => ({
|
|
||||||
type: LIST_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchLists = () => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchListsRequest());
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/lists')
|
|
||||||
.then(({ data }) => dispatch(fetchListsSuccess(data)))
|
|
||||||
.catch(err => dispatch(fetchListsFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchListsRequest = () => ({
|
|
||||||
type: LISTS_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchListsSuccess = lists => ({
|
|
||||||
type: LISTS_FETCH_SUCCESS,
|
|
||||||
lists,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchListsFail = error => ({
|
|
||||||
type: LISTS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const submitListEditor = shouldReset => (dispatch, getState) => {
|
|
||||||
const listId = getState().getIn(['listEditor', 'listId']);
|
|
||||||
const title = getState().getIn(['listEditor', 'title']);
|
|
||||||
|
|
||||||
if (listId === null) {
|
|
||||||
dispatch(createList(title, shouldReset));
|
|
||||||
} else {
|
|
||||||
dispatch(updateList(listId, title, shouldReset));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setupListEditor = listId => (dispatch, getState) => {
|
|
||||||
dispatch({
|
|
||||||
type: LIST_EDITOR_SETUP,
|
|
||||||
list: getState().getIn(['lists', listId]),
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(fetchListAccounts(listId));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const changeListEditorTitle = value => ({
|
|
||||||
type: LIST_EDITOR_TITLE_CHANGE,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const createList = (title, shouldReset) => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(createListRequest());
|
|
||||||
|
|
||||||
api(getState).post('/api/v1/lists', { title }).then(({ data }) => {
|
|
||||||
dispatch(createListSuccess(data));
|
|
||||||
|
|
||||||
if (shouldReset) {
|
|
||||||
dispatch(resetListEditor());
|
|
||||||
}
|
|
||||||
}).catch(err => dispatch(createListFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createListRequest = () => ({
|
|
||||||
type: LIST_CREATE_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const createListSuccess = list => ({
|
|
||||||
type: LIST_CREATE_SUCCESS,
|
|
||||||
list,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const createListFail = error => ({
|
|
||||||
type: LIST_CREATE_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const updateList = (id, title, shouldReset) => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(updateListRequest(id));
|
|
||||||
|
|
||||||
api(getState).put(`/api/v1/lists/${id}`, { title }).then(({ data }) => {
|
|
||||||
dispatch(updateListSuccess(data));
|
|
||||||
|
|
||||||
if (shouldReset) {
|
|
||||||
dispatch(resetListEditor());
|
|
||||||
}
|
|
||||||
}).catch(err => dispatch(updateListFail(id, err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateListRequest = id => ({
|
|
||||||
type: LIST_UPDATE_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const updateListSuccess = list => ({
|
|
||||||
type: LIST_UPDATE_SUCCESS,
|
|
||||||
list,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const updateListFail = (id, error) => ({
|
|
||||||
type: LIST_UPDATE_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const resetListEditor = () => ({
|
|
||||||
type: LIST_EDITOR_RESET,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const deleteList = id => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(deleteListRequest(id));
|
|
||||||
|
|
||||||
api(getState).delete(`/api/v1/lists/${id}`)
|
|
||||||
.then(() => dispatch(deleteListSuccess(id)))
|
|
||||||
.catch(err => dispatch(deleteListFail(id, err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteListRequest = id => ({
|
|
||||||
type: LIST_DELETE_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const deleteListSuccess = id => ({
|
|
||||||
type: LIST_DELETE_SUCCESS,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const deleteListFail = (id, error) => ({
|
|
||||||
type: LIST_DELETE_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchListAccounts = listId => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
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)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchListAccountsRequest = id => ({
|
|
||||||
type: LIST_ACCOUNTS_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchListAccountsSuccess = (id, accounts, next) => ({
|
|
||||||
type: LIST_ACCOUNTS_FETCH_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchListAccountsFail = (id, error) => ({
|
|
||||||
type: LIST_ACCOUNTS_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchListSuggestions = q => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
q,
|
|
||||||
resolve: false,
|
|
||||||
limit: 4,
|
|
||||||
following: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
|
|
||||||
dispatch(importFetchedAccounts(data));
|
|
||||||
dispatch(fetchListSuggestionsReady(q, data));
|
|
||||||
}).catch(error => dispatch(showAlertForError(error)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchListSuggestionsReady = (query, accounts) => ({
|
|
||||||
type: LIST_EDITOR_SUGGESTIONS_READY,
|
|
||||||
query,
|
|
||||||
accounts,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const clearListSuggestions = () => ({
|
|
||||||
type: LIST_EDITOR_SUGGESTIONS_CLEAR,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const changeListSuggestions = value => ({
|
|
||||||
type: LIST_EDITOR_SUGGESTIONS_CHANGE,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addToListEditor = accountId => (dispatch, getState) => {
|
|
||||||
dispatch(addToList(getState().getIn(['listEditor', 'listId']), accountId));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addToList = (listId, accountId) => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(addToListRequest(listId, accountId));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/lists/${listId}/accounts`, { account_ids: [accountId] })
|
|
||||||
.then(() => dispatch(addToListSuccess(listId, accountId)))
|
|
||||||
.catch(err => dispatch(addToListFail(listId, accountId, err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addToListRequest = (listId, accountId) => ({
|
|
||||||
type: LIST_EDITOR_ADD_REQUEST,
|
|
||||||
listId,
|
|
||||||
accountId,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addToListSuccess = (listId, accountId) => ({
|
|
||||||
type: LIST_EDITOR_ADD_SUCCESS,
|
|
||||||
listId,
|
|
||||||
accountId,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addToListFail = (listId, accountId, error) => ({
|
|
||||||
type: LIST_EDITOR_ADD_FAIL,
|
|
||||||
listId,
|
|
||||||
accountId,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeFromListEditor = accountId => (dispatch, getState) => {
|
|
||||||
dispatch(removeFromList(getState().getIn(['listEditor', 'listId']), accountId));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeFromList = (listId, accountId) => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(removeFromListRequest(listId, accountId));
|
|
||||||
|
|
||||||
api(getState).delete(`/api/v1/lists/${listId}/accounts`, { params: { account_ids: [accountId] } })
|
|
||||||
.then(() => dispatch(removeFromListSuccess(listId, accountId)))
|
|
||||||
.catch(err => dispatch(removeFromListFail(listId, accountId, err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeFromListRequest = (listId, accountId) => ({
|
|
||||||
type: LIST_EDITOR_REMOVE_REQUEST,
|
|
||||||
listId,
|
|
||||||
accountId,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeFromListSuccess = (listId, accountId) => ({
|
|
||||||
type: LIST_EDITOR_REMOVE_SUCCESS,
|
|
||||||
listId,
|
|
||||||
accountId,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeFromListFail = (listId, accountId, error) => ({
|
|
||||||
type: LIST_EDITOR_REMOVE_FAIL,
|
|
||||||
listId,
|
|
||||||
accountId,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const resetListAdder = () => ({
|
|
||||||
type: LIST_ADDER_RESET,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setupListAdder = accountId => (dispatch, getState) => {
|
|
||||||
dispatch({
|
|
||||||
type: LIST_ADDER_SETUP,
|
|
||||||
account: getState().getIn(['accounts', accountId]),
|
|
||||||
});
|
|
||||||
dispatch(fetchLists());
|
|
||||||
dispatch(fetchAccountLists(accountId));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchAccountLists = accountId => (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchAccountListsRequest(accountId));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/accounts/${accountId}/lists`)
|
|
||||||
.then(({ data }) => dispatch(fetchAccountListsSuccess(accountId, data)))
|
|
||||||
.catch(err => dispatch(fetchAccountListsFail(accountId, err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchAccountListsRequest = id => ({
|
|
||||||
type: LIST_ADDER_LISTS_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchAccountListsSuccess = (id, lists) => ({
|
|
||||||
type: LIST_ADDER_LISTS_FETCH_SUCCESS,
|
|
||||||
id,
|
|
||||||
lists,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchAccountListsFail = (id, err) => ({
|
|
||||||
type: LIST_ADDER_LISTS_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
err,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addToListAdder = listId => (dispatch, getState) => {
|
|
||||||
dispatch(addToList(listId, getState().getIn(['listAdder', 'accountId'])));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeFromListAdder = listId => (dispatch, getState) => {
|
|
||||||
dispatch(removeFromList(listId, getState().getIn(['listAdder', 'accountId'])));
|
|
||||||
};
|
|
|
@ -0,0 +1,486 @@
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import { showAlertForError } from './alerts';
|
||||||
|
import { importFetchedAccounts } from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST';
|
||||||
|
const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS';
|
||||||
|
const LIST_FETCH_FAIL = 'LIST_FETCH_FAIL';
|
||||||
|
|
||||||
|
const LISTS_FETCH_REQUEST = 'LISTS_FETCH_REQUEST';
|
||||||
|
const LISTS_FETCH_SUCCESS = 'LISTS_FETCH_SUCCESS';
|
||||||
|
const LISTS_FETCH_FAIL = 'LISTS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE';
|
||||||
|
const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET';
|
||||||
|
const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP';
|
||||||
|
|
||||||
|
const LIST_CREATE_REQUEST = 'LIST_CREATE_REQUEST';
|
||||||
|
const LIST_CREATE_SUCCESS = 'LIST_CREATE_SUCCESS';
|
||||||
|
const LIST_CREATE_FAIL = 'LIST_CREATE_FAIL';
|
||||||
|
|
||||||
|
const LIST_UPDATE_REQUEST = 'LIST_UPDATE_REQUEST';
|
||||||
|
const LIST_UPDATE_SUCCESS = 'LIST_UPDATE_SUCCESS';
|
||||||
|
const LIST_UPDATE_FAIL = 'LIST_UPDATE_FAIL';
|
||||||
|
|
||||||
|
const LIST_DELETE_REQUEST = 'LIST_DELETE_REQUEST';
|
||||||
|
const LIST_DELETE_SUCCESS = 'LIST_DELETE_SUCCESS';
|
||||||
|
const LIST_DELETE_FAIL = 'LIST_DELETE_FAIL';
|
||||||
|
|
||||||
|
const LIST_ACCOUNTS_FETCH_REQUEST = 'LIST_ACCOUNTS_FETCH_REQUEST';
|
||||||
|
const LIST_ACCOUNTS_FETCH_SUCCESS = 'LIST_ACCOUNTS_FETCH_SUCCESS';
|
||||||
|
const LIST_ACCOUNTS_FETCH_FAIL = 'LIST_ACCOUNTS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const LIST_EDITOR_SUGGESTIONS_CHANGE = 'LIST_EDITOR_SUGGESTIONS_CHANGE';
|
||||||
|
const LIST_EDITOR_SUGGESTIONS_READY = 'LIST_EDITOR_SUGGESTIONS_READY';
|
||||||
|
const LIST_EDITOR_SUGGESTIONS_CLEAR = 'LIST_EDITOR_SUGGESTIONS_CLEAR';
|
||||||
|
|
||||||
|
const LIST_EDITOR_ADD_REQUEST = 'LIST_EDITOR_ADD_REQUEST';
|
||||||
|
const LIST_EDITOR_ADD_SUCCESS = 'LIST_EDITOR_ADD_SUCCESS';
|
||||||
|
const LIST_EDITOR_ADD_FAIL = 'LIST_EDITOR_ADD_FAIL';
|
||||||
|
|
||||||
|
const LIST_EDITOR_REMOVE_REQUEST = 'LIST_EDITOR_REMOVE_REQUEST';
|
||||||
|
const LIST_EDITOR_REMOVE_SUCCESS = 'LIST_EDITOR_REMOVE_SUCCESS';
|
||||||
|
const LIST_EDITOR_REMOVE_FAIL = 'LIST_EDITOR_REMOVE_FAIL';
|
||||||
|
|
||||||
|
const LIST_ADDER_RESET = 'LIST_ADDER_RESET';
|
||||||
|
const LIST_ADDER_SETUP = 'LIST_ADDER_SETUP';
|
||||||
|
|
||||||
|
const LIST_ADDER_LISTS_FETCH_REQUEST = 'LIST_ADDER_LISTS_FETCH_REQUEST';
|
||||||
|
const LIST_ADDER_LISTS_FETCH_SUCCESS = 'LIST_ADDER_LISTS_FETCH_SUCCESS';
|
||||||
|
const LIST_ADDER_LISTS_FETCH_FAIL = 'LIST_ADDER_LISTS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const fetchList = (id: string | number) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
if (getState().lists.get(String(id))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchListRequest(id));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/lists/${id}`)
|
||||||
|
.then(({ data }) => dispatch(fetchListSuccess(data)))
|
||||||
|
.catch(err => dispatch(fetchListFail(id, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchListRequest = (id: string | number) => ({
|
||||||
|
type: LIST_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchListSuccess = (list: APIEntity) => ({
|
||||||
|
type: LIST_FETCH_SUCCESS,
|
||||||
|
list,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchListFail = (id: string | number, error: AxiosError) => ({
|
||||||
|
type: LIST_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchLists = () => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(fetchListsRequest());
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/lists')
|
||||||
|
.then(({ data }) => dispatch(fetchListsSuccess(data)))
|
||||||
|
.catch(err => dispatch(fetchListsFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchListsRequest = () => ({
|
||||||
|
type: LISTS_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchListsSuccess = (lists: APIEntity[]) => ({
|
||||||
|
type: LISTS_FETCH_SUCCESS,
|
||||||
|
lists,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchListsFail = (error: AxiosError) => ({
|
||||||
|
type: LISTS_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitListEditor = (shouldReset?: boolean) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const listId = getState().listEditor.listId!;
|
||||||
|
const title = getState().listEditor.title;
|
||||||
|
|
||||||
|
if (listId === null) {
|
||||||
|
dispatch(createList(title, shouldReset));
|
||||||
|
} else {
|
||||||
|
dispatch(updateList(listId, title, shouldReset));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setupListEditor = (listId: string | number) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({
|
||||||
|
type: LIST_EDITOR_SETUP,
|
||||||
|
list: getState().lists.get(String(listId)),
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(fetchListAccounts(listId));
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeListEditorTitle = (value: string) => ({
|
||||||
|
type: LIST_EDITOR_TITLE_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createList = (title: string, shouldReset?: boolean) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(createListRequest());
|
||||||
|
|
||||||
|
api(getState).post('/api/v1/lists', { title }).then(({ data }) => {
|
||||||
|
dispatch(createListSuccess(data));
|
||||||
|
|
||||||
|
if (shouldReset) {
|
||||||
|
dispatch(resetListEditor());
|
||||||
|
}
|
||||||
|
}).catch(err => dispatch(createListFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const createListRequest = () => ({
|
||||||
|
type: LIST_CREATE_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createListSuccess = (list: APIEntity) => ({
|
||||||
|
type: LIST_CREATE_SUCCESS,
|
||||||
|
list,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createListFail = (error: AxiosError) => ({
|
||||||
|
type: LIST_CREATE_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateList = (id: string | number, title: string, shouldReset?: boolean) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(updateListRequest(id));
|
||||||
|
|
||||||
|
api(getState).put(`/api/v1/lists/${id}`, { title }).then(({ data }) => {
|
||||||
|
dispatch(updateListSuccess(data));
|
||||||
|
|
||||||
|
if (shouldReset) {
|
||||||
|
dispatch(resetListEditor());
|
||||||
|
}
|
||||||
|
}).catch(err => dispatch(updateListFail(id, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateListRequest = (id: string | number) => ({
|
||||||
|
type: LIST_UPDATE_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateListSuccess = (list: APIEntity) => ({
|
||||||
|
type: LIST_UPDATE_SUCCESS,
|
||||||
|
list,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateListFail = (id: string | number, error: AxiosError) => ({
|
||||||
|
type: LIST_UPDATE_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const resetListEditor = () => ({
|
||||||
|
type: LIST_EDITOR_RESET,
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteList = (id: string | number) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(deleteListRequest(id));
|
||||||
|
|
||||||
|
api(getState).delete(`/api/v1/lists/${id}`)
|
||||||
|
.then(() => dispatch(deleteListSuccess(id)))
|
||||||
|
.catch(err => dispatch(deleteListFail(id, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteListRequest = (id: string | number) => ({
|
||||||
|
type: LIST_DELETE_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteListSuccess = (id: string | number) => ({
|
||||||
|
type: LIST_DELETE_SUCCESS,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteListFail = (id: string | number, error: AxiosError) => ({
|
||||||
|
type: LIST_DELETE_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchListAccounts = (listId: string | number) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(fetchListAccountsRequest(listId));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }).then(({ data }) => {
|
||||||
|
dispatch(importFetchedAccounts(data));
|
||||||
|
dispatch(fetchListAccountsSuccess(listId, data, null));
|
||||||
|
}).catch(err => dispatch(fetchListAccountsFail(listId, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchListAccountsRequest = (id: string | number) => ({
|
||||||
|
type: LIST_ACCOUNTS_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchListAccountsSuccess = (id: string | number, accounts: APIEntity[], next: string | null) => ({
|
||||||
|
type: LIST_ACCOUNTS_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchListAccountsFail = (id: string | number, error: AxiosError) => ({
|
||||||
|
type: LIST_ACCOUNTS_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchListSuggestions = (q: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
q,
|
||||||
|
resolve: false,
|
||||||
|
limit: 4,
|
||||||
|
following: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
|
||||||
|
dispatch(importFetchedAccounts(data));
|
||||||
|
dispatch(fetchListSuggestionsReady(q, data));
|
||||||
|
}).catch(error => dispatch(showAlertForError(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchListSuggestionsReady = (query: string, accounts: APIEntity[]) => ({
|
||||||
|
type: LIST_EDITOR_SUGGESTIONS_READY,
|
||||||
|
query,
|
||||||
|
accounts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const clearListSuggestions = () => ({
|
||||||
|
type: LIST_EDITOR_SUGGESTIONS_CLEAR,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeListSuggestions = (value: string) => ({
|
||||||
|
type: LIST_EDITOR_SUGGESTIONS_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addToListEditor = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(addToList(getState().listEditor.listId!, accountId));
|
||||||
|
};
|
||||||
|
|
||||||
|
const addToList = (listId: string | number, accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(addToListRequest(listId, accountId));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/lists/${listId}/accounts`, { account_ids: [accountId] })
|
||||||
|
.then(() => dispatch(addToListSuccess(listId, accountId)))
|
||||||
|
.catch(err => dispatch(addToListFail(listId, accountId, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const addToListRequest = (listId: string | number, accountId: string) => ({
|
||||||
|
type: LIST_EDITOR_ADD_REQUEST,
|
||||||
|
listId,
|
||||||
|
accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addToListSuccess = (listId: string | number, accountId: string) => ({
|
||||||
|
type: LIST_EDITOR_ADD_SUCCESS,
|
||||||
|
listId,
|
||||||
|
accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addToListFail = (listId: string | number, accountId: string, error: APIEntity) => ({
|
||||||
|
type: LIST_EDITOR_ADD_FAIL,
|
||||||
|
listId,
|
||||||
|
accountId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeFromListEditor = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(removeFromList(getState().listEditor.listId!, accountId));
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeFromList = (listId: string | number, accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(removeFromListRequest(listId, accountId));
|
||||||
|
|
||||||
|
api(getState).delete(`/api/v1/lists/${listId}/accounts`, { params: { account_ids: [accountId] } })
|
||||||
|
.then(() => dispatch(removeFromListSuccess(listId, accountId)))
|
||||||
|
.catch(err => dispatch(removeFromListFail(listId, accountId, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeFromListRequest = (listId: string | number, accountId: string) => ({
|
||||||
|
type: LIST_EDITOR_REMOVE_REQUEST,
|
||||||
|
listId,
|
||||||
|
accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeFromListSuccess = (listId: string | number, accountId: string) => ({
|
||||||
|
type: LIST_EDITOR_REMOVE_SUCCESS,
|
||||||
|
listId,
|
||||||
|
accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeFromListFail = (listId: string | number, accountId: string, error: AxiosError) => ({
|
||||||
|
type: LIST_EDITOR_REMOVE_FAIL,
|
||||||
|
listId,
|
||||||
|
accountId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const resetListAdder = () => ({
|
||||||
|
type: LIST_ADDER_RESET,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setupListAdder = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({
|
||||||
|
type: LIST_ADDER_SETUP,
|
||||||
|
account: getState().accounts.get(accountId),
|
||||||
|
});
|
||||||
|
dispatch(fetchLists());
|
||||||
|
dispatch(fetchAccountLists(accountId));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchAccountLists = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
|
dispatch(fetchAccountListsRequest(accountId));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/accounts/${accountId}/lists`)
|
||||||
|
.then(({ data }) => dispatch(fetchAccountListsSuccess(accountId, data)))
|
||||||
|
.catch(err => dispatch(fetchAccountListsFail(accountId, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchAccountListsRequest = (id: string) => ({
|
||||||
|
type: LIST_ADDER_LISTS_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchAccountListsSuccess = (id: string, lists: APIEntity[]) => ({
|
||||||
|
type: LIST_ADDER_LISTS_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
lists,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchAccountListsFail = (id: string, err: AxiosError) => ({
|
||||||
|
type: LIST_ADDER_LISTS_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addToListAdder = (listId: string | number) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(addToList(listId, getState().listAdder.accountId!));
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeFromListAdder = (listId: string | number) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(removeFromList(listId, getState().listAdder.accountId!));
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
LIST_FETCH_REQUEST,
|
||||||
|
LIST_FETCH_SUCCESS,
|
||||||
|
LIST_FETCH_FAIL,
|
||||||
|
LISTS_FETCH_REQUEST,
|
||||||
|
LISTS_FETCH_SUCCESS,
|
||||||
|
LISTS_FETCH_FAIL,
|
||||||
|
LIST_EDITOR_TITLE_CHANGE,
|
||||||
|
LIST_EDITOR_RESET,
|
||||||
|
LIST_EDITOR_SETUP,
|
||||||
|
LIST_CREATE_REQUEST,
|
||||||
|
LIST_CREATE_SUCCESS,
|
||||||
|
LIST_CREATE_FAIL,
|
||||||
|
LIST_UPDATE_REQUEST,
|
||||||
|
LIST_UPDATE_SUCCESS,
|
||||||
|
LIST_UPDATE_FAIL,
|
||||||
|
LIST_DELETE_REQUEST,
|
||||||
|
LIST_DELETE_SUCCESS,
|
||||||
|
LIST_DELETE_FAIL,
|
||||||
|
LIST_ACCOUNTS_FETCH_REQUEST,
|
||||||
|
LIST_ACCOUNTS_FETCH_SUCCESS,
|
||||||
|
LIST_ACCOUNTS_FETCH_FAIL,
|
||||||
|
LIST_EDITOR_SUGGESTIONS_CHANGE,
|
||||||
|
LIST_EDITOR_SUGGESTIONS_READY,
|
||||||
|
LIST_EDITOR_SUGGESTIONS_CLEAR,
|
||||||
|
LIST_EDITOR_ADD_REQUEST,
|
||||||
|
LIST_EDITOR_ADD_SUCCESS,
|
||||||
|
LIST_EDITOR_ADD_FAIL,
|
||||||
|
LIST_EDITOR_REMOVE_REQUEST,
|
||||||
|
LIST_EDITOR_REMOVE_SUCCESS,
|
||||||
|
LIST_EDITOR_REMOVE_FAIL,
|
||||||
|
LIST_ADDER_RESET,
|
||||||
|
LIST_ADDER_SETUP,
|
||||||
|
LIST_ADDER_LISTS_FETCH_REQUEST,
|
||||||
|
LIST_ADDER_LISTS_FETCH_SUCCESS,
|
||||||
|
LIST_ADDER_LISTS_FETCH_FAIL,
|
||||||
|
fetchList,
|
||||||
|
fetchListRequest,
|
||||||
|
fetchListSuccess,
|
||||||
|
fetchListFail,
|
||||||
|
fetchLists,
|
||||||
|
fetchListsRequest,
|
||||||
|
fetchListsSuccess,
|
||||||
|
fetchListsFail,
|
||||||
|
submitListEditor,
|
||||||
|
setupListEditor,
|
||||||
|
changeListEditorTitle,
|
||||||
|
createList,
|
||||||
|
createListRequest,
|
||||||
|
createListSuccess,
|
||||||
|
createListFail,
|
||||||
|
updateList,
|
||||||
|
updateListRequest,
|
||||||
|
updateListSuccess,
|
||||||
|
updateListFail,
|
||||||
|
resetListEditor,
|
||||||
|
deleteList,
|
||||||
|
deleteListRequest,
|
||||||
|
deleteListSuccess,
|
||||||
|
deleteListFail,
|
||||||
|
fetchListAccounts,
|
||||||
|
fetchListAccountsRequest,
|
||||||
|
fetchListAccountsSuccess,
|
||||||
|
fetchListAccountsFail,
|
||||||
|
fetchListSuggestions,
|
||||||
|
fetchListSuggestionsReady,
|
||||||
|
clearListSuggestions,
|
||||||
|
changeListSuggestions,
|
||||||
|
addToListEditor,
|
||||||
|
addToList,
|
||||||
|
addToListRequest,
|
||||||
|
addToListSuccess,
|
||||||
|
addToListFail,
|
||||||
|
removeFromListEditor,
|
||||||
|
removeFromList,
|
||||||
|
removeFromListRequest,
|
||||||
|
removeFromListSuccess,
|
||||||
|
removeFromListFail,
|
||||||
|
resetListAdder,
|
||||||
|
setupListAdder,
|
||||||
|
fetchAccountLists,
|
||||||
|
fetchAccountListsRequest,
|
||||||
|
fetchAccountListsSuccess,
|
||||||
|
fetchAccountListsFail,
|
||||||
|
addToListAdder,
|
||||||
|
removeFromListAdder,
|
||||||
|
};
|
|
@ -1,33 +0,0 @@
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
export const MARKER_FETCH_REQUEST = 'MARKER_FETCH_REQUEST';
|
|
||||||
export const MARKER_FETCH_SUCCESS = 'MARKER_FETCH_SUCCESS';
|
|
||||||
export const MARKER_FETCH_FAIL = 'MARKER_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const MARKER_SAVE_REQUEST = 'MARKER_SAVE_REQUEST';
|
|
||||||
export const MARKER_SAVE_SUCCESS = 'MARKER_SAVE_SUCCESS';
|
|
||||||
export const MARKER_SAVE_FAIL = 'MARKER_SAVE_FAIL';
|
|
||||||
|
|
||||||
export function fetchMarker(timeline) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: MARKER_FETCH_REQUEST });
|
|
||||||
return api(getState).get('/api/v1/markers', {
|
|
||||||
params: { timeline },
|
|
||||||
}).then(({ data: marker }) => {
|
|
||||||
dispatch({ type: MARKER_FETCH_SUCCESS, marker });
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: MARKER_FETCH_FAIL, error });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function saveMarker(marker) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: MARKER_SAVE_REQUEST, marker });
|
|
||||||
return api(getState).post('/api/v1/markers', marker).then(({ data: marker }) => {
|
|
||||||
dispatch({ type: MARKER_SAVE_SUCCESS, marker });
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: MARKER_SAVE_FAIL, error });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const MARKER_FETCH_REQUEST = 'MARKER_FETCH_REQUEST';
|
||||||
|
const MARKER_FETCH_SUCCESS = 'MARKER_FETCH_SUCCESS';
|
||||||
|
const MARKER_FETCH_FAIL = 'MARKER_FETCH_FAIL';
|
||||||
|
|
||||||
|
const MARKER_SAVE_REQUEST = 'MARKER_SAVE_REQUEST';
|
||||||
|
const MARKER_SAVE_SUCCESS = 'MARKER_SAVE_SUCCESS';
|
||||||
|
const MARKER_SAVE_FAIL = 'MARKER_SAVE_FAIL';
|
||||||
|
|
||||||
|
const fetchMarker = (timeline: Array<string>) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: MARKER_FETCH_REQUEST });
|
||||||
|
return api(getState).get('/api/v1/markers', {
|
||||||
|
params: { timeline },
|
||||||
|
}).then(({ data: marker }) => {
|
||||||
|
dispatch({ type: MARKER_FETCH_SUCCESS, marker });
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({ type: MARKER_FETCH_FAIL, error });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveMarker = (marker: APIEntity) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: MARKER_SAVE_REQUEST, marker });
|
||||||
|
return api(getState).post('/api/v1/markers', marker).then(({ data: marker }) => {
|
||||||
|
dispatch({ type: MARKER_SAVE_SUCCESS, marker });
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({ type: MARKER_SAVE_FAIL, error });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
MARKER_FETCH_REQUEST,
|
||||||
|
MARKER_FETCH_SUCCESS,
|
||||||
|
MARKER_FETCH_FAIL,
|
||||||
|
MARKER_SAVE_REQUEST,
|
||||||
|
MARKER_SAVE_SUCCESS,
|
||||||
|
MARKER_SAVE_FAIL,
|
||||||
|
fetchMarker,
|
||||||
|
saveMarker,
|
||||||
|
};
|
|
@ -1,123 +0,0 @@
|
||||||
import KVStore from 'soapbox/storage/kv_store';
|
|
||||||
import { getAuthUserId, getAuthUserUrl } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
import { loadCredentials } from './auth';
|
|
||||||
import { importFetchedAccount } from './importer';
|
|
||||||
|
|
||||||
export const ME_FETCH_REQUEST = 'ME_FETCH_REQUEST';
|
|
||||||
export const ME_FETCH_SUCCESS = 'ME_FETCH_SUCCESS';
|
|
||||||
export const ME_FETCH_FAIL = 'ME_FETCH_FAIL';
|
|
||||||
export const ME_FETCH_SKIP = 'ME_FETCH_SKIP';
|
|
||||||
|
|
||||||
export const ME_PATCH_REQUEST = 'ME_PATCH_REQUEST';
|
|
||||||
export const ME_PATCH_SUCCESS = 'ME_PATCH_SUCCESS';
|
|
||||||
export const ME_PATCH_FAIL = 'ME_PATCH_FAIL';
|
|
||||||
|
|
||||||
const noOp = () => new Promise(f => f());
|
|
||||||
|
|
||||||
const getMeId = state => state.get('me') || getAuthUserId(state);
|
|
||||||
|
|
||||||
const getMeUrl = state => {
|
|
||||||
const accountId = getMeId(state);
|
|
||||||
return state.getIn(['accounts', accountId, 'url']) || getAuthUserUrl(state);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getMeToken = state => {
|
|
||||||
// Fallback for upgrading IDs to URLs
|
|
||||||
const accountUrl = getMeUrl(state) || state.getIn(['auth', 'me']);
|
|
||||||
return state.getIn(['auth', 'users', accountUrl, 'access_token']);
|
|
||||||
};
|
|
||||||
|
|
||||||
export function fetchMe() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const token = getMeToken(state);
|
|
||||||
const accountUrl = getMeUrl(state);
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
dispatch({ type: ME_FETCH_SKIP }); return noOp();
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchMeRequest());
|
|
||||||
return dispatch(loadCredentials(token, accountUrl)).catch(error => {
|
|
||||||
dispatch(fetchMeFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Update the auth account in IndexedDB for Mastodon, etc. */
|
|
||||||
const persistAuthAccount = (account, params) => {
|
|
||||||
if (account && account.url) {
|
|
||||||
if (!account.pleroma) account.pleroma = {};
|
|
||||||
|
|
||||||
if (!account.pleroma.settings_store) {
|
|
||||||
account.pleroma.settings_store = params.pleroma_settings_store || {};
|
|
||||||
}
|
|
||||||
KVStore.setItem(`authAccount:${account.url}`, account).catch(console.error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export function patchMe(params) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch(patchMeRequest());
|
|
||||||
|
|
||||||
return api(getState)
|
|
||||||
.patch('/api/v1/accounts/update_credentials', params)
|
|
||||||
.then(response => {
|
|
||||||
persistAuthAccount(response.data, params);
|
|
||||||
dispatch(patchMeSuccess(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(patchMeFail(error));
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMeRequest() {
|
|
||||||
return {
|
|
||||||
type: ME_FETCH_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMeSuccess(me) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({
|
|
||||||
type: ME_FETCH_SUCCESS,
|
|
||||||
me,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMeFail(error) {
|
|
||||||
return {
|
|
||||||
type: ME_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
skipAlert: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function patchMeRequest() {
|
|
||||||
return {
|
|
||||||
type: ME_PATCH_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function patchMeSuccess(me) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch(importFetchedAccount(me));
|
|
||||||
dispatch({
|
|
||||||
type: ME_PATCH_SUCCESS,
|
|
||||||
me,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function patchMeFail(error) {
|
|
||||||
return {
|
|
||||||
type: ME_PATCH_FAIL,
|
|
||||||
error,
|
|
||||||
skipAlert: true,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
import KVStore from 'soapbox/storage/kv_store';
|
||||||
|
import { getAuthUserId, getAuthUserUrl } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import { loadCredentials } from './auth';
|
||||||
|
import { importFetchedAccount } from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const ME_FETCH_REQUEST = 'ME_FETCH_REQUEST';
|
||||||
|
const ME_FETCH_SUCCESS = 'ME_FETCH_SUCCESS';
|
||||||
|
const ME_FETCH_FAIL = 'ME_FETCH_FAIL';
|
||||||
|
const ME_FETCH_SKIP = 'ME_FETCH_SKIP';
|
||||||
|
|
||||||
|
const ME_PATCH_REQUEST = 'ME_PATCH_REQUEST';
|
||||||
|
const ME_PATCH_SUCCESS = 'ME_PATCH_SUCCESS';
|
||||||
|
const ME_PATCH_FAIL = 'ME_PATCH_FAIL';
|
||||||
|
|
||||||
|
const noOp = () => new Promise(f => f(undefined));
|
||||||
|
|
||||||
|
const getMeId = (state: RootState) => state.me || getAuthUserId(state);
|
||||||
|
|
||||||
|
const getMeUrl = (state: RootState) => {
|
||||||
|
const accountId = getMeId(state);
|
||||||
|
return state.accounts.get(accountId)?.url || getAuthUserUrl(state);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMeToken = (state: RootState) => {
|
||||||
|
// Fallback for upgrading IDs to URLs
|
||||||
|
const accountUrl = getMeUrl(state) || state.auth.get('me');
|
||||||
|
return state.auth.getIn(['users', accountUrl, 'access_token']);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchMe = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
const token = getMeToken(state);
|
||||||
|
const accountUrl = getMeUrl(state);
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
dispatch({ type: ME_FETCH_SKIP }); return noOp();
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchMeRequest());
|
||||||
|
return dispatch(loadCredentials(token, accountUrl)).catch(error => {
|
||||||
|
dispatch(fetchMeFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Update the auth account in IndexedDB for Mastodon, etc. */
|
||||||
|
const persistAuthAccount = (account: APIEntity, params: Record<string, any>) => {
|
||||||
|
if (account && account.url) {
|
||||||
|
if (!account.pleroma) account.pleroma = {};
|
||||||
|
|
||||||
|
if (!account.pleroma.settings_store) {
|
||||||
|
account.pleroma.settings_store = params.pleroma_settings_store || {};
|
||||||
|
}
|
||||||
|
KVStore.setItem(`authAccount:${account.url}`, account).catch(console.error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const patchMe = (params: Record<string, any>) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(patchMeRequest());
|
||||||
|
|
||||||
|
return api(getState)
|
||||||
|
.patch('/api/v1/accounts/update_credentials', params)
|
||||||
|
.then(response => {
|
||||||
|
persistAuthAccount(response.data, params);
|
||||||
|
dispatch(patchMeSuccess(response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(patchMeFail(error));
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchMeRequest = () => ({
|
||||||
|
type: ME_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchMeSuccess = (me: APIEntity) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: ME_FETCH_SUCCESS,
|
||||||
|
me,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchMeFail = (error: APIEntity) => ({
|
||||||
|
type: ME_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
skipAlert: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const patchMeRequest = () => ({
|
||||||
|
type: ME_PATCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const patchMeSuccess = (me: APIEntity) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
dispatch(importFetchedAccount(me));
|
||||||
|
dispatch({
|
||||||
|
type: ME_PATCH_SUCCESS,
|
||||||
|
me,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const patchMeFail = (error: AxiosError) => ({
|
||||||
|
type: ME_PATCH_FAIL,
|
||||||
|
error,
|
||||||
|
skipAlert: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
ME_FETCH_REQUEST,
|
||||||
|
ME_FETCH_SUCCESS,
|
||||||
|
ME_FETCH_FAIL,
|
||||||
|
ME_FETCH_SKIP,
|
||||||
|
ME_PATCH_REQUEST,
|
||||||
|
ME_PATCH_SUCCESS,
|
||||||
|
ME_PATCH_FAIL,
|
||||||
|
fetchMe,
|
||||||
|
patchMe,
|
||||||
|
fetchMeRequest,
|
||||||
|
fetchMeSuccess,
|
||||||
|
fetchMeFail,
|
||||||
|
patchMeRequest,
|
||||||
|
patchMeSuccess,
|
||||||
|
patchMeFail,
|
||||||
|
};
|
|
@ -1,47 +0,0 @@
|
||||||
import { getFeatures } from 'soapbox/utils/features';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
const noOp = () => {};
|
|
||||||
|
|
||||||
export function fetchMedia(mediaId) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
return api(getState).get(`/api/v1/media/${mediaId}`);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateMedia(mediaId, params) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
return api(getState).put(`/api/v1/media/${mediaId}`, params);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uploadMediaV1(data, onUploadProgress = noOp) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
return api(getState).post('/api/v1/media', data, {
|
|
||||||
onUploadProgress: onUploadProgress,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uploadMediaV2(data, onUploadProgress = noOp) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
return api(getState).post('/api/v2/media', data, {
|
|
||||||
onUploadProgress: onUploadProgress,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uploadMedia(data, onUploadProgress = noOp) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const instance = state.get('instance');
|
|
||||||
const features = getFeatures(instance);
|
|
||||||
|
|
||||||
if (features.mediaV2) {
|
|
||||||
return dispatch(uploadMediaV2(data, onUploadProgress));
|
|
||||||
} else {
|
|
||||||
return dispatch(uploadMediaV1(data, onUploadProgress));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { getFeatures } from 'soapbox/utils/features';
|
||||||
|
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
const noOp = (e: any) => {};
|
||||||
|
|
||||||
|
const fetchMedia = (mediaId: string) =>
|
||||||
|
(dispatch: any, getState: () => RootState) => {
|
||||||
|
return api(getState).get(`/api/v1/media/${mediaId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateMedia = (mediaId: string, params: Record<string, any>) =>
|
||||||
|
(dispatch: any, getState: () => RootState) => {
|
||||||
|
return api(getState).put(`/api/v1/media/${mediaId}`, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
const uploadMediaV1 = (data: FormData, onUploadProgress = noOp) =>
|
||||||
|
(dispatch: any, getState: () => RootState) =>
|
||||||
|
api(getState).post('/api/v1/media', data, {
|
||||||
|
onUploadProgress: onUploadProgress,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const uploadMediaV2 = (data: FormData, onUploadProgress = noOp) =>
|
||||||
|
(dispatch: any, getState: () => RootState) =>
|
||||||
|
api(getState).post('/api/v2/media', data, {
|
||||||
|
onUploadProgress: onUploadProgress,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const uploadMedia = (data: FormData, onUploadProgress = noOp) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
const instance = state.instance;
|
||||||
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
|
if (features.mediaV2) {
|
||||||
|
return dispatch(uploadMediaV2(data, onUploadProgress));
|
||||||
|
} else {
|
||||||
|
return dispatch(uploadMediaV1(data, onUploadProgress));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
fetchMedia,
|
||||||
|
updateMedia,
|
||||||
|
uploadMediaV1,
|
||||||
|
uploadMediaV2,
|
||||||
|
uploadMedia,
|
||||||
|
};
|
|
@ -1,84 +0,0 @@
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
export const MFA_FETCH_REQUEST = 'MFA_FETCH_REQUEST';
|
|
||||||
export const MFA_FETCH_SUCCESS = 'MFA_FETCH_SUCCESS';
|
|
||||||
export const MFA_FETCH_FAIL = 'MFA_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const MFA_BACKUP_CODES_FETCH_REQUEST = 'MFA_BACKUP_CODES_FETCH_REQUEST';
|
|
||||||
export const MFA_BACKUP_CODES_FETCH_SUCCESS = 'MFA_BACKUP_CODES_FETCH_SUCCESS';
|
|
||||||
export const MFA_BACKUP_CODES_FETCH_FAIL = 'MFA_BACKUP_CODES_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const MFA_SETUP_REQUEST = 'MFA_SETUP_REQUEST';
|
|
||||||
export const MFA_SETUP_SUCCESS = 'MFA_SETUP_SUCCESS';
|
|
||||||
export const MFA_SETUP_FAIL = 'MFA_SETUP_FAIL';
|
|
||||||
|
|
||||||
export const MFA_CONFIRM_REQUEST = 'MFA_CONFIRM_REQUEST';
|
|
||||||
export const MFA_CONFIRM_SUCCESS = 'MFA_CONFIRM_SUCCESS';
|
|
||||||
export const MFA_CONFIRM_FAIL = 'MFA_CONFIRM_FAIL';
|
|
||||||
|
|
||||||
export const MFA_DISABLE_REQUEST = 'MFA_DISABLE_REQUEST';
|
|
||||||
export const MFA_DISABLE_SUCCESS = 'MFA_DISABLE_SUCCESS';
|
|
||||||
export const MFA_DISABLE_FAIL = 'MFA_DISABLE_FAIL';
|
|
||||||
|
|
||||||
export function fetchMfa() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: MFA_FETCH_REQUEST });
|
|
||||||
return api(getState).get('/api/pleroma/accounts/mfa').then(({ data }) => {
|
|
||||||
dispatch({ type: MFA_FETCH_SUCCESS, data });
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: MFA_FETCH_FAIL });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchBackupCodes() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: MFA_BACKUP_CODES_FETCH_REQUEST });
|
|
||||||
return api(getState).get('/api/pleroma/accounts/mfa/backup_codes').then(({ data }) => {
|
|
||||||
dispatch({ type: MFA_BACKUP_CODES_FETCH_SUCCESS, data });
|
|
||||||
return data;
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: MFA_BACKUP_CODES_FETCH_FAIL });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setupMfa(method) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: MFA_SETUP_REQUEST, method });
|
|
||||||
return api(getState).get(`/api/pleroma/accounts/mfa/setup/${method}`).then(({ data }) => {
|
|
||||||
dispatch({ type: MFA_SETUP_SUCCESS, data });
|
|
||||||
return data;
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: MFA_SETUP_FAIL });
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function confirmMfa(method, code, password) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const params = { code, password };
|
|
||||||
dispatch({ type: MFA_CONFIRM_REQUEST, method, code });
|
|
||||||
return api(getState).post(`/api/pleroma/accounts/mfa/confirm/${method}`, params).then(({ data }) => {
|
|
||||||
dispatch({ type: MFA_CONFIRM_SUCCESS, method, code });
|
|
||||||
return data;
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: MFA_CONFIRM_FAIL, method, code, error, skipAlert: true });
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function disableMfa(method, password) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: MFA_DISABLE_REQUEST, method });
|
|
||||||
return api(getState).delete(`/api/pleroma/accounts/mfa/${method}`, { data: { password } }).then(({ data }) => {
|
|
||||||
dispatch({ type: MFA_DISABLE_SUCCESS, method });
|
|
||||||
return data;
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: MFA_DISABLE_FAIL, method, skipAlert: true });
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
const MFA_FETCH_REQUEST = 'MFA_FETCH_REQUEST';
|
||||||
|
const MFA_FETCH_SUCCESS = 'MFA_FETCH_SUCCESS';
|
||||||
|
const MFA_FETCH_FAIL = 'MFA_FETCH_FAIL';
|
||||||
|
|
||||||
|
const MFA_BACKUP_CODES_FETCH_REQUEST = 'MFA_BACKUP_CODES_FETCH_REQUEST';
|
||||||
|
const MFA_BACKUP_CODES_FETCH_SUCCESS = 'MFA_BACKUP_CODES_FETCH_SUCCESS';
|
||||||
|
const MFA_BACKUP_CODES_FETCH_FAIL = 'MFA_BACKUP_CODES_FETCH_FAIL';
|
||||||
|
|
||||||
|
const MFA_SETUP_REQUEST = 'MFA_SETUP_REQUEST';
|
||||||
|
const MFA_SETUP_SUCCESS = 'MFA_SETUP_SUCCESS';
|
||||||
|
const MFA_SETUP_FAIL = 'MFA_SETUP_FAIL';
|
||||||
|
|
||||||
|
const MFA_CONFIRM_REQUEST = 'MFA_CONFIRM_REQUEST';
|
||||||
|
const MFA_CONFIRM_SUCCESS = 'MFA_CONFIRM_SUCCESS';
|
||||||
|
const MFA_CONFIRM_FAIL = 'MFA_CONFIRM_FAIL';
|
||||||
|
|
||||||
|
const MFA_DISABLE_REQUEST = 'MFA_DISABLE_REQUEST';
|
||||||
|
const MFA_DISABLE_SUCCESS = 'MFA_DISABLE_SUCCESS';
|
||||||
|
const MFA_DISABLE_FAIL = 'MFA_DISABLE_FAIL';
|
||||||
|
|
||||||
|
const fetchMfa = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: MFA_FETCH_REQUEST });
|
||||||
|
return api(getState).get('/api/pleroma/accounts/mfa').then(({ data }) => {
|
||||||
|
dispatch({ type: MFA_FETCH_SUCCESS, data });
|
||||||
|
}).catch(() => {
|
||||||
|
dispatch({ type: MFA_FETCH_FAIL });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchBackupCodes = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: MFA_BACKUP_CODES_FETCH_REQUEST });
|
||||||
|
return api(getState).get('/api/pleroma/accounts/mfa/backup_codes').then(({ data }) => {
|
||||||
|
dispatch({ type: MFA_BACKUP_CODES_FETCH_SUCCESS, data });
|
||||||
|
return data;
|
||||||
|
}).catch(() => {
|
||||||
|
dispatch({ type: MFA_BACKUP_CODES_FETCH_FAIL });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setupMfa = (method: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: MFA_SETUP_REQUEST, method });
|
||||||
|
return api(getState).get(`/api/pleroma/accounts/mfa/setup/${method}`).then(({ data }) => {
|
||||||
|
dispatch({ type: MFA_SETUP_SUCCESS, data });
|
||||||
|
return data;
|
||||||
|
}).catch((error: AxiosError) => {
|
||||||
|
dispatch({ type: MFA_SETUP_FAIL });
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmMfa = (method: string, code: string, password: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const params = { code, password };
|
||||||
|
dispatch({ type: MFA_CONFIRM_REQUEST, method, code });
|
||||||
|
return api(getState).post(`/api/pleroma/accounts/mfa/confirm/${method}`, params).then(({ data }) => {
|
||||||
|
dispatch({ type: MFA_CONFIRM_SUCCESS, method, code });
|
||||||
|
return data;
|
||||||
|
}).catch((error: AxiosError) => {
|
||||||
|
dispatch({ type: MFA_CONFIRM_FAIL, method, code, error, skipAlert: true });
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const disableMfa = (method: string, password: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: MFA_DISABLE_REQUEST, method });
|
||||||
|
return api(getState).delete(`/api/pleroma/accounts/mfa/${method}`, { data: { password } }).then(({ data }) => {
|
||||||
|
dispatch({ type: MFA_DISABLE_SUCCESS, method });
|
||||||
|
return data;
|
||||||
|
}).catch((error: AxiosError) => {
|
||||||
|
dispatch({ type: MFA_DISABLE_FAIL, method, skipAlert: true });
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
MFA_FETCH_REQUEST,
|
||||||
|
MFA_FETCH_SUCCESS,
|
||||||
|
MFA_FETCH_FAIL,
|
||||||
|
MFA_BACKUP_CODES_FETCH_REQUEST,
|
||||||
|
MFA_BACKUP_CODES_FETCH_SUCCESS,
|
||||||
|
MFA_BACKUP_CODES_FETCH_FAIL,
|
||||||
|
MFA_SETUP_REQUEST,
|
||||||
|
MFA_SETUP_SUCCESS,
|
||||||
|
MFA_SETUP_FAIL,
|
||||||
|
MFA_CONFIRM_REQUEST,
|
||||||
|
MFA_CONFIRM_SUCCESS,
|
||||||
|
MFA_CONFIRM_FAIL,
|
||||||
|
MFA_DISABLE_REQUEST,
|
||||||
|
MFA_DISABLE_SUCCESS,
|
||||||
|
MFA_DISABLE_FAIL,
|
||||||
|
fetchMfa,
|
||||||
|
fetchBackupCodes,
|
||||||
|
setupMfa,
|
||||||
|
confirmMfa,
|
||||||
|
disableMfa,
|
||||||
|
};
|
|
@ -1,11 +1,13 @@
|
||||||
import { staticClient } from '../api';
|
import { staticClient } from '../api';
|
||||||
|
|
||||||
export const FETCH_MOBILE_PAGE_REQUEST = 'FETCH_MOBILE_PAGE_REQUEST';
|
import type { AppDispatch } from 'soapbox/store';
|
||||||
export const FETCH_MOBILE_PAGE_SUCCESS = 'FETCH_MOBILE_PAGE_SUCCESS';
|
|
||||||
export const FETCH_MOBILE_PAGE_FAIL = 'FETCH_MOBILE_PAGE_FAIL';
|
|
||||||
|
|
||||||
export function fetchMobilePage(slug = 'index', locale) {
|
const FETCH_MOBILE_PAGE_REQUEST = 'FETCH_MOBILE_PAGE_REQUEST';
|
||||||
return (dispatch, getState) => {
|
const FETCH_MOBILE_PAGE_SUCCESS = 'FETCH_MOBILE_PAGE_SUCCESS';
|
||||||
|
const FETCH_MOBILE_PAGE_FAIL = 'FETCH_MOBILE_PAGE_FAIL';
|
||||||
|
|
||||||
|
const fetchMobilePage = (slug = 'index', locale?: string) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
dispatch({ type: FETCH_MOBILE_PAGE_REQUEST, slug, locale });
|
dispatch({ type: FETCH_MOBILE_PAGE_REQUEST, slug, locale });
|
||||||
const filename = `${slug}${locale ? `.${locale}` : ''}.html`;
|
const filename = `${slug}${locale ? `.${locale}` : ''}.html`;
|
||||||
return staticClient.get(`/instance/mobile/${filename}`).then(({ data: html }) => {
|
return staticClient.get(`/instance/mobile/${filename}`).then(({ data: html }) => {
|
||||||
|
@ -16,4 +18,10 @@ export function fetchMobilePage(slug = 'index', locale) {
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
export {
|
||||||
|
FETCH_MOBILE_PAGE_REQUEST,
|
||||||
|
FETCH_MOBILE_PAGE_SUCCESS,
|
||||||
|
FETCH_MOBILE_PAGE_FAIL,
|
||||||
|
fetchMobilePage,
|
||||||
|
};
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { defineMessages } from 'react-intl';
|
import { defineMessages, IntlShape } from 'react-intl';
|
||||||
|
|
||||||
import { fetchAccountByUsername } from 'soapbox/actions/accounts';
|
import { fetchAccountByUsername } from 'soapbox/actions/accounts';
|
||||||
import { deactivateUsers, deleteUsers, deleteStatus, toggleStatusSensitivity } from 'soapbox/actions/admin';
|
import { deactivateUsers, deleteUsers, deleteStatus, toggleStatusSensitivity } from 'soapbox/actions/admin';
|
||||||
|
@ -8,6 +8,8 @@ import snackbar from 'soapbox/actions/snackbar';
|
||||||
import AccountContainer from 'soapbox/containers/account_container';
|
import AccountContainer from 'soapbox/containers/account_container';
|
||||||
import { isLocal } from 'soapbox/utils/accounts';
|
import { isLocal } from 'soapbox/utils/accounts';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
deactivateUserHeading: { id: 'confirmations.admin.deactivate_user.heading', defaultMessage: 'Deactivate @{acct}' },
|
deactivateUserHeading: { id: 'confirmations.admin.deactivate_user.heading', defaultMessage: 'Deactivate @{acct}' },
|
||||||
deactivateUserPrompt: { id: 'confirmations.admin.deactivate_user.message', defaultMessage: 'You are about to deactivate @{acct}. Deactivating a user is a reversible action.' },
|
deactivateUserPrompt: { id: 'confirmations.admin.deactivate_user.message', defaultMessage: 'You are about to deactivate @{acct}. Deactivating a user is a reversible action.' },
|
||||||
|
@ -35,11 +37,11 @@ const messages = defineMessages({
|
||||||
statusMarkedNotSensitive: { id: 'admin.statuses.status_marked_message_not_sensitive', defaultMessage: 'Post by @{acct} was marked not sensitive' },
|
statusMarkedNotSensitive: { id: 'admin.statuses.status_marked_message_not_sensitive', defaultMessage: 'Post by @{acct} was marked not sensitive' },
|
||||||
});
|
});
|
||||||
|
|
||||||
export function deactivateUserModal(intl, accountId, afterConfirm = () => {}) {
|
const deactivateUserModal = (intl: IntlShape, accountId: string, afterConfirm = () => {}) =>
|
||||||
return function(dispatch, getState) {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
const acct = state.accounts.get(accountId)!.acct;
|
||||||
const name = state.getIn(['accounts', accountId, 'username']);
|
const name = state.accounts.get(accountId)!.username;
|
||||||
|
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
icon: require('@tabler/icons/icons/user-off.svg'),
|
icon: require('@tabler/icons/icons/user-off.svg'),
|
||||||
|
@ -55,15 +57,15 @@ export function deactivateUserModal(intl, accountId, afterConfirm = () => {}) {
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteUserModal(intl, accountId, afterConfirm = () => {}) {
|
const deleteUserModal = (intl: IntlShape, accountId: string, afterConfirm = () => {}) =>
|
||||||
return function(dispatch, getState) {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
const account = state.accounts.get(accountId)!;
|
||||||
const name = state.getIn(['accounts', accountId, 'username']);
|
const acct = account.acct;
|
||||||
const favicon = state.getIn(['accounts', accountId, 'pleroma', 'favicon']);
|
const name = account.username;
|
||||||
const local = isLocal(state.getIn(['accounts', accountId]));
|
const favicon = account.pleroma.get('favicon');
|
||||||
|
const local = isLocal(account);
|
||||||
|
|
||||||
const message = (<>
|
const message = (<>
|
||||||
<AccountContainer id={accountId} />
|
<AccountContainer id={accountId} />
|
||||||
|
@ -96,13 +98,12 @@ export function deleteUserModal(intl, accountId, afterConfirm = () => {}) {
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function rejectUserModal(intl, accountId, afterConfirm = () => {}) {
|
const rejectUserModal = (intl: IntlShape, accountId: string, afterConfirm = () => {}) =>
|
||||||
return function(dispatch, getState) {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
const acct = state.accounts.get(accountId)!.acct;
|
||||||
const name = state.getIn(['accounts', accountId, 'username']);
|
const name = state.accounts.get(accountId)!.username;
|
||||||
|
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
icon: require('@tabler/icons/icons/user-off.svg'),
|
icon: require('@tabler/icons/icons/user-off.svg'),
|
||||||
|
@ -118,13 +119,12 @@ export function rejectUserModal(intl, accountId, afterConfirm = () => {}) {
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleStatusSensitivityModal(intl, statusId, sensitive, afterConfirm = () => {}) {
|
const toggleStatusSensitivityModal = (intl: IntlShape, statusId: string, sensitive: boolean, afterConfirm = () => {}) =>
|
||||||
return function(dispatch, getState) {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const accountId = state.getIn(['statuses', statusId, 'account']);
|
const accountId = state.statuses.get(statusId)!.account;
|
||||||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
const acct = state.accounts.get(accountId)!.acct;
|
||||||
|
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
icon: require('@tabler/icons/icons/alert-triangle.svg'),
|
icon: require('@tabler/icons/icons/alert-triangle.svg'),
|
||||||
|
@ -140,13 +140,12 @@ export function toggleStatusSensitivityModal(intl, statusId, sensitive, afterCon
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteStatusModal(intl, statusId, afterConfirm = () => {}) {
|
const deleteStatusModal = (intl: IntlShape, statusId: string, afterConfirm = () => {}) =>
|
||||||
return function(dispatch, getState) {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const accountId = state.getIn(['statuses', statusId, 'account']);
|
const accountId = state.statuses.get(statusId)!.account;
|
||||||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
const acct = state.accounts.get(accountId)!.acct;
|
||||||
|
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
icon: require('@tabler/icons/icons/trash.svg'),
|
icon: require('@tabler/icons/icons/trash.svg'),
|
||||||
|
@ -162,4 +161,12 @@ export function deleteStatusModal(intl, statusId, afterConfirm = () => {}) {
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
deactivateUserModal,
|
||||||
|
deleteUserModal,
|
||||||
|
rejectUserModal,
|
||||||
|
toggleStatusSensitivityModal,
|
||||||
|
deleteStatusModal,
|
||||||
|
};
|
|
@ -1,30 +0,0 @@
|
||||||
import { Set as ImmutableSet } from 'immutable';
|
|
||||||
|
|
||||||
import ConfigDB from 'soapbox/utils/config_db';
|
|
||||||
|
|
||||||
import { fetchConfig, updateConfig } from './admin';
|
|
||||||
|
|
||||||
const simplePolicyMerge = (simplePolicy, host, restrictions) => {
|
|
||||||
return simplePolicy.map((hosts, key) => {
|
|
||||||
const isRestricted = restrictions.get(key);
|
|
||||||
|
|
||||||
if (isRestricted) {
|
|
||||||
return ImmutableSet(hosts).add(host);
|
|
||||||
} else {
|
|
||||||
return ImmutableSet(hosts).delete(host);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export function updateMrf(host, restrictions) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
return dispatch(fetchConfig())
|
|
||||||
.then(() => {
|
|
||||||
const configs = getState().getIn(['admin', 'configs']);
|
|
||||||
const simplePolicy = ConfigDB.toSimplePolicy(configs);
|
|
||||||
const merged = simplePolicyMerge(simplePolicy, host, restrictions);
|
|
||||||
const config = ConfigDB.fromSimplePolicy(merged);
|
|
||||||
dispatch(updateConfig(config));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { Map as ImmutableMap, Set as ImmutableSet } from 'immutable';
|
||||||
|
|
||||||
|
import ConfigDB from 'soapbox/utils/config_db';
|
||||||
|
|
||||||
|
import { fetchConfig, updateConfig } from './admin';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { Policy } from 'soapbox/utils/config_db';
|
||||||
|
|
||||||
|
const simplePolicyMerge = (simplePolicy: Policy, host: string, restrictions: ImmutableMap<string, any>) => {
|
||||||
|
return simplePolicy.map((hosts, key) => {
|
||||||
|
const isRestricted = restrictions.get(key);
|
||||||
|
|
||||||
|
if (isRestricted) {
|
||||||
|
return ImmutableSet(hosts).add(host);
|
||||||
|
} else {
|
||||||
|
return ImmutableSet(hosts).delete(host);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateMrf = (host: string, restrictions: ImmutableMap<string, any>) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
|
dispatch(fetchConfig())
|
||||||
|
.then(() => {
|
||||||
|
const configs = getState().admin.get('configs');
|
||||||
|
const simplePolicy = ConfigDB.toSimplePolicy(configs);
|
||||||
|
const merged = simplePolicyMerge(simplePolicy, host, restrictions);
|
||||||
|
const config = ConfigDB.fromSimplePolicy(merged);
|
||||||
|
return dispatch(updateConfig(config.toJS() as Array<Record<string, any>>));
|
||||||
|
});
|
||||||
|
|
||||||
|
export { updateMrf };
|
|
@ -1,116 +0,0 @@
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
import { getNextLinkName } from 'soapbox/utils/quirks';
|
|
||||||
|
|
||||||
import api, { getLinks } from '../api';
|
|
||||||
|
|
||||||
import { fetchRelationships } from './accounts';
|
|
||||||
import { importFetchedAccounts } from './importer';
|
|
||||||
import { openModal } from './modals';
|
|
||||||
|
|
||||||
export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST';
|
|
||||||
export const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS';
|
|
||||||
export const MUTES_FETCH_FAIL = 'MUTES_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const MUTES_EXPAND_REQUEST = 'MUTES_EXPAND_REQUEST';
|
|
||||||
export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS';
|
|
||||||
export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL';
|
|
||||||
|
|
||||||
export const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL';
|
|
||||||
export const MUTES_TOGGLE_HIDE_NOTIFICATIONS = 'MUTES_TOGGLE_HIDE_NOTIFICATIONS';
|
|
||||||
|
|
||||||
export function fetchMutes() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
const nextLinkName = getNextLinkName(getState);
|
|
||||||
|
|
||||||
dispatch(fetchMutesRequest());
|
|
||||||
|
|
||||||
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)));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMutesRequest() {
|
|
||||||
return {
|
|
||||||
type: MUTES_FETCH_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMutesSuccess(accounts, next) {
|
|
||||||
return {
|
|
||||||
type: MUTES_FETCH_SUCCESS,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMutesFail(error) {
|
|
||||||
return {
|
|
||||||
type: MUTES_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandMutes() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
const nextLinkName = getNextLinkName(getState);
|
|
||||||
|
|
||||||
const url = getState().getIn(['user_lists', 'mutes', 'next']);
|
|
||||||
|
|
||||||
if (url === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandMutesRequest());
|
|
||||||
|
|
||||||
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)));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandMutesRequest() {
|
|
||||||
return {
|
|
||||||
type: MUTES_EXPAND_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandMutesSuccess(accounts, next) {
|
|
||||||
return {
|
|
||||||
type: MUTES_EXPAND_SUCCESS,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandMutesFail(error) {
|
|
||||||
return {
|
|
||||||
type: MUTES_EXPAND_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initMuteModal(account) {
|
|
||||||
return dispatch => {
|
|
||||||
dispatch({
|
|
||||||
type: MUTES_INIT_MODAL,
|
|
||||||
account,
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(openModal('MUTE'));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleHideNotifications() {
|
|
||||||
return dispatch => {
|
|
||||||
dispatch({ type: MUTES_TOGGLE_HIDE_NOTIFICATIONS });
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
import { getNextLinkName } from 'soapbox/utils/quirks';
|
||||||
|
|
||||||
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
|
import { fetchRelationships } from './accounts';
|
||||||
|
import { importFetchedAccounts } from './importer';
|
||||||
|
import { openModal } from './modals';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity, Account as AccountEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST';
|
||||||
|
const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS';
|
||||||
|
const MUTES_FETCH_FAIL = 'MUTES_FETCH_FAIL';
|
||||||
|
|
||||||
|
const MUTES_EXPAND_REQUEST = 'MUTES_EXPAND_REQUEST';
|
||||||
|
const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS';
|
||||||
|
const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL';
|
||||||
|
const MUTES_TOGGLE_HIDE_NOTIFICATIONS = 'MUTES_TOGGLE_HIDE_NOTIFICATIONS';
|
||||||
|
|
||||||
|
const fetchMutes = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
const nextLinkName = getNextLinkName(getState);
|
||||||
|
|
||||||
|
dispatch(fetchMutesRequest());
|
||||||
|
|
||||||
|
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: APIEntity) => item.id)));
|
||||||
|
}).catch(error => dispatch(fetchMutesFail(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchMutesRequest = () => ({
|
||||||
|
type: MUTES_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchMutesSuccess = (accounts: APIEntity[], next: string | null) => ({
|
||||||
|
type: MUTES_FETCH_SUCCESS,
|
||||||
|
accounts,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchMutesFail = (error: AxiosError) => ({
|
||||||
|
type: MUTES_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandMutes = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
const nextLinkName = getNextLinkName(getState);
|
||||||
|
|
||||||
|
const url = getState().user_lists.getIn(['mutes', 'next']);
|
||||||
|
|
||||||
|
if (url === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandMutesRequest());
|
||||||
|
|
||||||
|
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: APIEntity) => item.id)));
|
||||||
|
}).catch(error => dispatch(expandMutesFail(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandMutesRequest = () => ({
|
||||||
|
type: MUTES_EXPAND_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandMutesSuccess = (accounts: APIEntity[], next: string | null) => ({
|
||||||
|
type: MUTES_EXPAND_SUCCESS,
|
||||||
|
accounts,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandMutesFail = (error: AxiosError) => ({
|
||||||
|
type: MUTES_EXPAND_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const initMuteModal = (account: AccountEntity) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: MUTES_INIT_MODAL,
|
||||||
|
account,
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(openModal('MUTE'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleHideNotifications = () =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
dispatch({ type: MUTES_TOGGLE_HIDE_NOTIFICATIONS });
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
MUTES_FETCH_REQUEST,
|
||||||
|
MUTES_FETCH_SUCCESS,
|
||||||
|
MUTES_FETCH_FAIL,
|
||||||
|
MUTES_EXPAND_REQUEST,
|
||||||
|
MUTES_EXPAND_SUCCESS,
|
||||||
|
MUTES_EXPAND_FAIL,
|
||||||
|
MUTES_INIT_MODAL,
|
||||||
|
MUTES_TOGGLE_HIDE_NOTIFICATIONS,
|
||||||
|
fetchMutes,
|
||||||
|
fetchMutesRequest,
|
||||||
|
fetchMutesSuccess,
|
||||||
|
fetchMutesFail,
|
||||||
|
expandMutes,
|
||||||
|
expandMutesRequest,
|
||||||
|
expandMutesSuccess,
|
||||||
|
expandMutesFail,
|
||||||
|
initMuteModal,
|
||||||
|
toggleHideNotifications,
|
||||||
|
};
|
|
@ -1,20 +1,18 @@
|
||||||
import {
|
import {
|
||||||
List as ImmutableList,
|
List as ImmutableList,
|
||||||
Map as ImmutableMap,
|
Map as ImmutableMap,
|
||||||
OrderedMap as ImmutableOrderedMap,
|
|
||||||
} from 'immutable';
|
} from 'immutable';
|
||||||
import IntlMessageFormat from 'intl-messageformat';
|
import IntlMessageFormat from 'intl-messageformat';
|
||||||
import 'intl-pluralrules';
|
import 'intl-pluralrules';
|
||||||
import { defineMessages } from 'react-intl';
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
|
import api, { getLinks } from 'soapbox/api';
|
||||||
|
import { getFilters, regexFromFilters } from 'soapbox/selectors';
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
import { parseVersion, PLEROMA } from 'soapbox/utils/features';
|
import { parseVersion, PLEROMA } from 'soapbox/utils/features';
|
||||||
|
import { unescapeHTML } from 'soapbox/utils/html';
|
||||||
import { joinPublicPath } from 'soapbox/utils/static';
|
import { joinPublicPath } from 'soapbox/utils/static';
|
||||||
|
|
||||||
import api, { getLinks } from '../api';
|
|
||||||
import { getFilters, regexFromFilters } from '../selectors';
|
|
||||||
import { unescapeHTML } from '../utils/html';
|
|
||||||
|
|
||||||
import { fetchRelationships } from './accounts';
|
import { fetchRelationships } from './accounts';
|
||||||
import {
|
import {
|
||||||
importFetchedAccount,
|
importFetchedAccount,
|
||||||
|
@ -25,32 +23,36 @@ import {
|
||||||
import { saveMarker } from './markers';
|
import { saveMarker } from './markers';
|
||||||
import { getSettings, saveSettings } from './settings';
|
import { getSettings, saveSettings } from './settings';
|
||||||
|
|
||||||
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
|
import type { AxiosError } from 'axios';
|
||||||
export const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP';
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
export const NOTIFICATIONS_UPDATE_QUEUE = 'NOTIFICATIONS_UPDATE_QUEUE';
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
export const NOTIFICATIONS_DEQUEUE = 'NOTIFICATIONS_DEQUEUE';
|
|
||||||
|
|
||||||
export const NOTIFICATIONS_EXPAND_REQUEST = 'NOTIFICATIONS_EXPAND_REQUEST';
|
const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
|
||||||
export const NOTIFICATIONS_EXPAND_SUCCESS = 'NOTIFICATIONS_EXPAND_SUCCESS';
|
const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP';
|
||||||
export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL';
|
const NOTIFICATIONS_UPDATE_QUEUE = 'NOTIFICATIONS_UPDATE_QUEUE';
|
||||||
|
const NOTIFICATIONS_DEQUEUE = 'NOTIFICATIONS_DEQUEUE';
|
||||||
|
|
||||||
export const NOTIFICATIONS_FILTER_SET = 'NOTIFICATIONS_FILTER_SET';
|
const NOTIFICATIONS_EXPAND_REQUEST = 'NOTIFICATIONS_EXPAND_REQUEST';
|
||||||
|
const NOTIFICATIONS_EXPAND_SUCCESS = 'NOTIFICATIONS_EXPAND_SUCCESS';
|
||||||
|
const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL';
|
||||||
|
|
||||||
export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR';
|
const NOTIFICATIONS_FILTER_SET = 'NOTIFICATIONS_FILTER_SET';
|
||||||
export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP';
|
|
||||||
|
|
||||||
export const NOTIFICATIONS_MARK_READ_REQUEST = 'NOTIFICATIONS_MARK_READ_REQUEST';
|
const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR';
|
||||||
export const NOTIFICATIONS_MARK_READ_SUCCESS = 'NOTIFICATIONS_MARK_READ_SUCCESS';
|
const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP';
|
||||||
export const NOTIFICATIONS_MARK_READ_FAIL = 'NOTIFICATIONS_MARK_READ_FAIL';
|
|
||||||
|
|
||||||
export const MAX_QUEUED_NOTIFICATIONS = 40;
|
const NOTIFICATIONS_MARK_READ_REQUEST = 'NOTIFICATIONS_MARK_READ_REQUEST';
|
||||||
|
const NOTIFICATIONS_MARK_READ_SUCCESS = 'NOTIFICATIONS_MARK_READ_SUCCESS';
|
||||||
|
const NOTIFICATIONS_MARK_READ_FAIL = 'NOTIFICATIONS_MARK_READ_FAIL';
|
||||||
|
|
||||||
|
const MAX_QUEUED_NOTIFICATIONS = 40;
|
||||||
|
|
||||||
defineMessages({
|
defineMessages({
|
||||||
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
|
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
|
||||||
group: { id: 'notifications.group', defaultMessage: '{count} notifications' },
|
group: { id: 'notifications.group', defaultMessage: '{count} notifications' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchRelatedRelationships = (dispatch, notifications) => {
|
const fetchRelatedRelationships = (dispatch: AppDispatch, notifications: APIEntity[]) => {
|
||||||
const accountIds = notifications.filter(item => item.type === 'follow').map(item => item.account.id);
|
const accountIds = notifications.filter(item => item.type === 'follow').map(item => item.account.id);
|
||||||
|
|
||||||
if (accountIds.length > 0) {
|
if (accountIds.length > 0) {
|
||||||
|
@ -58,8 +60,8 @@ const fetchRelatedRelationships = (dispatch, notifications) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function updateNotifications(notification, intlMessages, intlLocale) {
|
const updateNotifications = (notification: APIEntity) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const showInColumn = getSettings(getState()).getIn(['notifications', 'shows', notification.type], true);
|
const showInColumn = getSettings(getState()).getIn(['notifications', 'shows', notification.type], true);
|
||||||
|
|
||||||
if (notification.account) {
|
if (notification.account) {
|
||||||
|
@ -84,17 +86,16 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
|
||||||
fetchRelatedRelationships(dispatch, [notification]);
|
fetchRelatedRelationships(dispatch, [notification]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function updateNotificationsQueue(notification, intlMessages, intlLocale, curPath) {
|
const updateNotificationsQueue = (notification: APIEntity, intlMessages: Record<string, string>, intlLocale: string, curPath: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
if (notification.type === 'pleroma:chat_mention') return; // Drop chat notifications, handle them per-chat
|
if (notification.type === 'pleroma:chat_mention') return; // Drop chat notifications, handle them per-chat
|
||||||
|
|
||||||
const showAlert = getSettings(getState()).getIn(['notifications', 'alerts', notification.type]);
|
const showAlert = getSettings(getState()).getIn(['notifications', 'alerts', notification.type]);
|
||||||
const filters = getFilters(getState(), { contextType: 'notifications' });
|
const filters = getFilters(getState(), { contextType: 'notifications' });
|
||||||
const playSound = getSettings(getState()).getIn(['notifications', 'sounds', notification.type]);
|
const playSound = getSettings(getState()).getIn(['notifications', 'sounds', notification.type]);
|
||||||
|
|
||||||
let filtered = false;
|
let filtered: boolean | null = false;
|
||||||
|
|
||||||
const isOnNotificationsPage = curPath === '/notifications';
|
const isOnNotificationsPage = curPath === '/notifications';
|
||||||
|
|
||||||
|
@ -140,21 +141,20 @@ export function updateNotificationsQueue(notification, intlMessages, intlLocale,
|
||||||
intlLocale,
|
intlLocale,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
dispatch(updateNotifications(notification, intlMessages, intlLocale));
|
dispatch(updateNotifications(notification));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function dequeueNotifications() {
|
const dequeueNotifications = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const queuedNotifications = getState().getIn(['notifications', 'queuedNotifications'], ImmutableOrderedMap());
|
const queuedNotifications = getState().notifications.get('queuedNotifications');
|
||||||
const totalQueuedNotificationsCount = getState().getIn(['notifications', 'totalQueuedNotificationsCount'], 0);
|
const totalQueuedNotificationsCount = getState().notifications.get('totalQueuedNotificationsCount');
|
||||||
|
|
||||||
if (totalQueuedNotificationsCount === 0) {
|
if (totalQueuedNotificationsCount === 0) {
|
||||||
return;
|
return;
|
||||||
} else if (totalQueuedNotificationsCount > 0 && totalQueuedNotificationsCount <= MAX_QUEUED_NOTIFICATIONS) {
|
} else if (totalQueuedNotificationsCount > 0 && totalQueuedNotificationsCount <= MAX_QUEUED_NOTIFICATIONS) {
|
||||||
queuedNotifications.forEach(block => {
|
queuedNotifications.forEach((block: APIEntity) => {
|
||||||
dispatch(updateNotifications(block.notification, block.intlMessages, block.intlLocale));
|
dispatch(updateNotifications(block.notification));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
dispatch(expandNotifications());
|
dispatch(expandNotifications());
|
||||||
|
@ -165,23 +165,22 @@ export function dequeueNotifications() {
|
||||||
});
|
});
|
||||||
dispatch(markReadNotifications());
|
dispatch(markReadNotifications());
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const excludeTypesFromSettings = getState => getSettings(getState()).getIn(['notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS();
|
const excludeTypesFromSettings = (getState: () => RootState) => (getSettings(getState()).getIn(['notifications', 'shows']) as ImmutableMap<string, boolean>).filter(enabled => !enabled).keySeq().toJS();
|
||||||
|
|
||||||
const excludeTypesFromFilter = filter => {
|
const excludeTypesFromFilter = (filter: string) => {
|
||||||
const allTypes = ImmutableList(['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'status', 'poll', 'move', 'pleroma:emoji_reaction']);
|
const allTypes = ImmutableList(['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'status', 'poll', 'move', 'pleroma:emoji_reaction']);
|
||||||
return allTypes.filterNot(item => item === filter).toJS();
|
return allTypes.filterNot(item => item === filter).toJS();
|
||||||
};
|
};
|
||||||
|
|
||||||
const noOp = () => {};
|
const noOp = () => {};
|
||||||
|
|
||||||
export function expandNotifications({ maxId } = {}, done = noOp) {
|
const expandNotifications = ({ maxId }: Record<string, any> = {}, done = noOp) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
if (!isLoggedIn(getState)) return dispatch(noOp);
|
if (!isLoggedIn(getState)) return dispatch(noOp);
|
||||||
|
|
||||||
const activeFilter = getSettings(getState()).getIn(['notifications', 'quickFilter', 'active']);
|
const activeFilter = getSettings(getState()).getIn(['notifications', 'quickFilter', 'active']) as string;
|
||||||
const notifications = getState().get('notifications');
|
const notifications = getState().notifications;
|
||||||
const isLoadingMore = !!maxId;
|
const isLoadingMore = !!maxId;
|
||||||
|
|
||||||
if (notifications.get('isLoading')) {
|
if (notifications.get('isLoading')) {
|
||||||
|
@ -189,7 +188,7 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
|
||||||
return dispatch(noOp);
|
return dispatch(noOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = {
|
const params: Record<string, any> = {
|
||||||
max_id: maxId,
|
max_id: maxId,
|
||||||
exclude_types: activeFilter === 'all'
|
exclude_types: activeFilter === 'all'
|
||||||
? excludeTypesFromSettings(getState)
|
? excludeTypesFromSettings(getState)
|
||||||
|
@ -205,7 +204,7 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
|
||||||
return api(getState).get('/api/v1/notifications', { params }).then(response => {
|
return api(getState).get('/api/v1/notifications', { params }).then(response => {
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
|
||||||
const entries = response.data.reduce((acc, item) => {
|
const entries = (response.data as APIEntity[]).reduce((acc, item) => {
|
||||||
if (item.account?.id) {
|
if (item.account?.id) {
|
||||||
acc.accounts[item.account.id] = item.account;
|
acc.accounts[item.account.id] = item.account;
|
||||||
}
|
}
|
||||||
|
@ -233,34 +232,27 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function expandNotificationsRequest(isLoadingMore) {
|
const expandNotificationsRequest = (isLoadingMore: boolean) => ({
|
||||||
return {
|
|
||||||
type: NOTIFICATIONS_EXPAND_REQUEST,
|
type: NOTIFICATIONS_EXPAND_REQUEST,
|
||||||
skipLoading: !isLoadingMore,
|
skipLoading: !isLoadingMore,
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
export function expandNotificationsSuccess(notifications, next, isLoadingMore) {
|
const expandNotificationsSuccess = (notifications: APIEntity[], next: string | null, isLoadingMore: boolean) => ({
|
||||||
return {
|
|
||||||
type: NOTIFICATIONS_EXPAND_SUCCESS,
|
type: NOTIFICATIONS_EXPAND_SUCCESS,
|
||||||
notifications,
|
notifications,
|
||||||
next,
|
next,
|
||||||
skipLoading: !isLoadingMore,
|
skipLoading: !isLoadingMore,
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
export function expandNotificationsFail(error, isLoadingMore) {
|
const expandNotificationsFail = (error: AxiosError, isLoadingMore: boolean) => ({
|
||||||
return {
|
|
||||||
type: NOTIFICATIONS_EXPAND_FAIL,
|
type: NOTIFICATIONS_EXPAND_FAIL,
|
||||||
error,
|
error,
|
||||||
skipLoading: !isLoadingMore,
|
skipLoading: !isLoadingMore,
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
export function clearNotifications() {
|
const clearNotifications = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
if (!isLoggedIn(getState)) return;
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
|
@ -269,20 +261,18 @@ export function clearNotifications() {
|
||||||
|
|
||||||
api(getState).post('/api/v1/notifications/clear');
|
api(getState).post('/api/v1/notifications/clear');
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function scrollTopNotifications(top) {
|
const scrollTopNotifications = (top: boolean) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: NOTIFICATIONS_SCROLL_TOP,
|
type: NOTIFICATIONS_SCROLL_TOP,
|
||||||
top,
|
top,
|
||||||
});
|
});
|
||||||
dispatch(markReadNotifications());
|
dispatch(markReadNotifications());
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function setFilter(filterType) {
|
const setFilter = (filterType: string) =>
|
||||||
return dispatch => {
|
(dispatch: AppDispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: NOTIFICATIONS_FILTER_SET,
|
type: NOTIFICATIONS_FILTER_SET,
|
||||||
path: ['notifications', 'quickFilter', 'active'],
|
path: ['notifications', 'quickFilter', 'active'],
|
||||||
|
@ -291,25 +281,23 @@ export function setFilter(filterType) {
|
||||||
dispatch(expandNotifications());
|
dispatch(expandNotifications());
|
||||||
dispatch(saveSettings());
|
dispatch(saveSettings());
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// Of course Markers don't work properly in Pleroma.
|
// Of course Markers don't work properly in Pleroma.
|
||||||
// https://git.pleroma.social/pleroma/pleroma/-/issues/2769
|
// https://git.pleroma.social/pleroma/pleroma/-/issues/2769
|
||||||
export function markReadPleroma(max_id) {
|
const markReadPleroma = (max_id: string | number) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
return api(getState).post('/api/v1/pleroma/notifications/read', { max_id });
|
return api(getState).post('/api/v1/pleroma/notifications/read', { max_id });
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function markReadNotifications() {
|
const markReadNotifications = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
if (!isLoggedIn(getState)) return;
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const instance = state.get('instance');
|
const instance = state.instance;
|
||||||
const topNotificationId = state.getIn(['notifications', 'items'], ImmutableOrderedMap()).first(ImmutableMap()).get('id');
|
const topNotificationId = state.notifications.get('items').first(ImmutableMap()).get('id');
|
||||||
const lastReadId = state.getIn(['notifications', 'lastRead']);
|
const lastReadId = state.notifications.get('lastRead');
|
||||||
const v = parseVersion(instance.get('version'));
|
const v = parseVersion(instance.version);
|
||||||
|
|
||||||
if (!(topNotificationId && topNotificationId > lastReadId)) return;
|
if (!(topNotificationId && topNotificationId > lastReadId)) return;
|
||||||
|
|
||||||
|
@ -325,4 +313,32 @@ export function markReadNotifications() {
|
||||||
dispatch(markReadPleroma(topNotificationId));
|
dispatch(markReadPleroma(topNotificationId));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
export {
|
||||||
|
NOTIFICATIONS_UPDATE,
|
||||||
|
NOTIFICATIONS_UPDATE_NOOP,
|
||||||
|
NOTIFICATIONS_UPDATE_QUEUE,
|
||||||
|
NOTIFICATIONS_DEQUEUE,
|
||||||
|
NOTIFICATIONS_EXPAND_REQUEST,
|
||||||
|
NOTIFICATIONS_EXPAND_SUCCESS,
|
||||||
|
NOTIFICATIONS_EXPAND_FAIL,
|
||||||
|
NOTIFICATIONS_FILTER_SET,
|
||||||
|
NOTIFICATIONS_CLEAR,
|
||||||
|
NOTIFICATIONS_SCROLL_TOP,
|
||||||
|
NOTIFICATIONS_MARK_READ_REQUEST,
|
||||||
|
NOTIFICATIONS_MARK_READ_SUCCESS,
|
||||||
|
NOTIFICATIONS_MARK_READ_FAIL,
|
||||||
|
MAX_QUEUED_NOTIFICATIONS,
|
||||||
|
updateNotifications,
|
||||||
|
updateNotificationsQueue,
|
||||||
|
dequeueNotifications,
|
||||||
|
expandNotifications,
|
||||||
|
expandNotificationsRequest,
|
||||||
|
expandNotificationsSuccess,
|
||||||
|
expandNotificationsFail,
|
||||||
|
clearNotifications,
|
||||||
|
scrollTopNotifications,
|
||||||
|
setFilter,
|
||||||
|
markReadPleroma,
|
||||||
|
markReadNotifications,
|
||||||
|
};
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
import { baseClient } from '../api';
|
import { baseClient } from '../api';
|
||||||
|
|
||||||
|
import type { AppDispatch } from 'soapbox/store';
|
||||||
|
|
||||||
export const OAUTH_TOKEN_CREATE_REQUEST = 'OAUTH_TOKEN_CREATE_REQUEST';
|
export const OAUTH_TOKEN_CREATE_REQUEST = 'OAUTH_TOKEN_CREATE_REQUEST';
|
||||||
export const OAUTH_TOKEN_CREATE_SUCCESS = 'OAUTH_TOKEN_CREATE_SUCCESS';
|
export const OAUTH_TOKEN_CREATE_SUCCESS = 'OAUTH_TOKEN_CREATE_SUCCESS';
|
||||||
export const OAUTH_TOKEN_CREATE_FAIL = 'OAUTH_TOKEN_CREATE_FAIL';
|
export const OAUTH_TOKEN_CREATE_FAIL = 'OAUTH_TOKEN_CREATE_FAIL';
|
||||||
|
@ -16,8 +18,8 @@ export const OAUTH_TOKEN_REVOKE_REQUEST = 'OAUTH_TOKEN_REVOKE_REQUEST';
|
||||||
export const OAUTH_TOKEN_REVOKE_SUCCESS = 'OAUTH_TOKEN_REVOKE_SUCCESS';
|
export const OAUTH_TOKEN_REVOKE_SUCCESS = 'OAUTH_TOKEN_REVOKE_SUCCESS';
|
||||||
export const OAUTH_TOKEN_REVOKE_FAIL = 'OAUTH_TOKEN_REVOKE_FAIL';
|
export const OAUTH_TOKEN_REVOKE_FAIL = 'OAUTH_TOKEN_REVOKE_FAIL';
|
||||||
|
|
||||||
export function obtainOAuthToken(params, baseURL) {
|
export const obtainOAuthToken = (params: Record<string, string>, baseURL?: string) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => {
|
||||||
dispatch({ type: OAUTH_TOKEN_CREATE_REQUEST, params });
|
dispatch({ type: OAUTH_TOKEN_CREATE_REQUEST, params });
|
||||||
return baseClient(null, baseURL).post('/oauth/token', params).then(({ data: token }) => {
|
return baseClient(null, baseURL).post('/oauth/token', params).then(({ data: token }) => {
|
||||||
dispatch({ type: OAUTH_TOKEN_CREATE_SUCCESS, params, token });
|
dispatch({ type: OAUTH_TOKEN_CREATE_SUCCESS, params, token });
|
||||||
|
@ -27,10 +29,9 @@ export function obtainOAuthToken(params, baseURL) {
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function revokeOAuthToken(params) {
|
export const revokeOAuthToken = (params: Record<string, string>) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch) => {
|
||||||
dispatch({ type: OAUTH_TOKEN_REVOKE_REQUEST, params });
|
dispatch({ type: OAUTH_TOKEN_REVOKE_REQUEST, params });
|
||||||
return baseClient().post('/oauth/revoke', params).then(({ data }) => {
|
return baseClient().post('/oauth/revoke', params).then(({ data }) => {
|
||||||
dispatch({ type: OAUTH_TOKEN_REVOKE_SUCCESS, params, data });
|
dispatch({ type: OAUTH_TOKEN_REVOKE_SUCCESS, params, data });
|
||||||
|
@ -40,4 +41,3 @@ export function revokeOAuthToken(params) {
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
export const PATRON_INSTANCE_FETCH_REQUEST = 'PATRON_INSTANCE_FETCH_REQUEST';
|
|
||||||
export const PATRON_INSTANCE_FETCH_SUCCESS = 'PATRON_INSTANCE_FETCH_SUCCESS';
|
|
||||||
export const PATRON_INSTANCE_FETCH_FAIL = 'PATRON_INSTANCE_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const PATRON_ACCOUNT_FETCH_REQUEST = 'PATRON_ACCOUNT_FETCH_REQUEST';
|
|
||||||
export const PATRON_ACCOUNT_FETCH_SUCCESS = 'PATRON_ACCOUNT_FETCH_SUCCESS';
|
|
||||||
export const PATRON_ACCOUNT_FETCH_FAIL = 'PATRON_ACCOUNT_FETCH_FAIL';
|
|
||||||
|
|
||||||
export function fetchPatronInstance() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: PATRON_INSTANCE_FETCH_REQUEST });
|
|
||||||
api(getState).get('/api/patron/v1/instance').then(response => {
|
|
||||||
dispatch(importFetchedInstance(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchInstanceFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchPatronAccount(apId) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
apId = encodeURIComponent(apId);
|
|
||||||
dispatch({ type: PATRON_ACCOUNT_FETCH_REQUEST });
|
|
||||||
api(getState).get(`/api/patron/v1/accounts/${apId}`).then(response => {
|
|
||||||
dispatch(importFetchedAccount(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchAccountFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function importFetchedInstance(instance) {
|
|
||||||
return {
|
|
||||||
type: PATRON_INSTANCE_FETCH_SUCCESS,
|
|
||||||
instance,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetchInstanceFail(error) {
|
|
||||||
return {
|
|
||||||
type: PATRON_INSTANCE_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
skipAlert: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function importFetchedAccount(account) {
|
|
||||||
return {
|
|
||||||
type: PATRON_ACCOUNT_FETCH_SUCCESS,
|
|
||||||
account,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetchAccountFail(error) {
|
|
||||||
return {
|
|
||||||
type: PATRON_ACCOUNT_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
skipAlert: true,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const PATRON_INSTANCE_FETCH_REQUEST = 'PATRON_INSTANCE_FETCH_REQUEST';
|
||||||
|
const PATRON_INSTANCE_FETCH_SUCCESS = 'PATRON_INSTANCE_FETCH_SUCCESS';
|
||||||
|
const PATRON_INSTANCE_FETCH_FAIL = 'PATRON_INSTANCE_FETCH_FAIL';
|
||||||
|
|
||||||
|
const PATRON_ACCOUNT_FETCH_REQUEST = 'PATRON_ACCOUNT_FETCH_REQUEST';
|
||||||
|
const PATRON_ACCOUNT_FETCH_SUCCESS = 'PATRON_ACCOUNT_FETCH_SUCCESS';
|
||||||
|
const PATRON_ACCOUNT_FETCH_FAIL = 'PATRON_ACCOUNT_FETCH_FAIL';
|
||||||
|
|
||||||
|
const fetchPatronInstance = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: PATRON_INSTANCE_FETCH_REQUEST });
|
||||||
|
return api(getState).get('/api/patron/v1/instance').then(response => {
|
||||||
|
dispatch(importFetchedInstance(response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchInstanceFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPatronAccount = (apId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
apId = encodeURIComponent(apId);
|
||||||
|
dispatch({ type: PATRON_ACCOUNT_FETCH_REQUEST });
|
||||||
|
api(getState).get(`/api/patron/v1/accounts/${apId}`).then(response => {
|
||||||
|
dispatch(importFetchedAccount(response.data));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchAccountFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const importFetchedInstance = (instance: APIEntity) => ({
|
||||||
|
type: PATRON_INSTANCE_FETCH_SUCCESS,
|
||||||
|
instance,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchInstanceFail = (error: AxiosError) => ({
|
||||||
|
type: PATRON_INSTANCE_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
skipAlert: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const importFetchedAccount = (account: APIEntity) => ({
|
||||||
|
type: PATRON_ACCOUNT_FETCH_SUCCESS,
|
||||||
|
account,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchAccountFail = (error: AxiosError) => ({
|
||||||
|
type: PATRON_ACCOUNT_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
skipAlert: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
PATRON_INSTANCE_FETCH_REQUEST,
|
||||||
|
PATRON_INSTANCE_FETCH_SUCCESS,
|
||||||
|
PATRON_INSTANCE_FETCH_FAIL,
|
||||||
|
PATRON_ACCOUNT_FETCH_REQUEST,
|
||||||
|
PATRON_ACCOUNT_FETCH_SUCCESS,
|
||||||
|
PATRON_ACCOUNT_FETCH_FAIL,
|
||||||
|
fetchPatronInstance,
|
||||||
|
fetchPatronAccount,
|
||||||
|
importFetchedInstance,
|
||||||
|
fetchInstanceFail,
|
||||||
|
importFetchedAccount,
|
||||||
|
fetchAccountFail,
|
||||||
|
};
|
|
@ -1,46 +0,0 @@
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
import { importFetchedStatuses } from './importer';
|
|
||||||
|
|
||||||
export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST';
|
|
||||||
export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS';
|
|
||||||
export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL';
|
|
||||||
|
|
||||||
export function fetchPinnedStatuses() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
const me = getState().get('me');
|
|
||||||
|
|
||||||
dispatch(fetchPinnedStatusesRequest());
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/accounts/${me}/statuses`, { params: { pinned: true } }).then(response => {
|
|
||||||
dispatch(importFetchedStatuses(response.data));
|
|
||||||
dispatch(fetchPinnedStatusesSuccess(response.data, null));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchPinnedStatusesFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchPinnedStatusesRequest() {
|
|
||||||
return {
|
|
||||||
type: PINNED_STATUSES_FETCH_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchPinnedStatusesSuccess(statuses, next) {
|
|
||||||
return {
|
|
||||||
type: PINNED_STATUSES_FETCH_SUCCESS,
|
|
||||||
statuses,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchPinnedStatusesFail(error) {
|
|
||||||
return {
|
|
||||||
type: PINNED_STATUSES_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||||
|
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import { importFetchedStatuses } from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST';
|
||||||
|
const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS';
|
||||||
|
const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL';
|
||||||
|
|
||||||
|
const fetchPinnedStatuses = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (!isLoggedIn(getState)) return;
|
||||||
|
const me = getState().me;
|
||||||
|
|
||||||
|
dispatch(fetchPinnedStatusesRequest());
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/accounts/${me}/statuses`, { params: { pinned: true } }).then(response => {
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch(fetchPinnedStatusesSuccess(response.data, null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchPinnedStatusesFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPinnedStatusesRequest = () => ({
|
||||||
|
type: PINNED_STATUSES_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchPinnedStatusesSuccess = (statuses: APIEntity[], next: string | null) => ({
|
||||||
|
type: PINNED_STATUSES_FETCH_SUCCESS,
|
||||||
|
statuses,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchPinnedStatusesFail = (error: AxiosError) => ({
|
||||||
|
type: PINNED_STATUSES_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
PINNED_STATUSES_FETCH_REQUEST,
|
||||||
|
PINNED_STATUSES_FETCH_SUCCESS,
|
||||||
|
PINNED_STATUSES_FETCH_FAIL,
|
||||||
|
fetchPinnedStatuses,
|
||||||
|
fetchPinnedStatusesRequest,
|
||||||
|
fetchPinnedStatusesSuccess,
|
||||||
|
fetchPinnedStatusesFail,
|
||||||
|
};
|
|
@ -1,61 +0,0 @@
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
import { importFetchedPoll } from './importer';
|
|
||||||
|
|
||||||
export const POLL_VOTE_REQUEST = 'POLL_VOTE_REQUEST';
|
|
||||||
export const POLL_VOTE_SUCCESS = 'POLL_VOTE_SUCCESS';
|
|
||||||
export const POLL_VOTE_FAIL = 'POLL_VOTE_FAIL';
|
|
||||||
|
|
||||||
export const POLL_FETCH_REQUEST = 'POLL_FETCH_REQUEST';
|
|
||||||
export const POLL_FETCH_SUCCESS = 'POLL_FETCH_SUCCESS';
|
|
||||||
export const POLL_FETCH_FAIL = 'POLL_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const vote = (pollId, choices) => (dispatch, getState) => {
|
|
||||||
dispatch(voteRequest());
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/polls/${pollId}/votes`, { choices })
|
|
||||||
.then(({ data }) => {
|
|
||||||
dispatch(importFetchedPoll(data));
|
|
||||||
dispatch(voteSuccess(data));
|
|
||||||
})
|
|
||||||
.catch(err => dispatch(voteFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchPoll = pollId => (dispatch, getState) => {
|
|
||||||
dispatch(fetchPollRequest());
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/polls/${pollId}`)
|
|
||||||
.then(({ data }) => {
|
|
||||||
dispatch(importFetchedPoll(data));
|
|
||||||
dispatch(fetchPollSuccess(data));
|
|
||||||
})
|
|
||||||
.catch(err => dispatch(fetchPollFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const voteRequest = () => ({
|
|
||||||
type: POLL_VOTE_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const voteSuccess = poll => ({
|
|
||||||
type: POLL_VOTE_SUCCESS,
|
|
||||||
poll,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const voteFail = error => ({
|
|
||||||
type: POLL_VOTE_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchPollRequest = () => ({
|
|
||||||
type: POLL_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchPollSuccess = poll => ({
|
|
||||||
type: POLL_FETCH_SUCCESS,
|
|
||||||
poll,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchPollFail = error => ({
|
|
||||||
type: POLL_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import { importFetchedPoll } from './importer';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const POLL_VOTE_REQUEST = 'POLL_VOTE_REQUEST';
|
||||||
|
const POLL_VOTE_SUCCESS = 'POLL_VOTE_SUCCESS';
|
||||||
|
const POLL_VOTE_FAIL = 'POLL_VOTE_FAIL';
|
||||||
|
|
||||||
|
const POLL_FETCH_REQUEST = 'POLL_FETCH_REQUEST';
|
||||||
|
const POLL_FETCH_SUCCESS = 'POLL_FETCH_SUCCESS';
|
||||||
|
const POLL_FETCH_FAIL = 'POLL_FETCH_FAIL';
|
||||||
|
|
||||||
|
const vote = (pollId: string, choices: string[]) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(voteRequest());
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/polls/${pollId}/votes`, { choices })
|
||||||
|
.then(({ data }) => {
|
||||||
|
dispatch(importFetchedPoll(data));
|
||||||
|
dispatch(voteSuccess(data));
|
||||||
|
})
|
||||||
|
.catch(err => dispatch(voteFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPoll = (pollId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(fetchPollRequest());
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/polls/${pollId}`)
|
||||||
|
.then(({ data }) => {
|
||||||
|
dispatch(importFetchedPoll(data));
|
||||||
|
dispatch(fetchPollSuccess(data));
|
||||||
|
})
|
||||||
|
.catch(err => dispatch(fetchPollFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const voteRequest = () => ({
|
||||||
|
type: POLL_VOTE_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const voteSuccess = (poll: APIEntity) => ({
|
||||||
|
type: POLL_VOTE_SUCCESS,
|
||||||
|
poll,
|
||||||
|
});
|
||||||
|
|
||||||
|
const voteFail = (error: AxiosError) => ({
|
||||||
|
type: POLL_VOTE_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchPollRequest = () => ({
|
||||||
|
type: POLL_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchPollSuccess = (poll: APIEntity) => ({
|
||||||
|
type: POLL_FETCH_SUCCESS,
|
||||||
|
poll,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchPollFail = (error: AxiosError) => ({
|
||||||
|
type: POLL_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
POLL_VOTE_REQUEST,
|
||||||
|
POLL_VOTE_SUCCESS,
|
||||||
|
POLL_VOTE_FAIL,
|
||||||
|
POLL_FETCH_REQUEST,
|
||||||
|
POLL_FETCH_SUCCESS,
|
||||||
|
POLL_FETCH_FAIL,
|
||||||
|
vote,
|
||||||
|
fetchPoll,
|
||||||
|
voteRequest,
|
||||||
|
voteSuccess,
|
||||||
|
voteFail,
|
||||||
|
fetchPollRequest,
|
||||||
|
fetchPollSuccess,
|
||||||
|
fetchPollFail,
|
||||||
|
};
|
|
@ -1,64 +0,0 @@
|
||||||
import { mapValues } from 'lodash';
|
|
||||||
|
|
||||||
import { verifyCredentials } from './auth';
|
|
||||||
import { importFetchedAccounts } from './importer';
|
|
||||||
|
|
||||||
export const PLEROMA_PRELOAD_IMPORT = 'PLEROMA_PRELOAD_IMPORT';
|
|
||||||
export const MASTODON_PRELOAD_IMPORT = 'MASTODON_PRELOAD_IMPORT';
|
|
||||||
|
|
||||||
// https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1176/diffs
|
|
||||||
const decodeUTF8Base64 = data => {
|
|
||||||
const rawData = atob(data);
|
|
||||||
const array = Uint8Array.from(rawData.split('').map((char) => char.charCodeAt(0)));
|
|
||||||
const text = new TextDecoder().decode(array);
|
|
||||||
return text;
|
|
||||||
};
|
|
||||||
|
|
||||||
const decodePleromaData = data => {
|
|
||||||
return mapValues(data, base64string => JSON.parse(decodeUTF8Base64(base64string)));
|
|
||||||
};
|
|
||||||
|
|
||||||
const pleromaDecoder = json => decodePleromaData(JSON.parse(json));
|
|
||||||
|
|
||||||
// This will throw if it fails.
|
|
||||||
// Should be called inside a try-catch.
|
|
||||||
const decodeFromMarkup = (elementId, decoder) => {
|
|
||||||
const { textContent } = document.getElementById(elementId);
|
|
||||||
return decoder(textContent);
|
|
||||||
};
|
|
||||||
|
|
||||||
function preloadFromMarkup(elementId, decoder, action) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
try {
|
|
||||||
const data = decodeFromMarkup(elementId, decoder);
|
|
||||||
dispatch(action(data));
|
|
||||||
} catch {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function preload() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch(preloadFromMarkup('initial-results', pleromaDecoder, preloadPleroma));
|
|
||||||
dispatch(preloadFromMarkup('initial-state', JSON.parse, preloadMastodon));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function preloadPleroma(data) {
|
|
||||||
return {
|
|
||||||
type: PLEROMA_PRELOAD_IMPORT,
|
|
||||||
data,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function preloadMastodon(data) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const { me, access_token } = data.meta;
|
|
||||||
const { url } = data.accounts[me];
|
|
||||||
|
|
||||||
dispatch(importFetchedAccounts(Object.values(data.accounts)));
|
|
||||||
dispatch(verifyCredentials(access_token, url));
|
|
||||||
dispatch({ type: MASTODON_PRELOAD_IMPORT, data });
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
import mapValues from 'lodash/mapValues';
|
||||||
|
|
||||||
|
import { verifyCredentials } from './auth';
|
||||||
|
import { importFetchedAccounts } from './importer';
|
||||||
|
|
||||||
|
import type { AppDispatch } from 'soapbox/store';
|
||||||
|
|
||||||
|
const PLEROMA_PRELOAD_IMPORT = 'PLEROMA_PRELOAD_IMPORT';
|
||||||
|
const MASTODON_PRELOAD_IMPORT = 'MASTODON_PRELOAD_IMPORT';
|
||||||
|
|
||||||
|
// https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1176/diffs
|
||||||
|
const decodeUTF8Base64 = (data: string) => {
|
||||||
|
const rawData = atob(data);
|
||||||
|
const array = Uint8Array.from(rawData.split('').map((char) => char.charCodeAt(0)));
|
||||||
|
const text = new TextDecoder().decode(array);
|
||||||
|
return text;
|
||||||
|
};
|
||||||
|
|
||||||
|
const decodePleromaData = (data: Record<string, any>) => {
|
||||||
|
return mapValues(data, base64string => JSON.parse(decodeUTF8Base64(base64string)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const pleromaDecoder = (json: string) => decodePleromaData(JSON.parse(json));
|
||||||
|
|
||||||
|
// This will throw if it fails.
|
||||||
|
// Should be called inside a try-catch.
|
||||||
|
const decodeFromMarkup = (elementId: string, decoder: (json: string) => Record<string, any>) => {
|
||||||
|
const { textContent } = document.getElementById(elementId)!;
|
||||||
|
return decoder(textContent as string);
|
||||||
|
};
|
||||||
|
|
||||||
|
const preloadFromMarkup = (elementId: string, decoder: (json: string) => Record<string, any>, action: (data: Record<string, any>) => any) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
try {
|
||||||
|
const data = decodeFromMarkup(elementId, decoder);
|
||||||
|
dispatch(action(data));
|
||||||
|
} catch {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const preload = () =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
dispatch(preloadFromMarkup('initial-results', pleromaDecoder, preloadPleroma));
|
||||||
|
dispatch(preloadFromMarkup('initial-state', JSON.parse, preloadMastodon));
|
||||||
|
};
|
||||||
|
|
||||||
|
const preloadPleroma = (data: Record<string, any>) => ({
|
||||||
|
type: PLEROMA_PRELOAD_IMPORT,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
|
||||||
|
const preloadMastodon = (data: Record<string, any>) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
const { me, access_token } = data.meta;
|
||||||
|
const { url } = data.accounts[me];
|
||||||
|
|
||||||
|
dispatch(importFetchedAccounts(Object.values(data.accounts)));
|
||||||
|
dispatch(verifyCredentials(access_token, url));
|
||||||
|
dispatch({ type: MASTODON_PRELOAD_IMPORT, data });
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
PLEROMA_PRELOAD_IMPORT,
|
||||||
|
MASTODON_PRELOAD_IMPORT,
|
||||||
|
preload,
|
||||||
|
preloadPleroma,
|
||||||
|
preloadMastodon,
|
||||||
|
};
|
|
@ -1,24 +0,0 @@
|
||||||
export const PROFILE_HOVER_CARD_OPEN = 'PROFILE_HOVER_CARD_OPEN';
|
|
||||||
export const PROFILE_HOVER_CARD_UPDATE = 'PROFILE_HOVER_CARD_UPDATE';
|
|
||||||
export const PROFILE_HOVER_CARD_CLOSE = 'PROFILE_HOVER_CARD_CLOSE';
|
|
||||||
|
|
||||||
export function openProfileHoverCard(ref, accountId) {
|
|
||||||
return {
|
|
||||||
type: PROFILE_HOVER_CARD_OPEN,
|
|
||||||
ref,
|
|
||||||
accountId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateProfileHoverCard() {
|
|
||||||
return {
|
|
||||||
type: PROFILE_HOVER_CARD_UPDATE,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function closeProfileHoverCard(force = false) {
|
|
||||||
return {
|
|
||||||
type: PROFILE_HOVER_CARD_CLOSE,
|
|
||||||
force,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
const PROFILE_HOVER_CARD_OPEN = 'PROFILE_HOVER_CARD_OPEN';
|
||||||
|
const PROFILE_HOVER_CARD_UPDATE = 'PROFILE_HOVER_CARD_UPDATE';
|
||||||
|
const PROFILE_HOVER_CARD_CLOSE = 'PROFILE_HOVER_CARD_CLOSE';
|
||||||
|
|
||||||
|
const openProfileHoverCard = (ref: React.MutableRefObject<HTMLDivElement>, accountId: string) => ({
|
||||||
|
type: PROFILE_HOVER_CARD_OPEN,
|
||||||
|
ref,
|
||||||
|
accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateProfileHoverCard = () => ({
|
||||||
|
type: PROFILE_HOVER_CARD_UPDATE,
|
||||||
|
});
|
||||||
|
|
||||||
|
const closeProfileHoverCard = (force = false) => ({
|
||||||
|
type: PROFILE_HOVER_CARD_CLOSE,
|
||||||
|
force,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
PROFILE_HOVER_CARD_OPEN,
|
||||||
|
PROFILE_HOVER_CARD_UPDATE,
|
||||||
|
PROFILE_HOVER_CARD_CLOSE,
|
||||||
|
openProfileHoverCard,
|
||||||
|
updateProfileHoverCard,
|
||||||
|
closeProfileHoverCard,
|
||||||
|
};
|
|
@ -7,17 +7,19 @@ import {
|
||||||
setAlerts,
|
setAlerts,
|
||||||
} from './setter';
|
} from './setter';
|
||||||
|
|
||||||
|
import type { AppDispatch } from 'soapbox/store';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
SET_BROWSER_SUPPORT,
|
SET_BROWSER_SUPPORT,
|
||||||
SET_SUBSCRIPTION,
|
SET_SUBSCRIPTION,
|
||||||
CLEAR_SUBSCRIPTION,
|
CLEAR_SUBSCRIPTION,
|
||||||
SET_ALERTS,
|
SET_ALERTS,
|
||||||
register,
|
register,
|
||||||
|
changeAlerts,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function changeAlerts(path, value) {
|
const changeAlerts = (path: Array<string>, value: any) =>
|
||||||
return dispatch => {
|
(dispatch: AppDispatch) => {
|
||||||
dispatch(setAlerts(path, value));
|
dispatch(setAlerts(path, value));
|
||||||
dispatch(saveSettings());
|
dispatch(saveSettings() as any);
|
||||||
};
|
};
|
||||||
}
|
|
|
@ -1,12 +1,15 @@
|
||||||
import { createPushSubsription, updatePushSubscription } from 'soapbox/actions/push_subscriptions';
|
import { createPushSubscription, updatePushSubscription } from 'soapbox/actions/push_subscriptions';
|
||||||
import { pushNotificationsSetting } from 'soapbox/settings';
|
import { pushNotificationsSetting } from 'soapbox/settings';
|
||||||
import { getVapidKey } from 'soapbox/utils/auth';
|
import { getVapidKey } from 'soapbox/utils/auth';
|
||||||
import { decode as decodeBase64 } from 'soapbox/utils/base64';
|
import { decode as decodeBase64 } from 'soapbox/utils/base64';
|
||||||
|
|
||||||
import { setBrowserSupport, setSubscription, clearSubscription } from './setter';
|
import { setBrowserSupport, setSubscription, clearSubscription } from './setter';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { Me } from 'soapbox/types/soapbox';
|
||||||
|
|
||||||
// Taken from https://www.npmjs.com/package/web-push
|
// Taken from https://www.npmjs.com/package/web-push
|
||||||
const urlBase64ToUint8Array = (base64String) => {
|
const urlBase64ToUint8Array = (base64String: string) => {
|
||||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||||
const base64 = (base64String + padding)
|
const base64 = (base64String + padding)
|
||||||
.replace(/\-/g, '+')
|
.replace(/\-/g, '+')
|
||||||
|
@ -17,22 +20,25 @@ const urlBase64ToUint8Array = (base64String) => {
|
||||||
|
|
||||||
const getRegistration = () => navigator.serviceWorker.ready;
|
const getRegistration = () => navigator.serviceWorker.ready;
|
||||||
|
|
||||||
const getPushSubscription = (registration) =>
|
const getPushSubscription = (registration: ServiceWorkerRegistration) =>
|
||||||
registration.pushManager.getSubscription()
|
registration.pushManager.getSubscription()
|
||||||
.then(subscription => ({ registration, subscription }));
|
.then(subscription => ({ registration, subscription }));
|
||||||
|
|
||||||
const subscribe = (registration, getState) =>
|
const subscribe = (registration: ServiceWorkerRegistration, getState: () => RootState) =>
|
||||||
registration.pushManager.subscribe({
|
registration.pushManager.subscribe({
|
||||||
userVisibleOnly: true,
|
userVisibleOnly: true,
|
||||||
applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState())),
|
applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState())),
|
||||||
});
|
});
|
||||||
|
|
||||||
const unsubscribe = ({ registration, subscription }) =>
|
const unsubscribe = ({ registration, subscription }: {
|
||||||
subscription ? subscription.unsubscribe().then(() => registration) : registration;
|
registration: ServiceWorkerRegistration,
|
||||||
|
subscription: PushSubscription | null,
|
||||||
|
}) =>
|
||||||
|
subscription ? subscription.unsubscribe().then(() => registration) : new Promise<ServiceWorkerRegistration>(r => r(registration));
|
||||||
|
|
||||||
const sendSubscriptionToBackend = (subscription, me) => {
|
const sendSubscriptionToBackend = (subscription: PushSubscription, me: Me) =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const alerts = getState().getIn(['push_notifications', 'alerts']).toJS();
|
const alerts = getState().push_notifications.get('alerts').toJS();
|
||||||
const params = { subscription, data: { alerts } };
|
const params = { subscription, data: { alerts } };
|
||||||
|
|
||||||
if (me) {
|
if (me) {
|
||||||
|
@ -42,16 +48,15 @@ const sendSubscriptionToBackend = (subscription, me) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dispatch(createPushSubsription(params));
|
return dispatch(createPushSubscription(params) as any);
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload
|
// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload
|
||||||
const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype);
|
const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype);
|
||||||
|
|
||||||
export function register() {
|
const register = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const me = getState().get('me');
|
const me = getState().me;
|
||||||
const vapidKey = getVapidKey(getState());
|
const vapidKey = getVapidKey(getState());
|
||||||
|
|
||||||
dispatch(setBrowserSupport(supportsPushNotifications));
|
dispatch(setBrowserSupport(supportsPushNotifications));
|
||||||
|
@ -68,35 +73,39 @@ export function register() {
|
||||||
|
|
||||||
getRegistration()
|
getRegistration()
|
||||||
.then(getPushSubscription)
|
.then(getPushSubscription)
|
||||||
.then(({ registration, subscription }) => {
|
// @ts-ignore
|
||||||
|
.then(({ registration, subscription }: {
|
||||||
|
registration: ServiceWorkerRegistration,
|
||||||
|
subscription: PushSubscription | null,
|
||||||
|
}) => {
|
||||||
if (subscription !== null) {
|
if (subscription !== null) {
|
||||||
// We have a subscription, check if it is still valid
|
// We have a subscription, check if it is still valid
|
||||||
const currentServerKey = (new Uint8Array(subscription.options.applicationServerKey)).toString();
|
const currentServerKey = (new Uint8Array(subscription.options.applicationServerKey!)).toString();
|
||||||
const subscriptionServerKey = urlBase64ToUint8Array(vapidKey).toString();
|
const subscriptionServerKey = urlBase64ToUint8Array(vapidKey).toString();
|
||||||
const serverEndpoint = getState().getIn(['push_notifications', 'subscription', 'endpoint']);
|
const serverEndpoint = getState().push_notifications.getIn(['subscription', 'endpoint']);
|
||||||
|
|
||||||
// If the VAPID public key did not change and the endpoint corresponds
|
// If the VAPID public key did not change and the endpoint corresponds
|
||||||
// to the endpoint saved in the backend, the subscription is valid
|
// to the endpoint saved in the backend, the subscription is valid
|
||||||
if (subscriptionServerKey === currentServerKey && subscription.endpoint === serverEndpoint) {
|
if (subscriptionServerKey === currentServerKey && subscription.endpoint === serverEndpoint) {
|
||||||
return subscription;
|
return { subscription };
|
||||||
} else {
|
} else {
|
||||||
// Something went wrong, try to subscribe again
|
// Something went wrong, try to subscribe again
|
||||||
return unsubscribe({ registration, subscription }).then(registration => {
|
return unsubscribe({ registration, subscription }).then((registration: ServiceWorkerRegistration) => {
|
||||||
return subscribe(registration, getState);
|
return subscribe(registration, getState);
|
||||||
}).then(
|
}).then(
|
||||||
subscription => dispatch(sendSubscriptionToBackend(subscription, me)));
|
(subscription: PushSubscription) => dispatch(sendSubscriptionToBackend(subscription, me) as any));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No subscription, try to subscribe
|
// No subscription, try to subscribe
|
||||||
return subscribe(registration, getState)
|
return subscribe(registration, getState)
|
||||||
.then(subscription => dispatch(sendSubscriptionToBackend(subscription, me)));
|
.then(subscription => dispatch(sendSubscriptionToBackend(subscription, me) as any));
|
||||||
})
|
})
|
||||||
.then(subscription => {
|
.then(({ subscription }: { subscription: PushSubscription | Record<string, any> }) => {
|
||||||
// If we got a PushSubscription (and not a subscription object from the backend)
|
// If we got a PushSubscription (and not a subscription object from the backend)
|
||||||
// it means that the backend subscription is valid (and was set during hydration)
|
// it means that the backend subscription is valid (and was set during hydration)
|
||||||
if (!(subscription instanceof PushSubscription)) {
|
if (!(subscription instanceof PushSubscription)) {
|
||||||
dispatch(setSubscription(subscription));
|
dispatch(setSubscription(subscription as PushSubscription));
|
||||||
if (me) {
|
if (me) {
|
||||||
pushNotificationsSetting.set(me, { alerts: subscription.alerts });
|
pushNotificationsSetting.set(me, { alerts: subscription.alerts });
|
||||||
}
|
}
|
||||||
|
@ -123,14 +132,13 @@ export function register() {
|
||||||
})
|
})
|
||||||
.catch(console.warn);
|
.catch(console.warn);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export function saveSettings() {
|
const saveSettings = () =>
|
||||||
return (dispatch, getState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState().get('push_notifications');
|
const state = getState().push_notifications;
|
||||||
const alerts = state.get('alerts');
|
const alerts = state.get('alerts');
|
||||||
const data = { alerts };
|
const data = { alerts };
|
||||||
const me = getState().get('me');
|
const me = getState().me;
|
||||||
|
|
||||||
return dispatch(updatePushSubscription({ data })).then(() => {
|
return dispatch(updatePushSubscription({ data })).then(() => {
|
||||||
if (me) {
|
if (me) {
|
||||||
|
@ -138,4 +146,8 @@ export function saveSettings() {
|
||||||
}
|
}
|
||||||
}).catch(console.warn);
|
}).catch(console.warn);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
export {
|
||||||
|
register,
|
||||||
|
saveSettings,
|
||||||
|
};
|
|
@ -1,34 +0,0 @@
|
||||||
export const SET_BROWSER_SUPPORT = 'PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
|
||||||
export const SET_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_SET_SUBSCRIPTION';
|
|
||||||
export const CLEAR_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION';
|
|
||||||
export const SET_ALERTS = 'PUSH_NOTIFICATIONS_SET_ALERTS';
|
|
||||||
|
|
||||||
export function setBrowserSupport(value) {
|
|
||||||
return {
|
|
||||||
type: SET_BROWSER_SUPPORT,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setSubscription(subscription) {
|
|
||||||
return {
|
|
||||||
type: SET_SUBSCRIPTION,
|
|
||||||
subscription,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearSubscription() {
|
|
||||||
return {
|
|
||||||
type: CLEAR_SUBSCRIPTION,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setAlerts(path, value) {
|
|
||||||
return dispatch => {
|
|
||||||
dispatch({
|
|
||||||
type: SET_ALERTS,
|
|
||||||
path,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import type { AnyAction } from 'redux';
|
||||||
|
|
||||||
|
const SET_BROWSER_SUPPORT = 'PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
||||||
|
const SET_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_SET_SUBSCRIPTION';
|
||||||
|
const CLEAR_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION';
|
||||||
|
const SET_ALERTS = 'PUSH_NOTIFICATIONS_SET_ALERTS';
|
||||||
|
|
||||||
|
const setBrowserSupport = (value: boolean) => ({
|
||||||
|
type: SET_BROWSER_SUPPORT,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setSubscription = (subscription: PushSubscription) => ({
|
||||||
|
type: SET_SUBSCRIPTION,
|
||||||
|
subscription,
|
||||||
|
});
|
||||||
|
|
||||||
|
const clearSubscription = () => ({
|
||||||
|
type: CLEAR_SUBSCRIPTION,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setAlerts = (path: Array<string>, value: any) =>
|
||||||
|
(dispatch: React.Dispatch<AnyAction>) =>
|
||||||
|
dispatch({
|
||||||
|
type: SET_ALERTS,
|
||||||
|
path,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
SET_BROWSER_SUPPORT,
|
||||||
|
SET_SUBSCRIPTION,
|
||||||
|
CLEAR_SUBSCRIPTION,
|
||||||
|
SET_ALERTS,
|
||||||
|
setBrowserSupport,
|
||||||
|
setSubscription,
|
||||||
|
clearSubscription,
|
||||||
|
setAlerts,
|
||||||
|
};
|
|
@ -1,62 +0,0 @@
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
export const PUSH_SUBSCRIPTION_CREATE_REQUEST = 'PUSH_SUBSCRIPTION_CREATE_REQUEST';
|
|
||||||
export const PUSH_SUBSCRIPTION_CREATE_SUCCESS = 'PUSH_SUBSCRIPTION_CREATE_SUCCESS';
|
|
||||||
export const PUSH_SUBSCRIPTION_CREATE_FAIL = 'PUSH_SUBSCRIPTION_CREATE_FAIL';
|
|
||||||
|
|
||||||
export const PUSH_SUBSCRIPTION_FETCH_REQUEST = 'PUSH_SUBSCRIPTION_FETCH_REQUEST';
|
|
||||||
export const PUSH_SUBSCRIPTION_FETCH_SUCCESS = 'PUSH_SUBSCRIPTION_FETCH_SUCCESS';
|
|
||||||
export const PUSH_SUBSCRIPTION_FETCH_FAIL = 'PUSH_SUBSCRIPTION_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const PUSH_SUBSCRIPTION_UPDATE_REQUEST = 'PUSH_SUBSCRIPTION_UPDATE_REQUEST';
|
|
||||||
export const PUSH_SUBSCRIPTION_UPDATE_SUCCESS = 'PUSH_SUBSCRIPTION_UPDATE_SUCCESS';
|
|
||||||
export const PUSH_SUBSCRIPTION_UPDATE_FAIL = 'PUSH_SUBSCRIPTION_UPDATE_FAIL';
|
|
||||||
|
|
||||||
export const PUSH_SUBSCRIPTION_DELETE_REQUEST = 'PUSH_SUBSCRIPTION_DELETE_REQUEST';
|
|
||||||
export const PUSH_SUBSCRIPTION_DELETE_SUCCESS = 'PUSH_SUBSCRIPTION_DELETE_SUCCESS';
|
|
||||||
export const PUSH_SUBSCRIPTION_DELETE_FAIL = 'PUSH_SUBSCRIPTION_DELETE_FAIL';
|
|
||||||
|
|
||||||
export function createPushSubsription(params) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_CREATE_REQUEST, params });
|
|
||||||
return api(getState).post('/api/v1/push/subscription', params).then(({ data: subscription }) => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_CREATE_SUCCESS, params, subscription });
|
|
||||||
return subscription;
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_CREATE_FAIL, params, error });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchPushSubsription() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_FETCH_REQUEST });
|
|
||||||
return api(getState).get('/api/v1/push/subscription').then(({ data: subscription }) => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_FETCH_SUCCESS, subscription });
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_FETCH_FAIL, error });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updatePushSubscription(params) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_UPDATE_REQUEST, params });
|
|
||||||
return api(getState).put('/api/v1/push/subscription', params).then(({ data: subscription }) => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_UPDATE_SUCCESS, params, subscription });
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_UPDATE_FAIL, params, error });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deletePushSubsription() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_DELETE_REQUEST });
|
|
||||||
return api(getState).delete('/api/v1/push/subscription').then(() => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_DELETE_SUCCESS });
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch({ type: PUSH_SUBSCRIPTION_DELETE_FAIL, error });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
const PUSH_SUBSCRIPTION_CREATE_REQUEST = 'PUSH_SUBSCRIPTION_CREATE_REQUEST';
|
||||||
|
const PUSH_SUBSCRIPTION_CREATE_SUCCESS = 'PUSH_SUBSCRIPTION_CREATE_SUCCESS';
|
||||||
|
const PUSH_SUBSCRIPTION_CREATE_FAIL = 'PUSH_SUBSCRIPTION_CREATE_FAIL';
|
||||||
|
|
||||||
|
const PUSH_SUBSCRIPTION_FETCH_REQUEST = 'PUSH_SUBSCRIPTION_FETCH_REQUEST';
|
||||||
|
const PUSH_SUBSCRIPTION_FETCH_SUCCESS = 'PUSH_SUBSCRIPTION_FETCH_SUCCESS';
|
||||||
|
const PUSH_SUBSCRIPTION_FETCH_FAIL = 'PUSH_SUBSCRIPTION_FETCH_FAIL';
|
||||||
|
|
||||||
|
const PUSH_SUBSCRIPTION_UPDATE_REQUEST = 'PUSH_SUBSCRIPTION_UPDATE_REQUEST';
|
||||||
|
const PUSH_SUBSCRIPTION_UPDATE_SUCCESS = 'PUSH_SUBSCRIPTION_UPDATE_SUCCESS';
|
||||||
|
const PUSH_SUBSCRIPTION_UPDATE_FAIL = 'PUSH_SUBSCRIPTION_UPDATE_FAIL';
|
||||||
|
|
||||||
|
const PUSH_SUBSCRIPTION_DELETE_REQUEST = 'PUSH_SUBSCRIPTION_DELETE_REQUEST';
|
||||||
|
const PUSH_SUBSCRIPTION_DELETE_SUCCESS = 'PUSH_SUBSCRIPTION_DELETE_SUCCESS';
|
||||||
|
const PUSH_SUBSCRIPTION_DELETE_FAIL = 'PUSH_SUBSCRIPTION_DELETE_FAIL';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
const createPushSubscription = (params: Record<string, any>) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_CREATE_REQUEST, params });
|
||||||
|
return api(getState).post('/api/v1/push/subscription', params).then(({ data: subscription }) =>
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_CREATE_SUCCESS, params, subscription }),
|
||||||
|
).catch(error =>
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_CREATE_FAIL, params, error }),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPushSubscription = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_FETCH_REQUEST });
|
||||||
|
return api(getState).get('/api/v1/push/subscription').then(({ data: subscription }) =>
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_FETCH_SUCCESS, subscription }),
|
||||||
|
).catch(error =>
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_FETCH_FAIL, error }),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updatePushSubscription = (params: Record<string, any>) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_UPDATE_REQUEST, params });
|
||||||
|
return api(getState).put('/api/v1/push/subscription', params).then(({ data: subscription }) =>
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_UPDATE_SUCCESS, params, subscription }),
|
||||||
|
).catch(error =>
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_UPDATE_FAIL, params, error }),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const deletePushSubscription = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_DELETE_REQUEST });
|
||||||
|
return api(getState).delete('/api/v1/push/subscription').then(() =>
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_DELETE_SUCCESS }),
|
||||||
|
).catch(error =>
|
||||||
|
dispatch({ type: PUSH_SUBSCRIPTION_DELETE_FAIL, error }),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
PUSH_SUBSCRIPTION_CREATE_REQUEST,
|
||||||
|
PUSH_SUBSCRIPTION_CREATE_SUCCESS,
|
||||||
|
PUSH_SUBSCRIPTION_CREATE_FAIL,
|
||||||
|
PUSH_SUBSCRIPTION_FETCH_REQUEST,
|
||||||
|
PUSH_SUBSCRIPTION_FETCH_SUCCESS,
|
||||||
|
PUSH_SUBSCRIPTION_FETCH_FAIL,
|
||||||
|
PUSH_SUBSCRIPTION_UPDATE_REQUEST,
|
||||||
|
PUSH_SUBSCRIPTION_UPDATE_SUCCESS,
|
||||||
|
PUSH_SUBSCRIPTION_UPDATE_FAIL,
|
||||||
|
PUSH_SUBSCRIPTION_DELETE_REQUEST,
|
||||||
|
PUSH_SUBSCRIPTION_DELETE_SUCCESS,
|
||||||
|
PUSH_SUBSCRIPTION_DELETE_FAIL,
|
||||||
|
createPushSubscription,
|
||||||
|
fetchPushSubscription,
|
||||||
|
updatePushSubscription,
|
||||||
|
deletePushSubscription,
|
||||||
|
};
|
|
@ -1,24 +0,0 @@
|
||||||
import { getSettings, changeSetting } from 'soapbox/actions/settings';
|
|
||||||
|
|
||||||
const getPinnedHosts = state => {
|
|
||||||
const settings = getSettings(state);
|
|
||||||
return settings.getIn(['remote_timeline', 'pinnedHosts']);
|
|
||||||
};
|
|
||||||
|
|
||||||
export function pinHost(host) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const pinnedHosts = getPinnedHosts(state);
|
|
||||||
|
|
||||||
return dispatch(changeSetting(['remote_timeline', 'pinnedHosts'], pinnedHosts.push(host)));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unpinHost(host) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const pinnedHosts = getPinnedHosts(state);
|
|
||||||
|
|
||||||
return dispatch(changeSetting(['remote_timeline', 'pinnedHosts'], pinnedHosts.filter((value) => value !== host)));
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { getSettings, changeSetting } from 'soapbox/actions/settings';
|
||||||
|
|
||||||
|
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
const getPinnedHosts = (state: RootState) => {
|
||||||
|
const settings = getSettings(state);
|
||||||
|
return settings.getIn(['remote_timeline', 'pinnedHosts']) as ImmutableOrderedSet<string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pinHost = (host: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
const pinnedHosts = getPinnedHosts(state);
|
||||||
|
|
||||||
|
return dispatch(changeSetting(['remote_timeline', 'pinnedHosts'], pinnedHosts.add(host)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const unpinHost = (host: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
const pinnedHosts = getPinnedHosts(state);
|
||||||
|
|
||||||
|
return dispatch(changeSetting(['remote_timeline', 'pinnedHosts'], pinnedHosts.remove(host)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
pinHost,
|
||||||
|
unpinHost,
|
||||||
|
};
|
|
@ -1,116 +0,0 @@
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
import { openModal } from './modals';
|
|
||||||
|
|
||||||
export const REPORT_INIT = 'REPORT_INIT';
|
|
||||||
export const REPORT_CANCEL = 'REPORT_CANCEL';
|
|
||||||
|
|
||||||
export const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST';
|
|
||||||
export const REPORT_SUBMIT_SUCCESS = 'REPORT_SUBMIT_SUCCESS';
|
|
||||||
export const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL';
|
|
||||||
|
|
||||||
export const REPORT_STATUS_TOGGLE = 'REPORT_STATUS_TOGGLE';
|
|
||||||
export const REPORT_COMMENT_CHANGE = 'REPORT_COMMENT_CHANGE';
|
|
||||||
export const REPORT_FORWARD_CHANGE = 'REPORT_FORWARD_CHANGE';
|
|
||||||
export const REPORT_BLOCK_CHANGE = 'REPORT_BLOCK_CHANGE';
|
|
||||||
|
|
||||||
export const REPORT_RULE_CHANGE = 'REPORT_RULE_CHANGE';
|
|
||||||
|
|
||||||
export function initReport(account, status) {
|
|
||||||
return dispatch => {
|
|
||||||
dispatch({
|
|
||||||
type: REPORT_INIT,
|
|
||||||
account,
|
|
||||||
status,
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(openModal('REPORT'));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initReportById(accountId) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({
|
|
||||||
type: REPORT_INIT,
|
|
||||||
account: getState().getIn(['accounts', accountId]),
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(openModal('REPORT'));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cancelReport() {
|
|
||||||
return {
|
|
||||||
type: REPORT_CANCEL,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleStatusReport(statusId, checked) {
|
|
||||||
return {
|
|
||||||
type: REPORT_STATUS_TOGGLE,
|
|
||||||
statusId,
|
|
||||||
checked,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function submitReport() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch(submitReportRequest());
|
|
||||||
const { reports } = getState();
|
|
||||||
|
|
||||||
return api(getState).post('/api/v1/reports', {
|
|
||||||
account_id: reports.getIn(['new', 'account_id']),
|
|
||||||
status_ids: reports.getIn(['new', 'status_ids']),
|
|
||||||
rule_ids: reports.getIn(['new', 'rule_ids']),
|
|
||||||
comment: reports.getIn(['new', 'comment']),
|
|
||||||
forward: reports.getIn(['new', 'forward']),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function submitReportRequest() {
|
|
||||||
return {
|
|
||||||
type: REPORT_SUBMIT_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function submitReportSuccess() {
|
|
||||||
return {
|
|
||||||
type: REPORT_SUBMIT_SUCCESS,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function submitReportFail(error) {
|
|
||||||
return {
|
|
||||||
type: REPORT_SUBMIT_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeReportComment(comment) {
|
|
||||||
return {
|
|
||||||
type: REPORT_COMMENT_CHANGE,
|
|
||||||
comment,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeReportForward(forward) {
|
|
||||||
return {
|
|
||||||
type: REPORT_FORWARD_CHANGE,
|
|
||||||
forward,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeReportBlock(block) {
|
|
||||||
return {
|
|
||||||
type: REPORT_BLOCK_CHANGE,
|
|
||||||
block,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeReportRule(ruleId) {
|
|
||||||
return {
|
|
||||||
type: REPORT_RULE_CHANGE,
|
|
||||||
rule_id: ruleId,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
import { openModal } from './modals';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { Account, Status } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const REPORT_INIT = 'REPORT_INIT';
|
||||||
|
const REPORT_CANCEL = 'REPORT_CANCEL';
|
||||||
|
|
||||||
|
const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST';
|
||||||
|
const REPORT_SUBMIT_SUCCESS = 'REPORT_SUBMIT_SUCCESS';
|
||||||
|
const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL';
|
||||||
|
|
||||||
|
const REPORT_STATUS_TOGGLE = 'REPORT_STATUS_TOGGLE';
|
||||||
|
const REPORT_COMMENT_CHANGE = 'REPORT_COMMENT_CHANGE';
|
||||||
|
const REPORT_FORWARD_CHANGE = 'REPORT_FORWARD_CHANGE';
|
||||||
|
const REPORT_BLOCK_CHANGE = 'REPORT_BLOCK_CHANGE';
|
||||||
|
|
||||||
|
const REPORT_RULE_CHANGE = 'REPORT_RULE_CHANGE';
|
||||||
|
|
||||||
|
const initReport = (account: Account, status: Status) =>
|
||||||
|
(dispatch: AppDispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: REPORT_INIT,
|
||||||
|
account,
|
||||||
|
status,
|
||||||
|
});
|
||||||
|
|
||||||
|
return dispatch(openModal('REPORT'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const initReportById = (accountId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({
|
||||||
|
type: REPORT_INIT,
|
||||||
|
account: getState().accounts.get(accountId),
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(openModal('REPORT'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelReport = () => ({
|
||||||
|
type: REPORT_CANCEL,
|
||||||
|
});
|
||||||
|
|
||||||
|
const toggleStatusReport = (statusId: string, checked: boolean) => ({
|
||||||
|
type: REPORT_STATUS_TOGGLE,
|
||||||
|
statusId,
|
||||||
|
checked,
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitReport = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(submitReportRequest());
|
||||||
|
const { reports } = getState();
|
||||||
|
|
||||||
|
return api(getState).post('/api/v1/reports', {
|
||||||
|
account_id: reports.getIn(['new', 'account_id']),
|
||||||
|
status_ids: reports.getIn(['new', 'status_ids']),
|
||||||
|
rule_ids: reports.getIn(['new', 'rule_ids']),
|
||||||
|
comment: reports.getIn(['new', 'comment']),
|
||||||
|
forward: reports.getIn(['new', 'forward']),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitReportRequest = () => ({
|
||||||
|
type: REPORT_SUBMIT_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitReportSuccess = () => ({
|
||||||
|
type: REPORT_SUBMIT_SUCCESS,
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitReportFail = (error: AxiosError) => ({
|
||||||
|
type: REPORT_SUBMIT_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeReportComment = (comment: string) => ({
|
||||||
|
type: REPORT_COMMENT_CHANGE,
|
||||||
|
comment,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeReportForward = (forward: boolean) => ({
|
||||||
|
type: REPORT_FORWARD_CHANGE,
|
||||||
|
forward,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeReportBlock = (block: boolean) => ({
|
||||||
|
type: REPORT_BLOCK_CHANGE,
|
||||||
|
block,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeReportRule = (ruleId: string) => ({
|
||||||
|
type: REPORT_RULE_CHANGE,
|
||||||
|
rule_id: ruleId,
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
REPORT_INIT,
|
||||||
|
REPORT_CANCEL,
|
||||||
|
REPORT_SUBMIT_REQUEST,
|
||||||
|
REPORT_SUBMIT_SUCCESS,
|
||||||
|
REPORT_SUBMIT_FAIL,
|
||||||
|
REPORT_STATUS_TOGGLE,
|
||||||
|
REPORT_COMMENT_CHANGE,
|
||||||
|
REPORT_FORWARD_CHANGE,
|
||||||
|
REPORT_BLOCK_CHANGE,
|
||||||
|
REPORT_RULE_CHANGE,
|
||||||
|
initReport,
|
||||||
|
initReportById,
|
||||||
|
cancelReport,
|
||||||
|
toggleStatusReport,
|
||||||
|
submitReport,
|
||||||
|
submitReportRequest,
|
||||||
|
submitReportSuccess,
|
||||||
|
submitReportFail,
|
||||||
|
changeReportComment,
|
||||||
|
changeReportForward,
|
||||||
|
changeReportBlock,
|
||||||
|
changeReportRule,
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue