Skip to content

Commit

Permalink
implement multiple authors to articles and assign other user as autho…
Browse files Browse the repository at this point in the history
…rs and refactor some code
  • Loading branch information
jonasdeluna committed Feb 28, 2023
1 parent 20d1da9 commit b962f02
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 106 deletions.
100 changes: 45 additions & 55 deletions app/components/Form/ObjectPermissions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { SelectInput, CheckBox } from 'app/components/Form';
import Tooltip from 'app/components/Tooltip';
import type { PublicGroup } from 'app/store/models/Group';

/*
* Usage inside redux-form:
Expand All @@ -24,12 +25,14 @@ const ObjectPermissions = ({
canEditGroups,
canViewGroups,
requireAuth,
authors,
...props
}: {
canEditUsers?: any;
canEditGroups?: any;
canViewGroups?: any;
requireAuth?: any;
canEditUsers?: PublicGroup[];
canEditGroups?: PublicGroup[];
canViewGroups?: PublicGroup[];
requireAuth?: boolean;
authors?: number[];
}) => {
return [
requireAuth && (
Expand All @@ -41,6 +44,15 @@ const ObjectPermissions = ({
/>
</Tooltip>
),
authors && (
<SelectInput.AutocompleteField
{...authors}
label="Forfattere"
isMulti
placeholder="Velg forfattere"
filter={['users.user']}
/>
),
canEditGroups && (
<SelectInput.AutocompleteField
{...canEditGroups}
Expand Down Expand Up @@ -78,73 +90,51 @@ export const normalizeObjectPermissions = ({
canViewGroups: initialCanViewGroups,
canEditGroups: initialCanEditGroups,
canEditUsers: initialCanEditUsers,
authors: initialAuthors,
currentUser: currentUser,
}: Record<string, any>) => {
const canEditUsers = initialCanEditUsers && initialCanEditUsers.map(toIds);
const canViewGroups = initialCanViewGroups && initialCanViewGroups.map(toIds);
const canEditGroups = initialCanEditGroups && initialCanEditGroups.map(toIds);
const authors = initialAuthors?.length
? initialAuthors?.map(toIds)
: [currentUser.id];

return {
requireAuth: !!requireAuth,
...(canEditUsers
? {
canEditUsers,
}
: {}),
//$FlowFixMe
...(canEditGroups
? {
canEditGroups,
}
: {}),
...(canViewGroups
? {
canViewGroups,
}
: {}),
canEditUsers: initialCanEditUsers?.map(toIds) ?? {},
canViewGroups: initialCanViewGroups?.map(toIds) ?? {},
canEditGroups: initialCanEditGroups?.map(toIds) ?? {},
authors: authors,
};
};
export const objectPermissionsToInitialValues = ({
export const objectToInitialValues = ({
canViewGroups: initialCanViewGroups,
canEditGroups: initialCanEditGroups,
canEditUsers: initialCanEditUsers,
authors: initialAuthors,
}: Record<string, any>) => {
const canEditGroups =
initialCanEditGroups &&
initialCanEditGroups
.filter(Boolean)
.map((group) => ({ ...group, label: group.name, value: group.id }));
const canViewGroups =
initialCanViewGroups &&
initialCanViewGroups
.filter(Boolean)
.map((group) => ({ ...group, label: group.name, value: group.id }));
const canEditUsers =
initialCanEditUsers &&
initialCanEditUsers
.filter(Boolean)
.map((user) => ({ ...user, label: user.fullName, value: user.id }));
const canEditGroups = initialCanEditGroups
?.filter(Boolean)
.map((group) => ({ ...group, label: group.name, value: group.id }));
const canViewGroups = initialCanViewGroups
?.filter(Boolean)
.map((group) => ({ ...group, label: group.name, value: group.id }));
const canEditUsers = initialCanEditUsers
?.filter(Boolean)
.map((user) => ({ ...user, label: user.fullName, value: user.id }));
const authors = initialAuthors
?.filter(Boolean)
.map((user) => ({ ...user, label: user.fullName, value: user.id }));
return {
...(canEditUsers
? {
canEditUsers,
}
: {}),
//$FlowFixMe
...(canEditGroups
? {
canEditGroups,
}
: {}),
...(canViewGroups
? {
canViewGroups,
}
: {}),
canEditUsers: canEditUsers ?? {},
canEditGroups: canEditGroups ?? {},
canViewGroups: canViewGroups ?? {},
authors: authors ?? {},
};
};
export const objectPermissionsInitialValues = {
requireAuth: true,
canEditUsers: [],
canEditGroups: [],
canViewGroups: [],
authors: [],
};
export default ObjectPermissions;
3 changes: 2 additions & 1 deletion app/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ export const reactionSchema = new schema.Entity('reactions');
export const articleSchema = new schema.Entity('articles', {
comments: [commentSchema],
reactions: [reactionSchema],
author: userSchema,
authors: [userSchema],
});

export const galleryPictureSchema = new schema.Entity('galleryPictures', {
comments: [commentSchema],
});
Expand Down
1 change: 1 addition & 0 deletions app/reducers/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const selectUserById = createSelector(
(state, props) => props.userId,
(usersById, userId) => usersById[userId] || {}
);

export const selectUserByUsername = createSelector(
(state) => state.users.byId,
(state, props) => props.username,
Expand Down
25 changes: 17 additions & 8 deletions app/routes/articles/ArticleCreateRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,26 @@ import { compose } from 'redux';
import { createArticle } from 'app/actions/ArticleActions';
import { uploadFile } from 'app/actions/FileActions';
import { LoginPage } from 'app/components/LoginForm';
import { selectCurrentUser } from 'app/reducers/auth';
import replaceUnlessLoggedIn from 'app/utils/replaceUnlessLoggedIn';
import ArticleEditor from './components/ArticleEditor';

const mapStateToProps = () => ({
isNew: true,
article: {},
initialValues: {
content: '',
},
});

const mapStateToProps = (state, props) => {
const currentUser = selectCurrentUser(state);
const authors = [currentUser];
return {
isNew: true,
article: {},
initialValues: {
content: '',
authors: authors.map((user) => ({
...user,
label: user.fullName,
value: user.id,
})),
},
};
};
const mapDispatchToProps = {
submitArticle: createArticle,
uploadFile,
Expand Down
14 changes: 8 additions & 6 deletions app/routes/articles/ArticleDetailRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ const mapStateToProps = (state, props) => {
const comments = selectCommentsForArticle(state, {
articleId,
});
const author = selectUserById(state, {
userId: article.author,
const authors = article?.authors?.map((e) => {
return selectUserById(state, {
userId: e,
});
});
const emojis = selectEmojis(state);
return {
Expand All @@ -35,7 +37,7 @@ const mapStateToProps = (state, props) => {
comments,
article,
articleId,
author,
authors,
emojis,
};
};
Expand All @@ -56,7 +58,7 @@ export default compose(
),
connect(mapStateToProps, mapDispatchToProps),
loadingIndicator(['article.content']),
helmet((props: { article: PublicArticle; author: PublicUser }, config) => {
helmet((props: { article: PublicArticle; authors: PublicUser }, config) => {
const tags = props.article.tags.map((content) => ({
content,
property: 'article:tag',
Expand Down Expand Up @@ -104,8 +106,8 @@ export default compose(
content: props.article.description,
},
{
property: 'article:author',
content: `${config.webUrl}/users/${props.author.username}`,
property: 'article:authors',
content: `${config.webUrl}/users/${props.authors.username}`,
},
...tags,
];
Expand Down
17 changes: 15 additions & 2 deletions app/routes/articles/ArticleEditRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
editArticle,
deleteArticle,
} from 'app/actions/ArticleActions';
import { objectPermissionsToInitialValues } from 'app/components/Form/ObjectPermissions';
import { objectToInitialValues } from 'app/components/Form/ObjectPermissions';
import { LoginPage } from 'app/components/LoginForm';
import { selectArticleById } from 'app/reducers/articles';
import { selectCurrentUser } from 'app/reducers/auth';
import { selectUserById } from 'app/reducers/users';
import loadingIndicator from 'app/utils/loadingIndicator';
import replaceUnlessLoggedIn from 'app/utils/replaceUnlessLoggedIn';
import withPreparedDispatch from 'app/utils/withPreparedDispatch';
Expand All @@ -19,13 +21,24 @@ const mapStateToProps = (state, props) => {
const article = selectArticleById(state, {
articleId,
});

const currentUser = selectCurrentUser(state);
const authors = article?.authors?.length
? article.authors.map((e) => selectUserById(state, { userId: e }))
: [currentUser];

return {
article,
articleId,
isNew: false,
initialValues: {
...article,
...objectPermissionsToInitialValues(article),
...objectToInitialValues({
canViewGroups: article.canViewGroups,
canEditGroups: article.canEditGroups,
canEditUsers: article.canEditUsers,
authors: authors,
}),
tags: (article.tags || []).map((tag) => ({
label: tag,
value: tag,
Expand Down
10 changes: 6 additions & 4 deletions app/routes/articles/ArticleListRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import type { PublicUser } from 'app/store/models/User';
import withPreparedDispatch from 'app/utils/withPreparedDispatch';
import Overview from './components/Overview';

export type ArticleWithAuthorDetails = Omit<PublicArticle, 'author'> & {
author: PublicUser;
export type ArticleWithAuthorDetails = Omit<PublicArticle, 'authors'> & {
authors: Array<PublicUser>;
};

const mapStateToProps = (state, props) => {
Expand All @@ -34,8 +34,10 @@ const mapStateToProps = (state, props) => {
}
).map((article) => ({
...article,
author: selectUserById(state, {
userId: article.author,
authors: article?.authors?.map((e) => {
return selectUserById(state, {
userId: e,
});
}),
}));

Expand Down
40 changes: 27 additions & 13 deletions app/routes/articles/components/ArticleDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ type Props = {
article: DetailedArticle | AdminDetailedArticle;
comments: Comment[];
loggedIn: boolean;
author: DetailedUser;
authors: DetailedUser[];
currentUser: CurrentUser;
deleteComment: (id: ID, contentTarget: string) => Promise<void>;
emojis: Array<EmojiEntity>;
addReaction: (arg0: {
emoji: string;
contentTarget: string;
}) => Promise<unknown>;
reactionsGrouped: Array<ReactionEntity>;
reactionsGrouped: ReactionEntity[];
deleteReaction: (arg0: {
reactionId: ID;
contentTarget: string;
Expand All @@ -41,7 +41,7 @@ type Props = {

const ArticleDetail = ({
article,
author,
authors,
loggedIn,
currentUser,
comments,
Expand Down Expand Up @@ -70,16 +70,30 @@ const ArticleDetail = ({
)}
</NavigationTab>

<div className={styles.articleDetails}>
<span className={styles.detail}>
Skrevet av
<Link to={`/users/${author.username}`}> {author.fullName}</Link>
</span>
<span className={styles.detail}>
{moment(article.createdAt).format('lll')}
</span>
</div>

{
<div className={styles.articleDetails}>
<span className={styles.detail}>
Skrevet av{' '}
{authors?.map((e, i) => {
return (
<span key={e.username}>
<Link
to={`/users/${e.username}`}
className={styles.overviewAuthor}
>
{' '}
{e.fullName}
</Link>
{i === authors.length - 1 ? '' : ','}
</span>
);
})}
</span>
<span className={styles.detail}>
{moment(article.createdAt).format('lll')}
</span>
</div>
}
<DisplayContent content={article.content} />

<Tags>
Expand Down
5 changes: 3 additions & 2 deletions app/routes/articles/components/ArticleEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ const ArticleEditor = ({
'canViewGroups',
'canEditUsers',
'canEditGroups',
'authors',
]}
component={ObjectPermissions}
/>
Expand Down Expand Up @@ -189,15 +190,15 @@ const onSubmit = (
cover: data.cover,
}
: {}),
...normalizeObjectPermissions(data),
...normalizeObjectPermissions({ ...data, currentUser: currentUser }),
youtubeUrl: data.youtubeUrl,
title: data.title,
author: currentUser.id,
description: data.description,
content: data.content,
tags: (data.tags || []).map((tag) => tag.value.toLowerCase()),
pinned: data.pinned,
};

return submitArticle(body);
};

Expand Down

0 comments on commit b962f02

Please sign in to comment.