diff --git a/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js b/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js index 8fb6dd2ef..ed0746d29 100644 --- a/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js +++ b/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js @@ -3,15 +3,15 @@ import { gql, compose } from 'react-apollo'; import { withFragments } from 'coral-framework/hocs'; import AssetStatusInfo from '../components/AssetStatusInfo'; import PropTypes from 'prop-types'; -import { withUpdateAssetStatus } from 'coral-framework/graphql/mutations'; +import { + withUpdateAssetStatus, + withCloseAsset, +} from 'coral-framework/graphql/mutations'; class AssetStatusInfoContainer extends React.Component { openAsset = () => this.props.updateAssetStatus(this.props.asset.id, { closedAt: null }); - closeAsset = () => - this.props.updateAssetStatus(this.props.asset.id, { - closedAt: new Date().toISOString(), - }); + closeAsset = () => this.props.closeAsset(this.props.asset.id); render() { return ( @@ -29,6 +29,7 @@ class AssetStatusInfoContainer extends React.Component { AssetStatusInfoContainer.propTypes = { asset: PropTypes.object.isRequired, updateAssetStatus: PropTypes.func.isRequired, + closeAsset: PropTypes.func.isRequired, }; const withAssetStatusInfoFragments = withFragments({ @@ -41,6 +42,10 @@ const withAssetStatusInfoFragments = withFragments({ `, }); -const enhance = compose(withAssetStatusInfoFragments, withUpdateAssetStatus); +const enhance = compose( + withAssetStatusInfoFragments, + withUpdateAssetStatus, + withCloseAsset +); export default enhance(AssetStatusInfoContainer); diff --git a/client/coral-framework/graphql/fragments.js b/client/coral-framework/graphql/fragments.js index 2ec92ea6b..a62fd6d92 100644 --- a/client/coral-framework/graphql/fragments.js +++ b/client/coral-framework/graphql/fragments.js @@ -3,27 +3,28 @@ import { createDefaultResponseFragments } from '../utils'; // fragments defined here are automatically registered. export default { ...createDefaultResponseFragments( - 'SetUserRoleResponse', - 'ChangeUsernameResponse', - 'SetUsernameResponse', 'BanUsersResponse', - 'UnbanUserResponse', - 'SetUserSuspensionStatusResponse', - 'SetCommentStatusResponse', - 'SetUsernameStatusResponse', - 'UnsuspendUserResponse', - 'SuspendUserResponse', + 'ChangeUsernameResponse', + 'CloseAssetResponse', 'CreateCommentResponse', - 'CreateFlagResponse', - 'EditCommentResponse', - 'PostFlagResponse', 'CreateDontAgreeResponse', + 'CreateFlagResponse', 'DeleteActionResponse', - 'ModifyTagResponse', + 'EditCommentResponse', 'IgnoreUserResponse', + 'ModifyTagResponse', + 'PostFlagResponse', + 'SetCommentStatusResponse', + 'SetUsernameResponse', + 'SetUsernameStatusResponse', + 'SetUserRoleResponse', + 'SetUserSuspensionStatusResponse', 'StopIgnoringUserResponse', - 'UpdateSettingsResponse', + 'SuspendUserResponse', + 'UnbanUserResponse', + 'UnsuspendUserResponse', 'UpdateAssetSettingsResponse', - 'UpdateAssetStatusResponse' + 'UpdateAssetStatusResponse', + 'UpdateSettingsResponse' ), }; diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index e5f0bb60e..f34a2cc88 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -665,3 +665,46 @@ export const withUpdateAssetStatus = withMutation( }), } ); + +export const withCloseAsset = withMutation( + gql` + mutation CloseAsset($id: ID!) { + closeAsset(id: $id) { + ...CloseAssetResponse + } + } + `, + { + props: ({ mutate }) => ({ + closeAsset: id => { + return mutate({ + variables: { + id, + }, + optimisticResponse: { + closeAsset: { + __typename: 'CloseAssetResponse', + errors: null, + }, + }, + update: proxy => { + const fragment = gql` + fragment Talk_CloseAssetResponse on Asset { + closedAt + isClosed + } + `; + + const fragmentId = `Asset_${id}`; + const data = { + __typename: 'Asset', + closedAt: new Date(), + isClosed: true, + }; + proxy.writeFragment({ fragment, id: fragmentId, data }); + }, + }); + }, + }), + } +); diff --git a/graph/mutators/asset.js b/graph/mutators/asset.js index 171c711f0..6524331e1 100644 --- a/graph/mutators/asset.js +++ b/graph/mutators/asset.js @@ -38,11 +38,30 @@ const updateStatus = async (ctx, id, { closedAt, closedMessage }) => } ); +/** + * closeNow will close an asset for commenting. + * + * @param {Object} ctx graphql context + * @param {String} id the asset's id to close + */ +const closeNow = async (ctx, id) => + AssetModel.update( + { + id, + }, + { + $set: { + closedAt: new Date(), + }, + } + ); + module.exports = ctx => { let mutators = { Asset: { updateSettings: () => Promise.reject(errors.ErrNotAuthorized), updateStatus: () => Promise.reject(errors.ErrNotAuthorized), + closeNow: () => Promise.reject(errors.ErrNotAuthorized), }, }; @@ -55,6 +74,7 @@ module.exports = ctx => { if (ctx.user.can(UPDATE_ASSET_STATUS)) { mutators.Asset.updateStatus = (id, status) => updateStatus(ctx, id, status); + mutators.Asset.closeNow = id => closeNow(ctx, id); } } diff --git a/graph/resolvers/root_mutation.js b/graph/resolvers/root_mutation.js index e99a8bd4b..3a646b3d8 100644 --- a/graph/resolvers/root_mutation.js +++ b/graph/resolvers/root_mutation.js @@ -94,6 +94,9 @@ const RootMutation = { ) => { await Asset.updateStatus(id, status); }, + closeAsset: async (_, { id }, { mutators: { Asset } }) => { + await Asset.closeNow(id); + }, setUserRole: async (_, { id, role }, { mutators: { User } }) => { await User.setRole(id, role); }, diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index 002318bc3..cd9eb9325 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -1111,6 +1111,14 @@ type UpdateAssetStatusResponse implements Response { errors: [UserError!] } +# CloseAssetResponse is the response returned with possibly some errors +# relating to the update status attempt. +type CloseAssetResponse implements Response { + + # An array of errors relating to the mutation that occurred. + errors: [UserError!] +} + # UpdateAssetSettingsResponse is the response returned with possibly some errors # relating to the update settings attempt. type UpdateAssetSettingsResponse implements Response { @@ -1446,6 +1454,9 @@ type RootMutation { # Mutation is restricted. updateAssetStatus(id: ID!, input: UpdateAssetStatusInput!): UpdateAssetStatusResponse + # closeAsset will close the asset for commenting based on server time. + closeAsset(id: ID!): CloseAssetResponse + # updateSettings will update the global settings. # Mutation is restricted. updateSettings(input: UpdateSettingsInput!): UpdateSettingsResponse