Skip to content

Commit

Permalink
Merge pull request #335 from cofacts/contributors
Browse files Browse the repository at this point in the history
Add article contributors
  • Loading branch information
MrOrz committed May 2, 2024
2 parents 4db9ec1 + 625fbb1 commit 0b486ac
Show file tree
Hide file tree
Showing 13 changed files with 270 additions and 60 deletions.
58 changes: 15 additions & 43 deletions src/graphql/__tests__/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ if (process.env.GCS_BUCKET_NAME) {
createdAt,
// eslint-disable-next-line no-unused-vars
updatedAt,
text,
...aiResponse
} = await createTranscript(
{
Expand All @@ -130,50 +131,21 @@ if (process.env.GCS_BUCKET_NAME) {
{ id: 'user-id', appId: 'app-id' }
);

// Expect some keywords are identified.
// The whole text are not always 100% identical, but these keywords should be always included.
expect(text).toMatch(/^排/);
expect(text).toMatch(/德國醫學博士艾倫斯特發現/);
expect(text).toMatch(/汗也具有調節體溫的重要作用/);
expect(aiResponse).toMatchInlineSnapshot(`
Object {
"appId": "app-id",
"docId": "foo",
"status": "SUCCESS",
"text": "排
汗和排尿的差別
想要健康長壽就要想辦法一天一次大量排汗
德國醫學博士艾倫斯特發現:所有運動選手中
唯獨馬拉松選手沒有罹患癌症病例。
艾倫斯特博士採集了每天跑步 30 公里以上的
馬拉松選手的汗水,分析其汗水的成份結果
發現汗水中含有 鎘 鉛銅鎳等之重金屬物質。
證明出汗是排泄體內疲勞物質及對人體有害的
重金屬毒素的重要途徑
雖然排泄體內不需要物質的基本功能,有排便
排尿與出汗。而尿也會排出重金屬,但是排出
功能卻遠不及汗。
汗與尿中的重金屬元素量
鉛(微克)鎘(微克)鈷(微克)
6.5
1.2
0.65
0.6
汗 84
尿 4.9
100 克 中〉
鎳(微克)銅(毫克)
32
0.11
3.1
0.01
汗也具有調節體溫的重要作用。 全身健康的
出汗,就能夠強化現代最欠缺的體溫調節功能
與自律神經。
藉著汗,氣化熱消耗熱量,能夠提升代謝力,
不但減少體脂肪,還有助於消除肥胖。
可以先從關掉冷氣做起
",
"type": "TRANSCRIPT",
"userId": "user-id",
}
`);
Object {
"appId": "app-id",
"docId": "foo",
"status": "SUCCESS",
"type": "TRANSCRIPT",
"userId": "user-id",
}
`);

// Cleanup
await client.delete({
index: 'airesponses',
Expand Down
23 changes: 23 additions & 0 deletions src/graphql/models/Article.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import Hyperlink from './Hyperlink';
import ReplyRequest from './ReplyRequest';
import ArticleTypeEnum from './ArticleTypeEnum';
import Cooccurrence from './Cooccurrence';
import Contributor from './Contributor';

const ATTACHMENT_URL_DURATION_DAY = 1;

Expand Down Expand Up @@ -580,6 +581,28 @@ const Article = new GraphQLObjectType({
},
}),
},
contributors: {
type: new GraphQLNonNull(
new GraphQLList(new GraphQLNonNull(Contributor))
),
description: 'Transcript contributors of the article',
resolve: ({ contributors }) => contributors ?? [],
},
transcribedAt: {
type: GraphQLString,
description: 'Time when the article was last transcribed',
resolve: async ({ contributors }) => {
if (!contributors || contributors.length === 0) {
return null;
}
const maxUpdatedAt = new Date(
Math.max(
...contributors.map(contributor => new Date(contributor.updatedAt))
)
);
return maxUpdatedAt.toISOString();
},
},
}),
});

Expand Down
16 changes: 16 additions & 0 deletions src/graphql/models/Contributor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { GraphQLObjectType, GraphQLString, GraphQLNonNull } from 'graphql';
import User, { userFieldResolver } from './User';

export default new GraphQLObjectType({
name: 'Contributor',
fields: () => ({
user: {
type: User,
description: 'The user who contributed to this article.',
resolve: userFieldResolver,
},
userId: { type: GraphQLNonNull(GraphQLString) },
appId: { type: GraphQLNonNull(GraphQLString) },
updatedAt: { type: GraphQLString },
}),
});
1 change: 1 addition & 0 deletions src/graphql/mutations/CreateArticle.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ async function createNewArticle({ text, reference: originalReference, user }) {
attachmentUrl: '',
attachmentHash: '',
status: getContentDefaultStatus(user),
contributors: [],
},
},
refresh: 'true', // Make sure the data is indexed when we create ReplyRequest
Expand Down
1 change: 1 addition & 0 deletions src/graphql/mutations/CreateMediaArticle.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ async function createNewMediaArticle({
articleType,
attachmentHash,
status: getContentDefaultStatus(user),
contributors: [],
},
});

Expand Down
1 change: 1 addition & 0 deletions src/graphql/mutations/__tests__/CreateMediaArticle.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ describe('creation', () => {
"articleReplies": Array [],
"articleType": "IMAGE",
"attachmentHash": "mock_image_hash",
"contributors": Array [],
"createdAt": "2017-01-28T08:45:57.011Z",
"hyperlinks": Array [],
"lastRequestedAt": "2017-01-28T08:45:57.011Z",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Object {
"articleType": "TEXT",
"attachmentHash": "",
"attachmentUrl": "",
"contributors": Array [],
"createdAt": "2017-01-28T08:45:57.011Z",
"hyperlinks": Array [
Object {
Expand Down
39 changes: 23 additions & 16 deletions src/graphql/queries/ListArticles.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
intRangeInput,
timeRangeInput,
moreLikeThisInput,
userAndExistInput,
getRangeFieldParamFromArithmeticExpression,
createCommonListFilter,
attachCommonListFilter,
Expand Down Expand Up @@ -136,22 +137,12 @@ export default {
articleRepliesFrom: {
description:
'Show only articles with(out) article replies created by specified user',
type: new GraphQLInputObjectType({
name: 'UserAndExistInput',
fields: {
userId: {
type: new GraphQLNonNull(GraphQLString),
},
exists: {
type: GraphQLBoolean,
defaultValue: true,
description: `
When true (or not specified), return only entries with the specified user's involvement.
When false, return only entries that the specified user did not involve.
`,
},
},
}),
type: userAndExistInput,
},
transcribedBy: {
description:
'Show only articles with(out) article transcript contributed by specified user',
type: userAndExistInput,
},
hasArticleReplyWithMorePositiveFeedback: {
type: GraphQLBoolean,
Expand Down Expand Up @@ -548,6 +539,22 @@ export default {
});
}

if (filter.transcribedBy) {
(filter.transcribedBy.exists === false
? mustNotQueries
: filterQueries
).push({
nested: {
path: 'contributors',
query: {
term: {
'contributors.userId': filter.transcribedBy.userId,
},
},
},
});
}

if (filter.replyTypes) {
filterQueries.push({
nested: {
Expand Down
29 changes: 29 additions & 0 deletions src/graphql/queries/__fixtures__/ListArticles.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,28 @@ export default {
negativeFeedbackCount: 0,
},
],
contributors: [
{
userId: 'user1',
appId: 'WEBSITE',
updatedAt: '2020-02-05T14:41:19.044Z',
},
{
userId: 'user2',
appId: 'WEBSITE',
updatedAt: '2020-02-09T14:41:19.044Z',
},
{
userId: 'user3',
appId: 'WEBSITE',
updatedAt: '2020-02-08T14:41:19.044Z',
},
{
userId: 'user4',
appId: 'WEBSITE',
updatedAt: '2020-02-07T14:41:19.044Z',
},
],
attachmentUrl: '',
attachmentHash: '',
articleType: 'TEXT',
Expand Down Expand Up @@ -105,6 +127,13 @@ export default {
negativeFeedbackCount: 0,
},
],
contributors: [
{
userId: 'user1',
appId: 'WEBSITE',
updatedAt: '2020-02-04T15:11:04.472Z',
},
],
attachmentUrl: '',
attachmentHash: '',
articleType: 'TEXT',
Expand Down
44 changes: 44 additions & 0 deletions src/graphql/queries/__tests__/ListArticles.js
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,50 @@ describe('ListArticles', () => {
).toMatchSnapshot('do not have articleReply from user1');
});

it('filters via transcribedBy', async () => {
expect(
await gql`
{
ListArticles(filter: { transcribedBy: { userId: "user1" } }) {
edges {
node {
id
contributors {
user {
id
}
}
transcribedAt
}
}
}
}
`({}, { appId: 'WEBSITE' })
).toMatchSnapshot('transcribedBy user1');

expect(
await gql`
{
ListArticles(
filter: { transcribedBy: { userId: "user1", exists: false } }
) {
edges {
node {
id
contributors {
user {
id
}
}
transcribedAt
}
}
}
}
`({}, { appId: 'WEBSITE' })
).toMatchSnapshot('is not transcribedBy user1');
});

it('filters by reply types', async () => {
expect(
await gql`
Expand Down

0 comments on commit 0b486ac

Please sign in to comment.