Skip to content

Commit

Permalink
fix: display research draft updates for author and admins (#3586)
Browse files Browse the repository at this point in the history
  • Loading branch information
mariojsnunes committed Jun 14, 2024
2 parents 460b1ce + 96ce744 commit c2c6fa2
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 80 deletions.
4 changes: 3 additions & 1 deletion packages/components/src/Icon/svgs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ export const iconMap = {
employee: <img alt="icon" style={imgStyle} src={employeeSVG} />,
flagUnknown: <img alt="alt" style={imgStyle} src={flagUnknownSVG} />,
hide: <img alt="icon" style={imgStyle} src={eyeCrossedSVG} />,
loading: <img alt="icon" style={imgStyle} src={loadingSVG} />,
loading: (
<img alt="icon" data-cy="icon-loading" style={imgStyle} src={loadingSVG} />
),
machine: <img alt="icon" style={imgStyle} src={machineSVG} />,
plastic: <img alt="icon" style={imgStyle} src={plasticSVG} />,
revenue: <img alt="icon" style={imgStyle} src={revenueSVG} />,
Expand Down
79 changes: 64 additions & 15 deletions packages/cypress/src/integration/research/write.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ describe('[Research]', () => {
cy.visit('/research')
})

const expected = {
_createdBy: 'research_creator',
_deleted: false,
description: 'After creating, the research will be deleted.',
title: 'Create research article test',
slug: 'create-research-article-test',
previousSlugs: ['create-research-article-test'],
status: 'In progress',
}

describe('[Create research article]', () => {
const expected = {
_createdBy: 'research_creator',
_deleted: false,
description: 'After creating, the research will be deleted.',
title: 'Create research article test',
slug: 'create-research-article-test',
previousSlugs: ['create-research-article-test'],
status: 'In progress',
}

it('[By Authenticated]', () => {
const updateTitle = 'Create a research update'
const updateDescription = 'This is the description for the update.'
Expand Down Expand Up @@ -264,14 +264,63 @@ describe('[Research]', () => {
cy.visit(editResearchUrl)
cy.get('[data-cy=BlockedRoute]').should('be.visible')
})
})

describe('[Displays draft updates for Author]', () => {
const expected = {
description: 'After creating, the research will be deleted.',
title: 'Create research article test 2',
slug: 'create-research-article-test-2',
}

it('[By Authenticated]', () => {
cy.step('Prevent non-owner access to edit research article')
const updateTitle = 'Create a research update 2'
const updateDescription = 'This is the description for the update.'
const updateVideoUrl = 'http://youtube.com/watch?v=sbcWY7t-JX8'

cy.login(researcherEmail, researcherPassword)

cy.step('Create the research article')
cy.visit('/research')
cy.login('research_editor@test.com', 'research_editor')
cy.visit(editResearchUrl)
// user should be redirect to research page
// cy.location('pathname').should('eq', researchUrl)
cy.get('[data-cy=loader]').should('not.exist')
cy.get('[data-cy=create]').click()

cy.step('Enter research article details')

cy.get('[data-cy=intro-title').clear().type(expected.title).blur()
cy.get('[data-cy=intro-description]').clear().type(expected.description)
cy.get('[data-cy=submit]').click()

cy.get('[data-cy=view-research]:enabled', { timeout: 20000 }).click()

cy.url().should('include', `/research/${expected.slug}`)
cy.visit(`/research/${expected.slug}`)

cy.step('Research article displays correctly')
cy.contains(expected.title)
cy.contains(expected.description)

cy.get('[data-cy=addResearchUpdateButton]').click()

cy.step('Enter update details')
cy.get('[data-cy=intro-title]').clear().type(updateTitle).blur()

cy.get('[data-cy=intro-description]')
.clear()
.type(updateDescription)
.blur()

cy.get('[data-cy=videoUrl]').clear().type(updateVideoUrl).blur()

cy.step('Save as Draft')
cy.get('[data-cy=draft]').click()

cy.step('Can see Draft after refresh')
cy.contains('Uploading Update').should('exist')
cy.get('[data-cy="icon-loading"]').should('not.exist')
cy.visit(`/research/${expected.slug}`)

cy.contains(updateTitle)
})
})
})
6 changes: 2 additions & 4 deletions src/pages/Research/Content/Common/ResearchUpdate.form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -473,10 +473,8 @@ export const ResearchUpdateForm = observer((props: IProps) => {
}}
>
<Button
data-cy={'draft'}
onClick={() => {
trySubmitForm(true)
}}
data-cy="draft"
onClick={() => trySubmitForm(true)}
variant="secondary"
type="submit"
disabled={submitting}
Expand Down
38 changes: 21 additions & 17 deletions src/pages/Research/Content/ResearchArticle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,24 @@ import {
UsefulStatsButton,
UserEngagementWrapper,
} from 'oa-components'
import { IModerationStatus, ResearchUpdateStatus } from 'oa-shared'
import { IModerationStatus } from 'oa-shared'
import { trackEvent } from 'src/common/Analytics'
import { useContributorsData } from 'src/common/hooks/contributorsData'
import { useCommonStores } from 'src/common/hooks/useCommonStores'
import { Breadcrumbs } from 'src/pages/common/Breadcrumbs/Breadcrumbs'
import { NotFoundPage } from 'src/pages/NotFound/NotFound'
import { useResearchStore } from 'src/stores/Research/research.store'
import {
getPublicUpdates,
getResearchTotalCommentCount,
isAllowedToDeleteContent,
isAllowedToEditContent,
} from 'src/utils/helpers'
import { seoTagsUpdate } from 'src/utils/seo'
import { Box, Flex } from 'theme-ui'

import {
getPublicUpdates,
researchUpdateStatusFilter,
} from '../researchHelpers'
import { researchCommentUrlPattern } from './helper'
import ResearchDescription from './ResearchDescription'
import ResearchUpdate from './ResearchUpdate'
Expand Down Expand Up @@ -215,25 +217,27 @@ const ResearchArticle = observer(() => {
onFollowClick={() => onFollowClick(item.slug)}
contributors={contributors}
subscribersCount={researchStore.subscribersCount}
commentsCount={getResearchTotalCommentCount(item)}
commentsCount={item.totalCommentCount}
updatesCount={
item.updates?.filter(
(u) => u.status !== ResearchUpdateStatus.DRAFT && !u._deleted,
item.updates?.filter((u) =>
researchUpdateStatusFilter(item, u, researchStore.activeUser),
).length || 0
}
/>
<Box sx={{ marginTop: 8, marginBottom: 4 }}>
{item &&
getPublicUpdates(item).map((update, index) => (
<ResearchUpdate
update={update}
key={update._id}
updateIndex={index}
isEditable={isEditable}
slug={item.slug}
showComments={areCommentVisible(index)}
/>
))}
getPublicUpdates(item, researchStore.activeUser).map(
(update, index) => (
<ResearchUpdate
update={update}
key={update._id}
updateIndex={index}
isEditable={isEditable}
slug={item.slug}
showComments={areCommentVisible(index)}
/>
),
)}
</Box>

<UserEngagementWrapper>
Expand Down Expand Up @@ -267,7 +271,7 @@ const ResearchArticle = observer(() => {
isLoggedIn={!!loggedInUser}
hasUserSubscribed={researchStore.userHasSubscribed}
onFollowClick={() => onFollowClick(item.slug)}
></FollowButton>
/>
</ArticleCallToAction>
)}
</Box>
Expand Down
3 changes: 2 additions & 1 deletion src/pages/Research/Content/ResearchDescription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ import { IModerationStatus } from 'oa-shared'
import { trackEvent } from 'src/common/Analytics'
import { logger } from 'src/logger'
import { useResearchStore } from 'src/stores/Research/research.store'
import { buildStatisticsLabel, researchStatusColour } from 'src/utils/helpers'
import { buildStatisticsLabel } from 'src/utils/helpers'
import { incrementViewCount } from 'src/utils/incrementViewCount'
import { Box, Card, Divider, Flex, Heading, Text } from 'theme-ui'

import { ContentAuthorTimestamp } from '../../common/ContentAuthorTimestamp/ContentAuthorTimestamp'
import { researchStatusColour } from '../researchHelpers'

import type { ITag } from 'src/models'
import type { IResearch } from 'src/models/research.models'
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Research/Content/ResearchListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import {
import { useCommonStores } from 'src/common/hooks/useCommonStores'
import { cdnImageUrl } from 'src/utils/cdnImageUrl'
import { formatDate } from 'src/utils/date'
import { getPublicUpdates, researchStatusColour } from 'src/utils/helpers'
import { Box, Card, Flex, Grid, Heading, Image, Text } from 'theme-ui'

import defaultResearchThumbnail from '../../../assets/images/default-research-thumbnail.jpg'
import { getPublicUpdates, researchStatusColour } from '../researchHelpers'

import type { IResearch } from 'src/models/research.models'
import type { IUploadedFileMeta } from 'src/stores/storage'
Expand Down
119 changes: 119 additions & 0 deletions src/pages/Research/researchHelpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { ResearchUpdateStatus, UserRole } from 'oa-shared'
import { describe, expect, it } from 'vitest'

import { researchUpdateStatusFilter } from './researchHelpers'

import type { IResearch, IUserPPDB } from 'src/models'

describe('Research Helpers', () => {
describe('Research Update Status Filter', () => {
it('should not show item when deleted', async () => {
// prepare
const user = { _id: 'author' } as IUserPPDB
const item = { _createdBy: user._id } as IResearch.Item
const update = { _deleted: true } as IResearch.Update

// act
const show = researchUpdateStatusFilter(item, update, user)

// assert
expect(show).toEqual(false)
})

it('should not show item when deleted and draft', async () => {
// prepare
const user = { _id: 'author' } as IUserPPDB
const item = { _createdBy: user._id } as IResearch.Item
const update = {
_deleted: true,
status: ResearchUpdateStatus.DRAFT,
} as IResearch.Update

// act
const show = researchUpdateStatusFilter(item, update, user)

// assert
expect(show).toEqual(false)
})

it('should not show when draft and not author', async () => {
// prepare
const user = { _id: 'non-author' } as IUserPPDB
const item = { _createdBy: 'author' } as IResearch.Item
const update = { status: ResearchUpdateStatus.DRAFT } as IResearch.Update

// act
const show = researchUpdateStatusFilter(item, update, user)

// assert
expect(show).toEqual(false)
})

it('should not show when draft and not authenticated', async () => {
// prepare
const user = { _id: 'author' } as IUserPPDB
const item = { _createdBy: user._id } as IResearch.Item
const update = { status: ResearchUpdateStatus.DRAFT } as IResearch.Update

// act
const show = researchUpdateStatusFilter(item, update)

// assert
expect(show).toEqual(false)
})

it('should show when not draft and not deleted', async () => {
// prepare
const user = { _id: 'author' } as IUserPPDB
const item = { _createdBy: user._id } as IResearch.Item
const update = {
status: ResearchUpdateStatus.PUBLISHED,
} as IResearch.Update

// act
const show = researchUpdateStatusFilter(item, update)

// assert
expect(show).toEqual(true)
})

it('should show when draft and current user is the author', async () => {
// prepare
const user = { _id: 'author' } as IUserPPDB
const item = { _createdBy: user._id } as IResearch.Item
const update = { status: ResearchUpdateStatus.DRAFT } as IResearch.Update

// act
const show = researchUpdateStatusFilter(item, update, user)

// assert
expect(show).toEqual(true)
})

it('should show when draft and current user is a collaborator', async () => {
// prepare
const user = { _id: 'author' } as IUserPPDB
const item = { collaborators: [user._id] } as IResearch.Item
const update = { status: ResearchUpdateStatus.DRAFT } as IResearch.Update

// act
const show = researchUpdateStatusFilter(item, update, user)

// assert
expect(show).toEqual(true)
})

it('should show when draft and current user is an Admin', async () => {
// prepare
const user = { _id: 'admin', userRoles: [UserRole.ADMIN] } as IUserPPDB
const item = {} as IResearch.Item
const update = { status: ResearchUpdateStatus.DRAFT } as IResearch.Update

// act
const show = researchUpdateStatusFilter(item, update, user)

// assert
expect(show).toEqual(true)
})
})
})
47 changes: 47 additions & 0 deletions src/pages/Research/researchHelpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ResearchStatus, ResearchUpdateStatus, UserRole } from 'oa-shared'

import type { IResearch, IUserPPDB } from 'src/models'

export const researchUpdateStatusFilter = (
item: IResearch.Item,
update: IResearch.Update,
currentUser?: IUserPPDB | null,
) => {
const isCollaborator =
currentUser?._id &&
item.collaborators &&
item.collaborators.includes(currentUser?._id)

const isAuthor = item._createdBy === currentUser?._id
const isAdmin = currentUser?.userRoles?.includes(UserRole.ADMIN)
const isUpdateDraft = update.status === ResearchUpdateStatus.DRAFT
const isUpdateDeleted = update._deleted

return (
(isAdmin || isAuthor || isCollaborator || !isUpdateDraft) &&
!isUpdateDeleted
)
}

export const getPublicUpdates = (
item: IResearch.Item,
currentUser?: IUserPPDB | null,
) => {
if (item.updates) {
return item.updates.filter((update) =>
researchUpdateStatusFilter(item, update, currentUser),
)
} else {
return []
}
}

export const researchStatusColour = (
researchStatus?: ResearchStatus,
): string => {
return researchStatus === ResearchStatus.ARCHIVED
? 'lightgrey'
: researchStatus === ResearchStatus.COMPLETED
? 'betaGreen'
: 'accent.base'
}
Loading

0 comments on commit c2c6fa2

Please sign in to comment.