import _difference from 'lodash/difference' ; import _some from 'lodash/some' ; import _uniq from 'lodash/uniq' ; import { DB_NOTICE_TYPE , USER_STATE } from 'common/enums' ; import { environment } from 'common/environment' ; import { AuthenticationError , ForbiddenByStateError , ForbiddenError , NotAllowAddOfficialTagError , TagNotFoundError , UserInputError , } from 'common/errors' ; import { fromGlobalId } from 'common/utils' ; import { ArticleService , NotificationService } from 'connectors' ; import { MutationToAddArticlesTagsResolver } from 'definitions' ; const triggerNotice = async ( { articleId , articleService , notificationService , tag , viewerId , isOwner , } ) => { const { mattyId } = environment ; const article = await articleService . baseFindById ( articleId ) ; const editors = ( tag . editors || [ ] ) . filter ( ( id ) => id !== mattyId ) ; const owner = tag . owner ? [ `${ tag . owner }` ] : [ ] ; const users = [ article . authorId , ... ( isOwner ? editors : owner ) ] . filter ( ( id ) => id !== viewerId ) ; users . map ( ( user ) => { notificationService . trigger ( { event : DB_NOTICE_TYPE . article_tag_has_been_added , recipientId : user , actorId : viewerId , entities : [ { type : 'target' , entityTable : 'article' , entity : article , } , { type : 'tag' , entityTable : 'tag' , entity : tag , } , ] , } ) ; } ) ; } ; const resolver = async ( root , { input : { id , articles , selected } } , { viewer , dataSources : { atomService , articleService , notificationService , tagService , } , } ) => { if ( ! viewer . id ) { throw new AuthenticationError ( 'visitor has no permission' ) ; } if ( viewer . state === USER_STATE . frozen ) { throw new ForbiddenByStateError ( `${ viewer . state } user has no permission` ) ; } if ( ! articles ) { throw new UserInputError ( '"articles" is required in update' ) ; } const { id : dbId } = fromGlobalId ( id ) ; const tag = await tagService . baseFindById ( dbId ) ; if ( ! tag ) { throw new TagNotFoundError ( 'tag not found' ) ; } const isOwner = tag . owner === viewer . id ; const isEditor = _some ( tag . editors , ( editor ) => editor === viewer . id ) ; const isMatty = viewer . id === environment . mattyId ; const isMaintainer = isOwner || isEditor || isMatty ; if ( ! isMaintainer && selected ) { throw new ForbiddenError ( 'not allow add tag to article' ) ; } if ( ! isMatty && tag . id === environment . mattyChoiceTagId ) { throw new NotAllowAddOfficialTagError ( 'not allow to add official tag' ) ; } const oldIds = await tagService . findArticleIdsByTagIds ( [ dbId ] ) ; const newIds = articles . map ( ( articleId ) => fromGlobalId ( articleId ) . id ) ; const addIds = _difference ( newIds , oldIds ) ; if ( ! isMaintainer ) { const count = await atomService . count ( { table : 'article' , where : { authorId : viewer . id } , whereIn : [ 'id' , addIds ] , } ) ; if ( count !== addIds . length ) { throw new ForbiddenError ( 'not allow add tag to article' ) ; } } await tagService . createArticleTags ( { articleIds : addIds , creator : viewer . id , tagIds : [ dbId ] , selected , } ) ; if ( isMaintainer ) { for ( const articleId of addIds ) { await triggerNotice ( { articleId , articleService , notificationService , tag , viewerId : viewer . id , isOwner , } ) ; } } return tag ; } ; export default resolver ;