import { Injectable } from '@nestjs/common' ; import { InjectConnection , InjectRepository } from '@nestjs/typeorm' ; import * as _ from 'lodash' ; import { Connection , In , Repository } from 'typeorm' ; import { CategoriesService , OptionService } from '..' ; import { IPaginationOptions , paginate , Pagination } from '../../common/paginate' ; import { ID } from '../../common/shared-types' ; import { EUserPostsBehavior } from '../../common/types/common-types' ; import { formatAllMeta , formatOneMeta } from '../../common/utils' ; import { Post as PostEntity , PostMeta , Term , TermRelationships , TermTaxonomy , User } from '../../entity' ; @ Injectable ( ) export class PostService { constructor ( @ InjectConnection ( ) private connection , private readonly categoriesService , private readonly optionService ) { } param id async findById ( id ) { const data = await this . connection . getRepository ( PostEntity ) . findOneOrFail ( { where : { id , } , } ) ; return data ; } async loadBLock ( blocks ) { const dataList = await this . connection . manager . createQueryBuilder ( ) . select ( ) . from ( PostEntity , 'p' ) . where ( `id IN (:blocks)` , { blocks } ) . orderBy ( `INSTR (',${ blocks },', CONCAT(',',id,','))` ) . getRawMany ( ) ; formatAllMeta ( dataList ) ; for ( const item of dataList ) { const typeObject = await this . categoriesService . formatTermForObject ( item . id ) as Term ; if ( ! _ . isEmpty ( typeObject ) ) { item . type = typeObject . slug ; await this . getFormatData ( item ) ; } } return dataList ; } async getFormatData ( item ) { switch ( item . type ) { case 'post-format-audio' : { if ( ! _ . isEmpty ( item . block ) ) { const postId = JSON . parse ( item . block ) [ 0 ] ; const block = await this . getAttachmentInfo ( postId ) ; if ( ! Object . is ( block . meta . _attachment_file , undefined ) ) { item . guid = block . meta . _attachment_file ; } if ( ! Object . is ( block . meta . _attachment_metadata , undefined ) ) { if ( block . meta . _attachment_metadata !== '{}' ) { item = _ . extend ( item , block . meta . _attachment_metadata ) ; } } } Reflect . deleteProperty ( item , 'meta' ) ; break ; } default : break ; } return item ; } param id private async getAttachmentInfo ( id ) { const data = await this . findById ( id ) ; return formatOneMeta ( data ) ; } param ids private async getAudios ( ids ) { this . connection . manager . createQueryBuilder ( PostEntity , 'post' ) . orderBy ( `INSTR (',${ ids },', CONCAT(',',id,','))` ) ; } param options async paginate ( options ) { return await paginate < PostEntity > ( this . connection . getRepository ( PostEntity ) , options , { type : 'page' , } ) ; } param categorySlug param status param page param pageSize async getFromCategory ( categorySlug , status ? , querys ? ) { const pageSize = querys . pagesize ? querys . pagesize : 10 ; const page = querys . page ? querys . page * pageSize : 1 ; let where ; if ( _ . isEmpty ( status ) ) { where = `obj.status NOT IN ('trash')` ; } else { where = `obj.status = '${ status }'` ; } let data ; data = await this . connection . manager . createQueryBuilder ( ) . select ( 'obj.*, tt.description as category' ) . from ( Term , 't' ) . innerJoin ( query => { return query . from ( TermTaxonomy , 'tt' ) ; } , 'tt' , 'tt.id = t.id' ) . innerJoin ( query => { return query . from ( TermRelationships , 'tr' ) ; } , 'tr' , 'tr.taxonomyId = tt.id' ) . innerJoin ( query => { return query . from ( PostEntity , 'obj' ) ; } , 'obj' , 'obj.id = tr.objectId' ) . where ( 'obj.type = :type' , { type : 'page' } ) . andWhere ( where ) . andWhere ( 't.slug = :categorySlug' , { categorySlug } ) . orderBy ( 'obj.updatedAt' , 'DESC' ) . offset ( page ) . limit ( pageSize ) . getRawMany ( ) ; const objIds = [ ] ; data . forEach ( item => { objIds . push ( item . id ) ; } ) ; if ( ! _ . isEmpty ( objIds ) ) { const metaData = await this . connection . getRepository ( PostMeta ) . find ( { post : In ( objIds ) , } ) ; data . forEach ( item => { item . metas = _ . filter ( metaData , { id : item . id } ) ; } ) ; } return data ; } param isRandom param limit async getPopular ( isRandom = false , limit = 10 ) { let data ; const orderBy = ! isRandom ? { viewCount : 'DESC' } : 'rand()' ; data = await this . connection . manager . createQueryBuilder ( ) . select ( 'p.*, JSON_LENGTH(value) as viewCount' ) . from ( PostEntity , 'p' ) . innerJoin ( query => { return query . from ( PostMeta , 'meta' ) ; } , 'meta' , 'meta.postId = p.id' ) . where ( 'meta.key = :key' , { key : '_post_views' } ) . orderBy ( orderBy ) . limit ( limit ) . getRawMany ( ) ; return data ; } param limit async getNews ( limit ) { let data ; data = await this . connection . manager . createQueryBuilder ( ) . select ( 'obj.*, tt.description as category' ) . from ( Term , 't' ) . innerJoin ( query => { return query . from ( TermTaxonomy , 'tt' ) ; } , 'tt' , 'tt.id = t.id' ) . innerJoin ( query => { return query . from ( TermRelationships , 'tr' ) ; } , 'tr' , 'tr.taxonomyId = tt.id' ) . innerJoin ( query => { return query . from ( PostEntity , 'obj' ) ; } , 'obj' , 'obj.id = tr.objectId' ) . where ( 'obj.type = :type' , { type : 'page' } ) . andWhere ( 'obj.status IN (:status)' , { status : 'publish' } ) . andWhere ( 'tt.taxonomy = :category' , { category : 'category' } ) . orderBy ( 'obj.updatedAt' , 'DESC' ) . limit ( limit ) . getRawMany ( ) ; const objIds = [ ] ; data . forEach ( item => { objIds . push ( item . id ) ; } ) ; if ( ! _ . isEmpty ( objIds ) ) { const metaData = await this . connection . getRepository ( PostMeta ) . find ( { post : In ( objIds ) , } ) ; data . forEach ( item => { item . metas = _ . filter ( metaData , { id : item . id } ) ; } ) ; } return data ; } param stickys async getStickys ( stickys , querys ? ) { const data = await this . connection . manager . createQueryBuilder ( ) . select ( ) . from ( PostEntity , 'p' ) . where ( 'p.id IN (:stickys)' , { stickys } ) . orderBy ( `INSTR (',${ stickys },', CONCAT(',',id,','))` ) . getRawMany ( ) ; const objIds = [ ] ; data . forEach ( item => { objIds . push ( item . id ) ; } ) ; if ( ! _ . isEmpty ( objIds ) ) { const metaData = await this . connection . manager . createQueryBuilder ( ) . select ( ) . from ( PostMeta , 'pm' ) . where ( `postId IN (:objIds)` , { objIds } ) . getRawMany ( ) ; data . forEach ( item => { item . metas = _ . filter ( metaData , { postId : item . id } ) ; } ) ; } return data ; } async findAllByType ( postType , userId , take ) { const where = { status : 'publish' , type : In ( [ postType ] ) , } ; if ( userId ) { where . author = userId ; } return await this . connection . getRepository ( PostEntity ) . find ( { where , take : take || 10 , skip : 0 , cache : true , } ) ; } param type param postId async getAttachment ( postId , type = 'file' ) { let where = { postId , } ; switch ( type ) { case 'file' : { where = _ . extend ( { key : '_attachment_file' } , where ) ; const attachment = await this . connection . manager . createQueryBuilder ( ) . select ( ) . from ( PostMeta , 'pm' ) . where ( `pm.key = :key AND pm.postId = :postId` , { key : '_attachment_file' , postId } ) . getRawOne ( ) ; if ( ! _ . isEmpty ( attachment ) ) { return JSON . parse ( attachment . value ) ; } return '' ; } case 'meta' : break ; } } param ids async getAttachments ( ids ) { let where = { postId : In ( ids ) , } ; where = _ . extend ( { key : '_attachment_file' } , where ) ; const list = await this . connection . getRepository ( PostMeta ) . find ( { where , } ) ; return list ; } param behavior param postId async countByBehavior ( behavior , postId ) { const data = await this . connection . manager . createQueryBuilder ( ) . select ( `JSON_LENGTH(pm.value) as count` ) . from ( PostMeta , 'pm' ) . where ( `pm.postId = :postId AND pm.key = :key` , { postId , key : behavior } ) . getRawOne ( ) ; if ( ! _ . isEmpty ( data ) ) { return data . count ; } return 0 ; } /**
     * 根据用户的内容交互行为类型返回用户列表
     */ async getUsersByBehavior ( behavior , postId ) { const data = await this . connection . manager . createQueryBuilder ( ) . select ( ) . from ( PostMeta , 'pm' ) . where ( `pm.postId = :postId AND pm.key = :key` , { postId , key : behavior } ) . getRawOne ( ) ; return data ; } param userId param postId param ip async newViewer ( userId , postId , ip ) { const hasViewer = await this . connection . getRepository ( PostMeta ) . findOne ( { post : { id : postId } , key : EUserPostsBehavior . VIEW , } ) ; if ( ! hasViewer ) { await this . connection . getRepository ( PostMeta ) . save ( { post : { id : postId } , key : EUserPostsBehavior . VIEW , value : [ ] , } ) . then ( entity => { } ) ; } const updateResult = await this . connection . createQueryBuilder ( ) . update ( PostMeta ) . set ( { post : { id : postId } , key : '_post_views' , value : ( ) => `JSON_ARRAY_APPEND(value, '$', JSON_OBJECT('id', '${ userId }','ip', '${ ip }', 'date', '${ new Date ( ) . getTime ( ) }'))` , } ) . where ( 'postId = :postId AND `key` = :key' , { postId , key : EUserPostsBehavior . VIEW } ) . execute ( ) ; return updateResult ; } param userId param postId param ip async updateViewer ( userId , postId , ip ) { const updateResult = await this . connection . createQueryBuilder ( ) . update ( PostMeta ) . set ( { value : ( ) => { return `
            JSON_REPLACE(
              value,
                CONCAT(
                    SUBSTRING_INDEX(
                        REPLACE(
                            JSON_SEARCH(value, 'one', '${ userId }', NULL, '$**.id'),
                            '"', ''
                        ),
                    '.', 1),
                  '.date'
                ),
                '${ new Date ( ) . getTime ( ) }',
                CONCAT(
                    SUBSTRING_INDEX(
                        REPLACE(
                            JSON_SEARCH(value, 'one', '${ userId }', NULL, '$**.id'),
                            '"', ''
                        ),
                    '.', 1),
                  '.ip'
              ),
             '${ ip }'
            )` ; } , } ) . where ( 'postId = :postId AND `key` = :key' , { postId , key : EUserPostsBehavior . VIEW } ) . execute ( ) ; return updateResult ; } }