Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stories moderation #2928

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/commons/application/ApplicationTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,12 @@ export const defaultSession: SessionState = {
};

export const defaultStories: StoriesState = {
storyList: [],
storyLists: {
draft: [],
pending: [],
rejected: [],
published: []
},
currentStoryId: null,
currentStory: null,
envs: {}
Expand Down
43 changes: 38 additions & 5 deletions src/commons/sagas/StoriesSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import {
postStory,
updateStory
} from 'src/features/stories/storiesComponents/BackendAccess';
import { StoryData, StoryListView, StoryView } from 'src/features/stories/StoriesTypes';
import {
StoryData,
StoryListView,
StoryListViews,
StoryStatus,
StoryView
} from 'src/features/stories/StoriesTypes';

import { OverallState, StoriesRole } from '../application/ApplicationTypes';
import { Tokens } from '../application/types/SessionTypes';
Expand All @@ -25,11 +31,34 @@ const StoriesSaga = combineSagaHandlers(StoriesActions, {
// TODO: This should be using `takeLatest`, not `takeEvery`
getStoriesList: function* () {
const tokens: Tokens = yield selectTokens();
const allStories: StoryListView[] = yield call(async () => {
const resp = await getStories(tokens);

const draftStories: StoryListView[] = yield call(async () => {
const resp = await getStories(tokens, StoryStatus.Draft);
return resp ?? [];
});

const pendingStories: StoryListView[] = yield call(async () => {
const resp = await getStories(tokens, StoryStatus.Pending);
return resp ?? [];
});

const rejectedStories: StoryListView[] = yield call(async () => {
const resp = await getStories(tokens, StoryStatus.Rejected);
return resp ?? [];
});

const publishedStories: StoryListView[] = yield call(async () => {
const resp = await getStories(tokens, StoryStatus.Published);
return resp ?? [];
});

const allStories: StoryListViews = {
draft: draftStories,
pending: pendingStories,
rejected: rejectedStories,
published: publishedStories
};
Comment on lines +34 to +60
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This design doesn't look right to me. To the user/the frontend, the "listing" of stories should be transparent.

In other words, the FE just makes one "list stories" query, and the backend returns a list of stories that the user has access to. The permissions/different types of stories should be transparent and the frontend can subsequently later filter the story by the status. You are adding a status field inside the story model in the backend but it's not being utilised here at all.


yield put(actions.updateStoriesList(allStories));
},
setCurrentStoryId: function* (action) {
Expand All @@ -42,7 +71,9 @@ const StoriesSaga = combineSagaHandlers(StoriesActions, {
const defaultStory: StoryData = {
title: '',
content: defaultStoryContent,
pinOrder: null
pinOrder: null,
status: StoryStatus.Draft,
statusMessage: ''
};
yield put(actions.setCurrentStory(defaultStory));
}
Expand Down Expand Up @@ -82,7 +113,9 @@ const StoriesSaga = combineSagaHandlers(StoriesActions, {
id,
story.title,
story.content,
story.pinOrder
story.pinOrder,
story.status,
story.statusMessage
);

// TODO: Check correctness
Expand Down
4 changes: 2 additions & 2 deletions src/features/stories/StoriesActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
SET_CURRENT_STORIES_GROUP,
SET_CURRENT_STORIES_USER,
StoryData,
StoryListView,
StoryListViews,
StoryParams
} from './StoriesTypes';

Expand All @@ -31,7 +31,7 @@ const newActions = createActions('stories', {

// New action creators post-refactor
getStoriesList: () => ({}),
updateStoriesList: (storyList: StoryListView[]) => storyList,
updateStoriesList: (storyLists: StoryListViews) => storyLists,
setCurrentStory: (story: StoryData | null) => story,
setCurrentStoryId: (id: number | null) => id,
createStory: (story: StoryParams) => story,
Expand Down
2 changes: 1 addition & 1 deletion src/features/stories/StoriesReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const newStoriesReducer = createReducer(defaultStories, builder => {
})
// New cases post-refactor
.addCase(updateStoriesList, (state, action) => {
state.storyList = action.payload;
state.storyLists = action.payload;
})
.addCase(setCurrentStoryId, (state, action) => {
state.currentStoryId = action.payload;
Expand Down
18 changes: 17 additions & 1 deletion src/features/stories/StoriesTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,19 @@ export type StoryData = {
title: string;
content: string;
pinOrder: number | null;
status: StoryStatus;
statusMessage: string;
};

export type StoryParams = StoryData;

export enum StoryStatus {
Draft = 0,
Pending,
Rejected,
Published
}
Comment on lines +28 to +33
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, enum values should be UPPER_SNAKE_CASE (e.g. DRAFT)


export type StoryListView = StoryData &
StoryMetadata & {
id: number;
Expand Down Expand Up @@ -53,8 +62,15 @@ export type StoriesAuthState = {
readonly role?: StoriesRole;
};

export type StoryListViews = {
readonly draft: StoryListView[];
readonly pending: StoryListView[];
readonly rejected: StoryListView[];
readonly published: StoryListView[];
};

export type StoriesState = {
readonly storyList: StoryListView[];
readonly storyLists: StoryListViews;
readonly currentStoryId: number | null;
readonly currentStory: StoryData | null;
readonly envs: { [key: string]: StoriesEnvState };
Expand Down
26 changes: 21 additions & 5 deletions src/features/stories/storiesComponents/BackendAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { store } from 'src/pages/createStore';

import { Tokens } from '../../../commons/application/types/SessionTypes';
import { NameUsernameRole } from '../../../pages/academy/adminPanel/subcomponents/AddStoriesUserPanel';
import { StoryListView, StoryView } from '../StoriesTypes';
import { StoryListView, StoryStatus, StoryView } from '../StoriesTypes';

// Helpers

Expand Down Expand Up @@ -75,8 +75,22 @@ export const postNewStoriesUsers = async (
// TODO: Return response JSON directly.
};

export const getStories = async (tokens: Tokens): Promise<StoryListView[] | null> => {
const resp = await requestStoryBackend(`/groups/${getStoriesGroupId()}/stories`, 'GET', {
export const getStories = async (
tokens: Tokens,
status: StoryStatus | null = null
): Promise<StoryListView[] | null> => {
const route =
status === StoryStatus.Draft
? '/draft'
: status === StoryStatus.Pending
? '/pending'
: status === StoryStatus.Rejected
? '/rejected'
: status === StoryStatus.Published
? '/published'
: '';
Comment on lines +83 to +91
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filters are generally done using a query parameter instead of a different route/path (which would conventionally mean a different resource.)


const resp = await requestStoryBackend(`/groups/${getStoriesGroupId()}/stories${route}`, 'GET', {
...tokens
});
if (!resp) {
Expand Down Expand Up @@ -124,10 +138,12 @@ export const updateStory = async (
id: number,
title: string,
content: string,
pinOrder: number | null
pinOrder: number | null,
status: StoryStatus,
statusMessage: string
): Promise<StoryView | null> => {
const resp = await requestStoryBackend(`/groups/${getStoriesGroupId()}/stories/${id}`, 'PUT', {
body: { title, content, pinOrder },
body: { title, content, pinOrder, status, statusMessage },
...tokens
});
if (!resp) {
Expand Down
Loading
Loading