Sort posts before storing in redux
This commit is contained in:
parent
40a0b72d87
commit
40749403b9
10 changed files with 146 additions and 95 deletions
|
|
@ -56,7 +56,7 @@ const mapStateToProps = state => {
|
||||||
const { error } = state.error;
|
const { error } = state.error;
|
||||||
|
|
||||||
if (!isEqual(state.selected.post, {})) {
|
if (!isEqual(state.selected.post, {})) {
|
||||||
const ruleId = state.selected.post.rule;
|
const ruleId = state.selected.post.rule.id;
|
||||||
|
|
||||||
const rule = state.rules.items[ruleId];
|
const rule = state.rules.items[ruleId];
|
||||||
const category = state.categories.items[rule.category];
|
const category = state.categories.items[rule.category];
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import { formatDatetime } from '../../../../utils.js';
|
||||||
class PostItem extends React.Component {
|
class PostItem extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const rule = { ...this.props.post.rule };
|
const rule = { ...this.props.post.rule };
|
||||||
const post = { ...this.props.post, rule: rule.id };
|
const post = { ...this.props.post };
|
||||||
const token = Cookies.get('csrftoken');
|
const token = Cookies.get('csrftoken');
|
||||||
const publicationDate = formatDatetime(post.publicationDate);
|
const publicationDate = formatDatetime(post.publicationDate);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,9 @@ class PostList extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const isLastItem = this.props.postsByType.toReversed().find(item => !item.read);
|
||||||
|
|
||||||
const postItems = this.props.postsByType.map((item, index) => {
|
const postItems = this.props.postsByType.map((item, index) => {
|
||||||
const isLastItem = this.props.postsByType.length - 1 == index;
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
key: index,
|
key: index,
|
||||||
post: item,
|
post: item,
|
||||||
|
|
@ -68,7 +69,7 @@ class PostList extends React.Component {
|
||||||
timezone: this.props.timezone,
|
timezone: this.props.timezone,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLastItem && !item.read) {
|
if (isLastItem?.id === item.id) {
|
||||||
return <PostItem {...defaultProps} forwardedRef={this.lastPostRef} />;
|
return <PostItem {...defaultProps} forwardedRef={this.lastPostRef} />;
|
||||||
} else {
|
} else {
|
||||||
return <PostItem {...defaultProps} />;
|
return <PostItem {...defaultProps} />;
|
||||||
|
|
|
||||||
|
|
@ -4,31 +4,10 @@ const isEmpty = (object = {}) => {
|
||||||
return Object.keys(object).length === 0;
|
return Object.keys(object).length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortOrdering = (firstPost, secondPost) => {
|
|
||||||
const dateOrdering =
|
|
||||||
new Date(firstPost.publicationDate) < new Date(secondPost.publicationDate);
|
|
||||||
|
|
||||||
if (firstPost.read && !secondPost.read) {
|
|
||||||
return 1;
|
|
||||||
} else if (secondPost.read && !firstPost.read) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dateOrdering;
|
|
||||||
};
|
|
||||||
|
|
||||||
const savedOrdering = (firstPost, secondPost) => {
|
|
||||||
return new Date(firstPost.publicationDate) < new Date(secondPost.publicationDate);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const filterPostsByRule = (rule = {}, posts = []) => {
|
export const filterPostsByRule = (rule = {}, posts = []) => {
|
||||||
const filteredPosts = posts.filter(post => {
|
return posts.filter(post => {
|
||||||
return post.rule === rule.id;
|
return post.rule.id === rule.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredData = filteredPosts.map(post => ({ ...post, rule: { ...rule } }));
|
|
||||||
|
|
||||||
return filteredData.sort(sortOrdering);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filterPostsByCategory = (category = {}, rules = [], posts = []) => {
|
export const filterPostsByCategory = (category = {}, rules = [], posts = []) => {
|
||||||
|
|
@ -36,24 +15,13 @@ export const filterPostsByCategory = (category = {}, rules = [], posts = []) =>
|
||||||
return rule.category === category.id;
|
return rule.category === category.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredData = filteredRules.map(rule => {
|
const ruleIds = filteredRules.map(rule => rule.id);
|
||||||
const filteredPosts = posts.filter(post => {
|
|
||||||
return post.rule === rule.id;
|
|
||||||
});
|
|
||||||
|
|
||||||
return filteredPosts.map(post => ({ ...post, rule: { ...rule } }));
|
return [...posts].filter(post => ruleIds.includes(post.rule.id));
|
||||||
});
|
|
||||||
|
|
||||||
const sortedPosts = [...filteredData.flat()].sort(sortOrdering);
|
|
||||||
|
|
||||||
return sortedPosts;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filterPostsBySaved = (rules = [], posts = []) => {
|
export const filterPostsBySaved = (rules = [], posts = []) => {
|
||||||
const filteredPosts = posts.filter(post => post.saved);
|
return [...posts].filter(post => post.saved);
|
||||||
return filteredPosts
|
|
||||||
.map(post => ({ ...post, rule: { ...rules.find(rule => rule.id === post.rule) } }))
|
|
||||||
.sort(savedOrdering);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filterPosts = state => {
|
export const filterPosts = state => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import { isEqual } from 'lodash';
|
|
||||||
|
|
||||||
import { objectsFromArray } from '../../../utils.js';
|
import { objectsFromArray } from '../../../utils.js';
|
||||||
import { CATEGORY_TYPE, RULE_TYPE } from '../constants.js';
|
import { CATEGORY_TYPE, RULE_TYPE } from '../constants.js';
|
||||||
|
|
||||||
|
|
@ -12,58 +10,83 @@ import {
|
||||||
TOGGLING_POST,
|
TOGGLING_POST,
|
||||||
TOGGLED_POST,
|
TOGGLED_POST,
|
||||||
} from '../actions/posts.js';
|
} from '../actions/posts.js';
|
||||||
import { SELECT_CATEGORY } from '../actions/categories.js';
|
|
||||||
import { SELECT_RULE } from '../actions/rules.js';
|
|
||||||
import { MARK_SECTION_READ } from '../actions/selected.js';
|
import { MARK_SECTION_READ } from '../actions/selected.js';
|
||||||
|
|
||||||
const defaultState = { items: {}, isFetching: false, isUpdating: false };
|
const sortOrdering = (firstPost, secondPost) => {
|
||||||
|
const dateOrdering =
|
||||||
|
new Date(firstPost.publicationDate) < new Date(secondPost.publicationDate);
|
||||||
|
|
||||||
|
if (firstPost.read && !secondPost.read) {
|
||||||
|
return 1;
|
||||||
|
} else if (secondPost.read && !firstPost.read) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dateOrdering;
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultState = { items: [], isFetching: false, isUpdating: false };
|
||||||
|
|
||||||
export const posts = (state = { ...defaultState }, action) => {
|
export const posts = (state = { ...defaultState }, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case REQUEST_POSTS:
|
case REQUEST_POSTS:
|
||||||
return { ...state, isFetching: true };
|
return { ...state, isFetching: true };
|
||||||
case RECEIVE_POST:
|
case RECEIVE_POST:
|
||||||
|
const postIndex = state.items.findIndex(post => post.id === action.post.id);
|
||||||
|
let newItems = [...state.items];
|
||||||
|
|
||||||
|
if (postIndex >= 0) {
|
||||||
|
newItems.splice(postIndex, 1, { ...action.post });
|
||||||
|
} else {
|
||||||
|
newItems = [...state.items, { ...action.post }];
|
||||||
|
}
|
||||||
|
|
||||||
|
newItems.sort(sortOrdering);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
items: { ...state.items, [action.post.id]: { ...action.post } },
|
items: newItems,
|
||||||
};
|
};
|
||||||
case RECEIVE_POSTS:
|
case RECEIVE_POSTS:
|
||||||
const receivedItems = objectsFromArray(action.posts, 'id');
|
const receivedPosts = objectsFromArray(action.posts, 'id');
|
||||||
|
|
||||||
|
let mergedPosts = { ...objectsFromArray(state.items, 'id'), ...receivedPosts };
|
||||||
|
let sortedPosts = Object.values(mergedPosts).sort(sortOrdering);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
items: { ...state.items, ...receivedItems },
|
items: sortedPosts,
|
||||||
};
|
};
|
||||||
case MARK_SECTION_READ:
|
case MARK_SECTION_READ:
|
||||||
const updatedPosts = {};
|
let posts = [];
|
||||||
let relatedPosts = [];
|
|
||||||
|
|
||||||
switch (action.section.type) {
|
switch (action.section.type) {
|
||||||
case CATEGORY_TYPE:
|
case CATEGORY_TYPE:
|
||||||
relatedPosts = Object.values({ ...state.items }).filter(post => {
|
posts = [...state.items];
|
||||||
return post.rule in { ...action.section.rules };
|
|
||||||
|
posts.forEach(post => {
|
||||||
|
if (!(post.rule.id in { ...action.section.rules })) return;
|
||||||
|
|
||||||
|
post.read = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case RULE_TYPE:
|
case RULE_TYPE:
|
||||||
relatedPosts = Object.values({ ...state.items }).filter(post => {
|
posts = [...state.items];
|
||||||
return post.rule === action.section.id;
|
|
||||||
|
posts.forEach(post => {
|
||||||
|
if (post.rule.id != action.section.id) return;
|
||||||
|
|
||||||
|
post.read = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
relatedPosts.forEach(post => {
|
|
||||||
updatedPosts[post.id] = { ...post, read: true };
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
items: {
|
items: posts,
|
||||||
...state.items,
|
|
||||||
...updatedPosts,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
case MARKING_POST:
|
case MARKING_POST:
|
||||||
return { ...state, isUpdating: true };
|
return { ...state, isUpdating: true };
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import * as actions from '../../../pages/homepage/actions/posts.js';
|
||||||
import * as selectedActions from '../../../pages/homepage/actions/selected.js';
|
import * as selectedActions from '../../../pages/homepage/actions/selected.js';
|
||||||
import * as constants from '../../../pages/homepage/constants.js';
|
import * as constants from '../../../pages/homepage/constants.js';
|
||||||
|
|
||||||
const defaultState = { items: {}, isFetching: false };
|
const defaultState = { items: [], isFetching: false };
|
||||||
|
|
||||||
describe('post actions', () => {
|
describe('post actions', () => {
|
||||||
it('should return state after requesting posts', () => {
|
it('should return state after requesting posts', () => {
|
||||||
|
|
@ -42,7 +42,7 @@ describe('post actions', () => {
|
||||||
...defaultState,
|
...defaultState,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
isUpdating: false,
|
isUpdating: false,
|
||||||
items: { [post.id]: post },
|
items: [post],
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(reducer(undefined, action)).toEqual(expectedState);
|
expect(reducer(undefined, action)).toEqual(expectedState);
|
||||||
|
|
@ -85,12 +85,11 @@ describe('post actions', () => {
|
||||||
posts,
|
posts,
|
||||||
};
|
};
|
||||||
|
|
||||||
const expectedPosts = objectsFromArray(posts, 'id');
|
|
||||||
const expectedState = {
|
const expectedState = {
|
||||||
...defaultState,
|
...defaultState,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
isUpdating: false,
|
isUpdating: false,
|
||||||
items: expectedPosts,
|
items: posts,
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(reducer(undefined, action)).toEqual(expectedState);
|
expect(reducer(undefined, action)).toEqual(expectedState);
|
||||||
|
|
@ -108,7 +107,14 @@ describe('post actions', () => {
|
||||||
author: 'Kyle Orland',
|
author: 'Kyle Orland',
|
||||||
publicationDate: '2020-01-24T19:50:12Z',
|
publicationDate: '2020-01-24T19:50:12Z',
|
||||||
url: 'https://arstechnica.com/?p=1648607',
|
url: 'https://arstechnica.com/?p=1648607',
|
||||||
rule: 5,
|
rule: {
|
||||||
|
id: 5,
|
||||||
|
name: 'Ars Technica',
|
||||||
|
url: 'http://feeds.arstechnica.com/arstechnica/index?fmt=xml',
|
||||||
|
favicon: 'https://cdn.arstechnica.net/favicon.ico',
|
||||||
|
category: 9,
|
||||||
|
unread: 544,
|
||||||
|
},
|
||||||
read: false,
|
read: false,
|
||||||
},
|
},
|
||||||
2141: {
|
2141: {
|
||||||
|
|
@ -120,7 +126,14 @@ describe('post actions', () => {
|
||||||
author: 'WIRED',
|
author: 'WIRED',
|
||||||
publicationDate: '2020-01-25T11:06:46Z',
|
publicationDate: '2020-01-25T11:06:46Z',
|
||||||
url: 'https://arstechnica.com/?p=1648757',
|
url: 'https://arstechnica.com/?p=1648757',
|
||||||
rule: 5,
|
rule: {
|
||||||
|
id: 5,
|
||||||
|
name: 'Ars Technica',
|
||||||
|
url: 'http://feeds.arstechnica.com/arstechnica/index?fmt=xml',
|
||||||
|
favicon: 'https://cdn.arstechnica.net/favicon.ico',
|
||||||
|
category: 9,
|
||||||
|
unread: 544,
|
||||||
|
},
|
||||||
read: false,
|
read: false,
|
||||||
},
|
},
|
||||||
4637: {
|
4637: {
|
||||||
|
|
@ -132,7 +145,9 @@ describe('post actions', () => {
|
||||||
author: null,
|
author: null,
|
||||||
publicationDate: '2020-01-29T19:08:25Z',
|
publicationDate: '2020-01-29T19:08:25Z',
|
||||||
url: 'https://www.bbc.co.uk/news/world-asia-china-51299195',
|
url: 'https://www.bbc.co.uk/news/world-asia-china-51299195',
|
||||||
rule: 4,
|
rule: {
|
||||||
|
id: 4,
|
||||||
|
},
|
||||||
read: false,
|
read: false,
|
||||||
saved: false,
|
saved: false,
|
||||||
},
|
},
|
||||||
|
|
@ -145,7 +160,9 @@ describe('post actions', () => {
|
||||||
author: null,
|
author: null,
|
||||||
publicationDate: '2020-01-29T18:27:56Z',
|
publicationDate: '2020-01-29T18:27:56Z',
|
||||||
url: 'https://www.bbc.co.uk/news/world-europe-51294305',
|
url: 'https://www.bbc.co.uk/news/world-europe-51294305',
|
||||||
rule: 4,
|
rule: {
|
||||||
|
id: 4,
|
||||||
|
},
|
||||||
read: false,
|
read: false,
|
||||||
saved: false,
|
saved: false,
|
||||||
},
|
},
|
||||||
|
|
@ -165,16 +182,17 @@ describe('post actions', () => {
|
||||||
section: { ...rule, type: constants.RULE_TYPE },
|
section: { ...rule, type: constants.RULE_TYPE },
|
||||||
};
|
};
|
||||||
|
|
||||||
const state = { ...defaultState, items: { ...posts } };
|
const state = { ...defaultState, items: Object.values(posts) };
|
||||||
|
|
||||||
const expectedState = {
|
const expectedState = {
|
||||||
...defaultState,
|
...defaultState,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
items: {
|
items: [
|
||||||
...posts,
|
{ ...posts[2067], read: true },
|
||||||
2067: { ...posts[2067], read: true },
|
{ ...posts[2141], read: true },
|
||||||
2141: { ...posts[2141], read: true },
|
{ ...posts[4637] },
|
||||||
},
|
{ ...posts[4638] },
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(reducer(state, action)).toEqual(expectedState);
|
expect(reducer(state, action)).toEqual(expectedState);
|
||||||
|
|
@ -192,7 +210,15 @@ describe('post actions', () => {
|
||||||
author: 'Kyle Orland',
|
author: 'Kyle Orland',
|
||||||
publicationDate: '2020-01-24T19:50:12Z',
|
publicationDate: '2020-01-24T19:50:12Z',
|
||||||
url: 'https://arstechnica.com/?p=1648607',
|
url: 'https://arstechnica.com/?p=1648607',
|
||||||
rule: 5,
|
rule: {
|
||||||
|
id: 5,
|
||||||
|
name: 'BBC',
|
||||||
|
url: 'http://feeds.bbci.co.uk/news/world/rss.xml',
|
||||||
|
favicon:
|
||||||
|
'https://m.files.bbci.co.uk/modules/bbc-morph-news-waf-page-meta/2.5.2/apple-touch-icon-57x57-precomposed.png',
|
||||||
|
category: 8,
|
||||||
|
unread: 632,
|
||||||
|
},
|
||||||
read: false,
|
read: false,
|
||||||
saved: false,
|
saved: false,
|
||||||
},
|
},
|
||||||
|
|
@ -205,7 +231,15 @@ describe('post actions', () => {
|
||||||
author: 'WIRED',
|
author: 'WIRED',
|
||||||
publicationDate: '2020-01-25T11:06:46Z',
|
publicationDate: '2020-01-25T11:06:46Z',
|
||||||
url: 'https://arstechnica.com/?p=1648757',
|
url: 'https://arstechnica.com/?p=1648757',
|
||||||
rule: 5,
|
rule: {
|
||||||
|
id: 5,
|
||||||
|
name: 'BBC',
|
||||||
|
url: 'http://feeds.bbci.co.uk/news/world/rss.xml',
|
||||||
|
favicon:
|
||||||
|
'https://m.files.bbci.co.uk/modules/bbc-morph-news-waf-page-meta/2.5.2/apple-touch-icon-57x57-precomposed.png',
|
||||||
|
category: 8,
|
||||||
|
unread: 632,
|
||||||
|
},
|
||||||
read: false,
|
read: false,
|
||||||
saved: false,
|
saved: false,
|
||||||
},
|
},
|
||||||
|
|
@ -218,7 +252,15 @@ describe('post actions', () => {
|
||||||
author: null,
|
author: null,
|
||||||
publicationDate: '2020-01-29T19:08:25Z',
|
publicationDate: '2020-01-29T19:08:25Z',
|
||||||
url: 'https://www.bbc.co.uk/news/world-asia-china-51299195',
|
url: 'https://www.bbc.co.uk/news/world-asia-china-51299195',
|
||||||
rule: 4,
|
rule: {
|
||||||
|
id: 4,
|
||||||
|
name: 'BBC',
|
||||||
|
url: 'http://feeds.bbci.co.uk/news/world/rss.xml',
|
||||||
|
favicon:
|
||||||
|
'https://m.files.bbci.co.uk/modules/bbc-morph-news-waf-page-meta/2.5.2/apple-touch-icon-57x57-precomposed.png',
|
||||||
|
category: 8,
|
||||||
|
unread: 321,
|
||||||
|
},
|
||||||
read: false,
|
read: false,
|
||||||
saved: false,
|
saved: false,
|
||||||
},
|
},
|
||||||
|
|
@ -231,7 +273,15 @@ describe('post actions', () => {
|
||||||
author: null,
|
author: null,
|
||||||
publicationDate: '2020-01-29T18:27:56Z',
|
publicationDate: '2020-01-29T18:27:56Z',
|
||||||
url: 'https://www.bbc.co.uk/news/world-europe-51294305',
|
url: 'https://www.bbc.co.uk/news/world-europe-51294305',
|
||||||
rule: 4,
|
rule: {
|
||||||
|
id: 4,
|
||||||
|
name: 'BBC',
|
||||||
|
url: 'http://feeds.bbci.co.uk/news/world/rss.xml',
|
||||||
|
favicon:
|
||||||
|
'https://m.files.bbci.co.uk/modules/bbc-morph-news-waf-page-meta/2.5.2/apple-touch-icon-57x57-precomposed.png',
|
||||||
|
category: 8,
|
||||||
|
unread: 321,
|
||||||
|
},
|
||||||
read: false,
|
read: false,
|
||||||
saved: false,
|
saved: false,
|
||||||
},
|
},
|
||||||
|
|
@ -245,7 +295,9 @@ describe('post actions', () => {
|
||||||
publicationDate: '2020-01-29T19:03:01Z',
|
publicationDate: '2020-01-29T19:03:01Z',
|
||||||
url:
|
url:
|
||||||
'https://tweakers.net/nieuws/162878/analyse-nintendo-verdiende-miljard-dollar-aan-mobiele-games.html',
|
'https://tweakers.net/nieuws/162878/analyse-nintendo-verdiende-miljard-dollar-aan-mobiele-games.html',
|
||||||
rule: 7,
|
rule: {
|
||||||
|
id: 7,
|
||||||
|
},
|
||||||
read: false,
|
read: false,
|
||||||
saved: false,
|
saved: false,
|
||||||
},
|
},
|
||||||
|
|
@ -259,7 +311,9 @@ describe('post actions', () => {
|
||||||
publicationDate: '2020-01-29T16:29:40Z',
|
publicationDate: '2020-01-29T16:29:40Z',
|
||||||
url:
|
url:
|
||||||
'https://tweakers.net/nieuws/162870/samsung-kondigt-eerste-tablet-met-5g-aan.html',
|
'https://tweakers.net/nieuws/162870/samsung-kondigt-eerste-tablet-met-5g-aan.html',
|
||||||
rule: 7,
|
rule: {
|
||||||
|
id: 7,
|
||||||
|
},
|
||||||
read: false,
|
read: false,
|
||||||
saved: false,
|
saved: false,
|
||||||
},
|
},
|
||||||
|
|
@ -276,7 +330,7 @@ describe('post actions', () => {
|
||||||
unread: 321,
|
unread: 321,
|
||||||
},
|
},
|
||||||
5: {
|
5: {
|
||||||
id: 4,
|
id: 5,
|
||||||
name: 'BBC',
|
name: 'BBC',
|
||||||
url: 'http://feeds.bbci.co.uk/news/world/rss.xml',
|
url: 'http://feeds.bbci.co.uk/news/world/rss.xml',
|
||||||
favicon:
|
favicon:
|
||||||
|
|
@ -301,18 +355,19 @@ describe('post actions', () => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const state = { ...defaultState, items: { ...posts } };
|
const state = { ...defaultState, items: Object.values(posts) };
|
||||||
|
|
||||||
const expectedState = {
|
const expectedState = {
|
||||||
...defaultState,
|
...defaultState,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
items: {
|
items: [
|
||||||
...posts,
|
{ ...posts[2067], read: true },
|
||||||
2067: { ...posts[2067], read: true },
|
{ ...posts[2141], read: true },
|
||||||
2141: { ...posts[2141], read: true },
|
{ ...posts[4589] },
|
||||||
4637: { ...posts[4637], read: true },
|
{ ...posts[4594] },
|
||||||
4638: { ...posts[4638], read: true },
|
{ ...posts[4637], read: true },
|
||||||
},
|
{ ...posts[4638], read: true },
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(reducer(state, action)).toEqual(expectedState);
|
expect(reducer(state, action)).toEqual(expectedState);
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
|
|
||||||
for post in data["results"]:
|
for post in data["results"]:
|
||||||
with self.subTest(post=post):
|
with self.subTest(post=post):
|
||||||
self.assertEqual(post["rule"], rule.pk)
|
self.assertEqual(post["rule"]["id"], rule.pk)
|
||||||
|
|
||||||
def test_unread_posts(self):
|
def test_unread_posts(self):
|
||||||
rule = FeedFactory.create(user=self.user)
|
rule = FeedFactory.create(user=self.user)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from newsreader.news.collection.serializers import RuleSerializer
|
||||||
from newsreader.news.core.models import Category, Post
|
from newsreader.news.core.models import Category, Post
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -9,6 +10,8 @@ class PostSerializer(serializers.ModelSerializer):
|
||||||
)
|
)
|
||||||
remoteIdentifier = serializers.CharField(source="remote_identifier", required=False)
|
remoteIdentifier = serializers.CharField(source="remote_identifier", required=False)
|
||||||
|
|
||||||
|
rule = RuleSerializer(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Post
|
model = Post
|
||||||
fields = (
|
fields = (
|
||||||
|
|
|
||||||
|
|
@ -510,8 +510,8 @@ class NestedCategoryPostView(TestCase):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(len(data["results"]), 2)
|
self.assertEqual(len(data["results"]), 2)
|
||||||
|
|
||||||
self.assertEqual(posts[0]["rule"], guardian_rule.pk)
|
self.assertEqual(posts[0]["rule"]["id"], guardian_rule.pk)
|
||||||
self.assertEqual(posts[1]["rule"], guardian_rule.pk)
|
self.assertEqual(posts[1]["rule"]["id"], guardian_rule.pk)
|
||||||
|
|
||||||
def test_unread_posts(self):
|
def test_unread_posts(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ class PostDetailViewTestCase(TestCase):
|
||||||
data=json.dumps({"title": "This title is very accurate"}),
|
data=json.dumps({"title": "This title is very accurate"}),
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
)
|
)
|
||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue