import { Injectable , Inject , HttpException } from '@nestjs/common' ; import { InjectRepository } from '@nestjs/typeorm' ; import { Repository , TreeRepository } from 'typeorm' ; import * as moment from 'moment' ; import { Article } from '../entities/article.entity' ; import { Classify } from '../entities/classify.entity' ; import { InputArticle , UpdateArticle , ArtResult } from '../interfaces/article.interface' ; import { ClassifyService } from './classify.service' ; import { UserService , User } from 'src/user' ; const _ = require ( 'underscore' ) ; @ Injectable ( ) export class ArticleService { constructor ( @ InjectRepository ( Article ) private readonly artRepo , @ InjectRepository ( Classify ) private readonly claRepo , @ Inject ( UserService ) private readonly userService , @ Inject ( ClassifyService ) private readonly classifyService , @ InjectRepository ( User ) private readonly userRepo ) { } param art async createArticle ( art , owner ) { const classify = await this . claRepo . findOne ( { value : art . classify . value } ) ; if ( ! classify ) { throw new HttpException ( '该文章分类不存在!' , 404 ) ; } art . owner = owner ; art . classify = classify ; await this . artRepo . save ( this . artRepo . create ( art ) ) ; } param art async updateArticle ( art , owner ) { try { const article = await this . artRepo . findOne ( art . id ) ; if ( ! article ) { throw new HttpException ( '该文章不存在!' , 404 ) ; } const classify = await this . claRepo . findOne ( { value : art . classify . value } ) ; if ( ! classify ) { throw new HttpException ( '该文章分类不存在!' , 404 ) ; } const user = await this . userRepo . findOne ( { where : { id : owner } , relations : [ 'roles' ] } ) ; if ( user . roles . length && user . roles [ 0 ] . id === 1 ) { article . status = 0 ; } art . classify = classify ; art . modifyAt = moment ( ) . format ( 'YYYY-MM-DD HH:mm:ss' ) ; await this . artRepo . save ( this . artRepo . create ( art ) ) ; } catch ( error ) { throw new HttpException ( error . toString ( ) , 500 ) ; } } param ids async recycleArticleByIds ( ids ) { const articles = [ ] ; await this . artRepo . findByIds ( ids ) . then ( art => { art . map ( ( key , value ) => { articles . push ( key . id ) ; } ) ; } ) ; const noExist = _ . difference ( ids , articles ) ; if ( noExist . length > 0 ) { throw new HttpException ( `id为${ noExist }的文章不存在` , 404 ) ; } await this . artRepo . update ( ids , { recycling : true } ) ; } param ids async deleteArticleByIds ( ids ) { const articles = [ ] ; await this . artRepo . findByIds ( ids ) . then ( art => { art . map ( ( key , value ) => { articles . push ( key . id ) ; } ) ; } ) ; const noExist = _ . difference ( ids , articles ) ; if ( noExist . length > 0 ) { throw new HttpException ( `id为${ noExist }的文章不存在` , 404 ) ; } await this . artRepo . delete ( ids ) ; } param ids async recoverArticleByIds ( ids ) { const articles = [ ] ; await this . artRepo . findByIds ( ids ) . then ( art => { art . map ( ( key , value ) => { articles . push ( key . id ) ; } ) ; } ) ; const noExist = _ . difference ( ids , articles ) ; if ( noExist . length > 0 ) { throw new HttpException ( `id为${ noExist }的文章不存在` , 404 ) ; } await this . artRepo . update ( ids , { recycling : false } ) ; } param ids param status param refuseReason async auditArticle ( ids , op , refuseReason ) { const articles = [ ] ; const arts = await this . artRepo . findByIds ( ids ) ; arts . forEach ( ( key , value ) => { articles . push ( key . id ) ; } ) ; const noExist = _ . difference ( ids , articles ) ; if ( noExist . length > 0 ) { throw new HttpException ( `id为${ noExist }的文章不存在` , 404 ) ; } switch ( op ) { case 1 : await this . artRepo . update ( ids , { status : op } ) ; break ; case 2 : await this . artRepo . update ( ids , { status : op , refuseReason } ) ; break ; default : throw new HttpException ( 'status参数错误' , 405 ) ; } } param classifyId param createdAt param endTime param title param username param top param pageNumber param pageSize async getAllArticle ( classifyAlias , createdAt , endTime , title , username , top , pageNumber , pageSize ) { const sqb = this . artRepo . createQueryBuilder ( 'article' ) . where ( 'article.status = :status' , { status : 1 } ) . andWhere ( 'article.recycling = false' ) . leftJoinAndSelect ( 'article.classify' , 'classify' ) ; if ( classifyAlias ) { const cla = await this . claRepo . findOne ( { where : { value : classifyAlias } } ) ; if ( ! cla ) { throw new HttpException ( '该分类不存在!' , 404 ) ; } sqb . andWhere ( 'article.classify = :classify' , { classify : cla . id } ) ; } if ( title ) { sqb . andWhere ( 'article.title Like :title' , { title : `%${ title }%` } ) ; } if ( username ) { sqb . andWhere ( 'article.username = :username' , { username } ) ; } if ( createdAt ) { const min = new Date ( createdAt ) ; sqb . andWhere ( 'article.createdAt > :start' , { start : min } ) ; } if ( endTime ) { const max = new Date ( endTime ) ; sqb . andWhere ( 'article.createdAt < :end' , { end : max } ) ; } if ( top ) { sqb . andWhere ( 'article.top In (1,2) ' ) ; } if ( top === false ) { sqb . andWhere ( 'article.top = :top' , { top : 0 } ) ; } const result = await sqb . skip ( pageSize * ( pageNumber - 1 ) ) . take ( pageSize ) . orderBy ( { 'article.top' : 'DESC' , 'article.modifyAt' : 'DESC' } ) . getManyAndCount ( ) ; const exist = [ ] ; for ( const i of result [ 0 ] ) { const classify = await this . claRepo . findOne ( i . classify . id ) ; const a = { id : i . id , title : i . title , classify , sourceUrl : i . sourceUrl , cover : i . cover , abstract : i . abstract , content : i . content , top : i . top , source : i . source , username , status : i . status , recycling : i . recycling , createdAt : i . createdAt , modifyAt : i . modifyAt , views : i . views , like : i . like , artInfos : i . artInfos , keywords : i . keywords , structure : i . structure , hidden : i . hidden } ; exist . push ( a ) ; } return { exist , total : result [ 1 ] } ; } async userGetArticles ( alias , pageNumber , pageSize ) { const cla = await this . claRepo . findOne ( { where : { value : alias , relations : [ 'parent' ] } } ) ; const ids = [ ] ; if ( cla . onlyChildrenArt ) { const a = await this . classifyService . getAllClassifyIds ( cla . id ) ; const b = a . splice ( a . indexOf ( cla . id ) , 1 ) ; for ( const i of b ) { ids . push ( i ) ; } } else { const a = await this . classifyService . getAllClassifyIds ( cla . id ) ; for ( const i of a ) { ids . push ( i ) ; } } const sqb = this . artRepo . createQueryBuilder ( 'article' ) . where ( 'article.status = :status' , { status : 1 } ) . andWhere ( 'article.recycling = false' ) . andWhere ( 'article.hidden = false' ) . andWhere ( 'article.classify IN(:...ids)' , { ids } ) . leftJoinAndSelect ( 'article.classify' , 'classify' ) ; const result = await sqb . skip ( pageSize * ( pageNumber - 1 ) ) . take ( pageSize ) . orderBy ( { 'article.top' : 'DESC' , 'article.modifyAt' : 'DESC' } ) . getManyAndCount ( ) ; const exist = [ ] ; for ( const i of result [ 0 ] ) { const classify = await this . claRepo . findOne ( i . classify ) ; const a = { id : i . id , title : i . title , classify , cover : i . cover , abstract : i . abstract , content : i . content , createAt : i . createdAt , createdAt : i . createdAt , keywords : i . keywords , like : i . like , sourceUrl : i . sourceUrl , source : i . source } ; exist . push ( a ) ; } return { total : result [ 1 ] , exist } ; } /**
     * 搜索回收站中文章
     *
     */ async getRecycleArticle ( classifyAlias , createdAt , endTime , title , username , top , pageNumber , pageSize ) { const sqb = this . artRepo . createQueryBuilder ( 'article' ) . where ( 'article.recycling = :recycling' , { recycling : true } ) . leftJoinAndSelect ( 'article.classify' , 'classify' ) ; if ( classifyAlias ) { const cla = await this . claRepo . findOne ( { where : { value : classifyAlias } } ) ; if ( ! cla ) { throw new HttpException ( '该分类不存在!' , 404 ) ; } sqb . andWhere ( 'article.classify = :classify' , { classify : cla . id } ) ; } if ( title ) { sqb . andWhere ( 'article.title Like :title' , { title : `%${ title }%` } ) ; } if ( username ) { sqb . andWhere ( 'article.username = :username' , { username } ) ; } if ( createdAt ) { const min = new Date ( createdAt ) ; const max = endTime ? new Date ( endTime ) : new Date ( ) ; sqb . andWhere ( 'article.createdAt > :start' , { start : min } ) ; sqb . andWhere ( 'article.createdAt < :end' , { end : max } ) ; } if ( top ) { sqb . andWhere ( 'article.top In (1,2) ' ) ; } if ( top === false ) { sqb . andWhere ( 'article.top = :top' , { top : 0 } ) ; } const result = await sqb . skip ( pageSize * ( pageNumber - 1 ) ) . take ( pageSize ) . orderBy ( { 'article.top' : 'DESC' , 'article.modifyAt' : 'DESC' } ) . getMany ( ) ; const exist = [ ] ; const total = await sqb . getCount ( ) ; for ( const i of result ) { const classify = await this . claRepo . findOne ( i . classify . id ) ; const a = { id : i . id , title : i . title , classify , sourceUrl : i . sourceUrl , cover : i . cover , abstract : i . abstract , content : i . content , top : i . top , source : i . source , username , status : i . status , views : i . views , like : i . like , recycling : i . recycling , createdAt : i . createdAt , modifyAt : i . modifyAt , structure : i . structure , artInfos : i . artInfos } ; exist . push ( a ) ; } return { exist , total } ; } param id async getArticleById ( id ) { const artQb = await this . artRepo . createQueryBuilder ( 'art' ) . leftJoinAndSelect ( 'art.classify' , 'classify' ) ; const art = await artQb . where ( 'art.id = :id' , { id } ) . getOne ( ) ; art . views ++ ; const classifyId = art . classify . id ; const pre = await this . artRepo . createQueryBuilder ( ) . where ( '"id" = (select max(id) from public.article where "id" < :id and "classifyId" =:classifyId and "status" =:status and "recycling" =:recycling) ' , { id , classifyId , status : 1 , recycling : false } ) . getOne ( ) ; const next = await this . artRepo . createQueryBuilder ( ) . where ( '"id" = (select min(id) from public.article where "id" > :id and "classifyId" =:classifyId and "status" =:status and "recycling" =:recycling) ' , { id , classifyId , status : 1 , recycling : false } ) . getOne ( ) ; const data = await this . artRepo . save ( this . artRepo . create ( art ) ) ; return { pre : pre ? pre . id : undefined , current : data , next : next ? next . id : undefined } ; } /**
     *
     * 搜索获取待审核文章
     *
     */ async getCheckArticle ( classifyAlias , createdAt , endTime , title , username , top , pageNumber , pageSize ) { const sqb = this . artRepo . createQueryBuilder ( 'article' ) . where ( 'article.recycling = :recycling' , { recycling : false } ) . andWhere ( 'article.status = :status' , { status : 0 } ) . leftJoinAndSelect ( 'article.classify' , 'classify' ) ; if ( classifyAlias ) { const cla = await this . claRepo . findOne ( { where : { value : classifyAlias } } ) ; if ( ! cla ) { throw new HttpException ( '该分类不存在!' , 404 ) ; } sqb . andWhere ( 'article.classify = :classify' , { classify : cla . id } ) ; } if ( title ) { sqb . andWhere ( 'article.title Like :title' , { title : `%${ title }%` } ) ; } if ( username ) { sqb . andWhere ( 'article.username = :username' , { username } ) ; } if ( createdAt ) { const min = new Date ( createdAt ) ; const max = endTime ? new Date ( endTime ) : new Date ( ) ; sqb . andWhere ( 'article.createdAt > :start' , { start : min } ) ; sqb . andWhere ( 'article.createdAt < :end' , { end : max } ) ; } if ( top ) { sqb . andWhere ( 'article.top In (1,2) ' ) ; } if ( top === false ) { sqb . andWhere ( 'article.top = :top' , { top : 0 } ) ; } const result = await sqb . skip ( pageSize * ( pageNumber - 1 ) ) . take ( pageSize ) . orderBy ( { 'article.modifyAt' : 'ASC' } ) . getMany ( ) ; const exist = [ ] ; const total = await sqb . getCount ( ) ; for ( const i of result ) { const classify = await this . claRepo . findOne ( i . classify . id ) ; const a = { id : i . id , title : i . title , classify , sourceUrl : i . sourceUrl , cover : i . cover , abstract : i . abstract , content : i . content , top : i . top , source : i . source , createdAt : i . createdAt , username , status : i . status , recycling : i . recycling , views : i . views , like : i . like , modifyAt : i . modifyAt , keywords : i . keywords , structure : i . structure , artInfos : i . artInfos } ; exist . push ( a ) ; } return { exist , total } ; } private addDate ( dates , days ) { if ( days === undefined || days === '' ) { days = 1 ; } const date = new Date ( dates ) ; date . setDate ( date . getDate ( ) + days ) ; const month = date . getMonth ( ) + 1 ; const day = date . getDate ( ) ; return date . getFullYear ( ) + '-' + this . getFormatDate ( month ) + '-' + this . getFormatDate ( day ) ; } private getFormatDate ( arg ) { if ( arg === undefined || arg === '' ) { return '' ; } let re = arg + '' ; if ( re . length < 2 ) { re = '0' + re ; } return re ; } }