package com.microservices.cms.doc.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.microservices.cms.doc.domain.CmsDoc;
import com.microservices.cms.doc.domain.CmsDocDto;
import com.microservices.cms.doc.domain.CmsDocSearchVo;
import com.microservices.cms.doc.domain.gitlink.EntryDto;
import com.microservices.cms.doc.domain.gitlink.FileEntryDto;
import com.microservices.cms.doc.domain.gitlink.LastCommitDto;
import com.microservices.cms.doc.mapper.CmsDocMapper;
import com.microservices.cms.doc.service.ICmsAsyncService;
import com.microservices.cms.doc.service.ICmsDocService;
import com.microservices.cms.project.domain.CmsProject;
import com.microservices.cms.project.service.ICmsProjectService;
import com.microservices.cms.utils.CmsConstants;
import com.microservices.cms.utils.CmsGitLinkRequestUrl;
import com.microservices.cms.utils.CmsUtils;
import com.microservices.common.core.constant.CacheConstants;
import com.microservices.common.core.constant.Constants;
import com.microservices.common.core.constant.SecurityConstants;
import com.microservices.common.core.enums.SystemRole;
import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.core.utils.html.EscapeUtil;
import com.microservices.common.core.utils.uuid.IdUtils;
import com.microservices.common.httpClient.constant.GitLinkConstants;
import com.microservices.common.httpClient.service.HttpAPIService;
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
import com.microservices.common.redis.service.RedisService;
import com.microservices.common.security.utils.SecurityUtils;
import com.microservices.system.api.RemoteDeptService;
import com.microservices.system.api.RemoteZoneService;
import com.microservices.system.api.utils.FeignUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.microservices.common.core.utils.sign.Base64.contentToBase64;

/**
 * 文章信息Service业务层处理
 *
 * @author otto
 * @date 2023-03-28
 */
@Service
public class CmsAsyncServiceImpl implements ICmsAsyncService {
    private static final Logger logger = LoggerFactory.getLogger(CmsAsyncServiceImpl.class);
    @Autowired
    private GitLinkRequestHelper gitLinkRequestHelper;
    @Autowired
    @Lazy
    private ICmsDocService cmsDocService;
    @Autowired
    @Lazy
    private ICmsProjectService cmsProjectService;
    @Autowired
    private CmsDocMapper cmsDocMapper;
    @Value("${cms.summaryMaxLength}")
    private int summaryMaxLength;
    @Value("${http.gatewayUrl}")
    private String gatewayUrl;
    @Value("${cms.baiduSearch.token}")
    private String baiduSearchToken;
    @Value("${cms.baiduSearch.url}")
    private String baiduSearchUrl;
    @Value("${cms.bingSearch.token}")
    private String bingSearchToken;
    @Value("${cms.bingSearch.url}")
    private String bingSearchUrl;
    @Autowired
    private RedisService redisService;
    @Autowired
    private RemoteDeptService remoteDeptService;
    @Autowired
    private HttpAPIService httpAPIService;
    @Autowired
    private RemoteZoneService remoteZoneService;
    @Autowired
    private RequestConfig config;
    /**
     * 异步设置文章更新时间
     *
     * @param entryDtoList
     * @param cmsProject
     */
    @Async
    @Override
    public void asyncBatchUpdateDoc(List<EntryDto> entryDtoList, CmsProject cmsProject) {
        //通过Redis设置更新频率，最快1分钟更新一次
        String updateDocIntervalKey = CacheConstants.UPDATE_DOC_INTERVAL_KEY + cmsProject.getIdentifier();
        if (redisService.hasKey(updateDocIntervalKey)) {
            return;
        } else {
            redisService.setCacheObject(updateDocIntervalKey, cmsProject.getName(), 1L, TimeUnit.MINUTES);
        }
        CmsDocSearchVo cmsDocSearch=new CmsDocSearchVo();
        cmsDocSearch.setDeptId(cmsProject.getDeptId());
        List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearch);
        for (EntryDto entryDto : entryDtoList) {
            CmsDoc cmsDoc = cmsDocList.stream().filter(x -> entryDto.getPath().equals(x.getFilePath())).findFirst().orElse(null);
            if (cmsDoc != null) {
                cmsDoc.setUpdateTime(new Date(entryDto.getCommit().getCreated_at_unix() * 1000L));
                cmsDoc.setFileSha(entryDto.getSha());
                cmsDoc.setFileSize(entryDto.getSize());
                cmsDocMapper.updateCmsDoc(cmsDoc);
            }
        }
    }


    @Async
    @Override
    public void asyncUpdateDoc(EntryDto entryDto, CmsDoc cmsDoc) {
        //通过Redis设置更新频率，最快1分钟更新一次
        String updateDocIntervalKey = CacheConstants.UPDATE_DOC_INTERVAL_KEY + cmsDoc.getId();
        if (redisService.hasKey(updateDocIntervalKey)) {
            return;
        } else {
            redisService.setCacheObject(updateDocIntervalKey, cmsDoc.getFilePath(), 1L, TimeUnit.MINUTES);
        }
        cmsDoc.setUpdateTime(new Date(entryDto.getCommit().getCreated_at_unix() * 1000L));
        cmsDoc.setFileSha(entryDto.getSha());
        cmsDoc.setFileSize(entryDto.getSize());
        cmsDocMapper.updateCmsDoc(cmsDoc);
    }

    @Override
    public void asyncCreateWebhook(CmsProject cmsProject) {
        JSONObject jsonObject = new JSONObject();
        JSONObject webhook = new JSONObject();
        webhook.put("active", true);
        webhook.put("branch_filter", CmsConstants.BRANCH_MASTER);
        webhook.put("content_type", "json");
        webhook.put("eventCondition", "push");
        webhook.put("http_method", "POST");
        webhook.put("secret", "");
        webhook.put("url", gatewayUrl+"/cms/doc/open/dept/"+cmsProject.getDeptId());
        webhook.put("events", new String[]{"push"});
        jsonObject.put("webhook", webhook);
        //增加Webhook
        JSONObject result = gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.CREATE_WEBHOOK(cmsProject), jsonObject);
    }

    @Async
    @Override
    public List<EntryDto> SyncDatabaseAndGitLinkDir(CmsProject cmsProject) {
        //暂时仅考虑主干分支
        //获取GitLink仓库下一级目录所有文件
        JSONObject result = gitLinkRequestHelper.doGet(CmsGitLinkRequestUrl.GET_ENTRIES(cmsProject, CmsConstants.BRANCH_MASTER));
        List<EntryDto> entryDtoList = cmsDocService.getEntriesFromRequestResult(result, cmsProject, false);
        if (entryDtoList == null) {
            return null;
        }
        //仅获取类型为Dir的文件
        entryDtoList = entryDtoList
                .stream()
                .filter(entry -> CmsConstants.ENTRY_TYPE_DIR_KEY.equals(entry.getType()))
                .collect(Collectors.toList());
        //获取GitLink仓库中文件夹名称列表
        List<String> gitLinkDirNameList = entryDtoList.stream().map(EntryDto::getName).collect(Collectors.toList());
        List<CmsDoc> cmsDirList = cmsDocMapper.selectCmsDirListByDeptId(cmsProject.getDeptId());
        //获取数据库中栏目名称列表
        List<String> databaseDirNameList = cmsDirList.stream().map(CmsDoc::getName).collect(Collectors.toList());
        //获取数据库中多的栏目名称列表
        List<String> deleteDirNameList = new ArrayList<>(databaseDirNameList);
        deleteDirNameList.removeAll(gitLinkDirNameList);
        for (String deleteDirName : deleteDirNameList) {
            CmsDoc cmsDir = cmsDocMapper.selectCmsDocDirByNameAndDeptId(deleteDirName, cmsProject.getDeptId());
            if (cmsDir != null) {
                //删除栏目时需要考虑栏目下是否还有文章，需一并删除
                CmsDocSearchVo cmsDocSearch = new CmsDocSearchVo();
                cmsDocSearch.setIsDir(false);
                cmsDocSearch.setDeptId(cmsProject.getDeptId());
                cmsDocSearch.setDirName(cmsDir.getName());
                List<CmsDoc> oldCmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearch);
                for (CmsDoc oldCmsDoc : oldCmsDocList) {
                    cmsDocMapper.deleteCmsDocById(oldCmsDoc.getId());
                }
                cmsDocMapper.deleteCmsDocById(cmsDir.getId());
            }
        }
        List<String> addDirNameList = new ArrayList<>(gitLinkDirNameList);
        addDirNameList.removeAll(databaseDirNameList);
        //获取GitLink中多的文件夹名称列表
        for (String addDirName : addDirNameList) {
            EntryDto entry = entryDtoList.stream().filter(x -> x.getName().equals(addDirName)).findFirst().orElse(null);
            if (entry != null) {
                syncCreateDir(addDirName, entry, cmsProject, true);
            }

        }
        return entryDtoList;
    }


    /**
     * 异步生成文章简介
     *
     * @param id
     * @param content
     */
    @Async
    @Override
    public void asyncSetSummary(Long id, String content) {
        //TODO:暂时不进行摘要自动提取
//        String summary = "";
//        if (StringUtils.isNotEmpty(content)) {
//            summary = HanLP.getSummary(content, summaryMaxLength);
//        }
//
//        CmsDoc cmsDoc = new CmsDoc();
//        cmsDoc.setId(id);
//        cmsDoc.setSummary(summary);
//        cmsDocMapper.updateCmsDoc(cmsDoc);
    }

    private void syncDocAddedData(CmsProject cmsProject, List<String> addedList) {
        for (String addedFilePath:addedList) {
            try {
                String[] filePathList = addedFilePath.split("/");
                if (filePathList.length != 2) {
                    continue;
                }
                String dirName = filePathList[0];
                FileEntryDto fileEntry = cmsDocService.getFileEntryDto(cmsProject, addedFilePath, CmsConstants.BRANCH_MASTER);
                EntryDto entry = fileEntry.getEntries();
                if (CmsConstants.MARKDOWN_SUFFIX.equals(CmsUtils.getFileSuffix(entry.getName()))) {
                    CmsDoc cmsDir = cmsDocMapper.selectCmsDocDirByNameAndDeptId(dirName, cmsProject.getDeptId());
                    if (cmsDir == null) {
                        syncCreateDir(dirName, entry, cmsProject, false);
                    }
                    CmsDoc cmsDoc = cmsDocMapper.selectCmsDocByNameAndDeptId(CmsUtils.getFileNameNoSuffix(entry.getName()), cmsProject.getDeptId(), dirName);
                    if (cmsDoc == null) {
                        syncCreateDoc(entry, dirName, cmsProject.getDeptId(), fileEntry.getLast_commit());
                    }
                }
            }catch (Exception e){
                logger.error("[{}]同步新增文章发生异常：{}"
                        , cmsProject.getName(), e.getMessage());
            }
        }
    }

    private void syncDocRemovedData(CmsProject cmsProject,List<String> removedList) {
        for (String removedFilePath:removedList) {
            try {
                String[] filePathList = removedFilePath.split("/");
                if (filePathList.length != 2) {
                    continue;
                }
                String dirName = filePathList[0];
                String fileName = filePathList[1];
                if (CmsConstants.MARKDOWN_SUFFIX.equals(CmsUtils.getFileSuffix(fileName))) {
                    CmsDoc cmsDoc = cmsDocMapper.selectCmsDocByNameAndDeptId(CmsUtils.getFileNameNoSuffix(fileName), cmsProject.getDeptId(), dirName);
                    if (cmsDoc != null) {
                        cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
                    }
                }
            } catch (Exception e) {
                logger.error("[{}]同步删除文章发生异常：{}"
                        , cmsProject.getName(), e.getMessage());
            }
        }
        if (!removedList.isEmpty()) {
            SyncDatabaseAndGitLinkDir(cmsProject);
        }
    }

    private void syncDocModifiedData(CmsProject cmsProject, List<String> modifiedList) {
        for (String modifiedFilePath : modifiedList) {
            try {
                String[] filePathList = modifiedFilePath.split("/");
                if (filePathList.length != 2) {
                    continue;
                }
                String dirName = filePathList[0];
                String fileName = filePathList[1];
                if (CmsConstants.MARKDOWN_SUFFIX.equals(CmsUtils.getFileSuffix(fileName))) {
                    CmsDoc cmsDoc = cmsDocMapper.selectCmsDocByNameAndDeptId(CmsUtils.getFileNameNoSuffix(fileName), cmsProject.getDeptId(), dirName);
                    if (cmsDoc != null) {
                        updateCmsPublishDataByGitLink(cmsProject, cmsDoc, CmsConstants.BRANCH_MASTER);
                    }
                }
            } catch (Exception e) {
                logger.error("[{}]同步修改文章发生异常：{}"
                        , cmsProject.getName(), e.getMessage());
            }
        }
    }

    @Override
    public void updateCmsPublishDataByGitLink(CmsProject cmsProject, CmsDoc cmsDoc, String branchName) {
        FileEntryDto fileEntryDto = cmsDocService.getFileEntryDto(cmsProject, cmsDoc.getFilePath(), branchName);
        LastCommitDto lastCommitDto = fileEntryDto.getLast_commit();
        EntryDto entryDto = fileEntryDto.getEntries();
        if (lastCommitDto != null && lastCommitDto.getAuthor() != null) {
            String commitUser = lastCommitDto.getAuthor().getLogin();
            cmsDoc.setUpdateBy(commitUser);
            cmsDoc.setPublishUser(commitUser);
            cmsDoc.setPublishUserNickname(lastCommitDto.getAuthor().getName());
            cmsDoc.setPublishUserUrl(EscapeUtil.removeExtraSlashOfUrl(
                    gitLinkRequestHelper.gitLinkUrl + "/" + commitUser
            ));
            cmsDoc.setPublishUserImage(EscapeUtil.removeExtraSlashOfUrl(
                    gitLinkRequestHelper.gitLinkUrl + "/" + lastCommitDto.getAuthor().getImage_url()
            ));
        }

        if (entryDto.getCommit() != null && entryDto.getCommit().getCreated_at_unix() != null) {
            Date publishDate = new Date(entryDto.getCommit().getCreated_at_unix() * 1000L);
            cmsDoc.setPublishTime(publishDate);
            cmsDoc.setUpdateTime(publishDate);
        }

        cmsDocMapper.updateCmsDoc(cmsDoc);
    }

    @Override
    @Async
    public void fullSyncDocData(CmsProject cmsProject) {
        //全量同步文件夹
        List<EntryDto> dirEntryList = SyncDatabaseAndGitLinkDir(cmsProject);
        for (EntryDto dirEntry : dirEntryList) {
            CmsDoc cmsDir = cmsDocMapper.selectCmsDocDirByNameAndDeptId(dirEntry.getName(), cmsProject.getDeptId());
            if (cmsDir == null) {
                logger.error("全量同步时发生异常：栏目不存在（栏目名称{}，组织Id{}）", dirEntry.getName(), cmsProject.getDeptId());
                continue;
            }
            //获取GitLink仓库专栏目录下所有文件
            List<EntryDto> entryDtoList = cmsDocService.getGitLinkFileByDir(cmsProject, cmsDir.getName());
            if (entryDtoList == null) {
                continue;
            }
            //获取GitLink所有文件的FilePath，通过一次数据库操作进行查找，减少数据库执行操作
            List<String> gitlinkFilePathList = entryDtoList
                    .stream()
                    .filter(entry -> CmsConstants.MARKDOWN_SUFFIX.equals(CmsUtils.getFileSuffix(entry.getName())))
                    .map(EntryDto::getPath)
                    .collect(Collectors.toList());
            CmsDocSearchVo cmsDocSearch = new CmsDocSearchVo();
            cmsDocSearch.setDeptId(cmsDir.getDeptId());
            cmsDocSearch.setDirName(cmsDir.getName());
            cmsDocSearch.setIsDir(false);
            List<CmsDoc> cmsDocList=cmsDocMapper.selectCmsDocList(cmsDocSearch);
            //获取数据库所有文件的filePath
            List<String> databaseFilePathList = cmsDocList.stream().map(CmsDoc::getFilePath).collect(Collectors.toList());
            //获取需要新增的文章
            List<String> addDocFilePathList = new ArrayList<>(gitlinkFilePathList);
            addDocFilePathList.removeAll(databaseFilePathList);
            syncDocAddedData(cmsProject, addDocFilePathList);
            //获取需要删除的文章
            List<String> removeDocFilePathList = new ArrayList<>(databaseFilePathList);
            removeDocFilePathList.removeAll(gitlinkFilePathList);
            syncDocRemovedData(cmsProject, removeDocFilePathList);
            //更新所有文章信息
            syncDocModifiedData(cmsProject, gitlinkFilePathList);
        }
        //清理没有栏目的文章
        List<CmsDoc> notDirCmsDocList = cmsDocMapper.selectNotDirCmsDocList(cmsProject.getDeptId());
        for (CmsDoc cmsDoc : notDirCmsDocList) {
            cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
        }

    }

    @Async
    @Override
    public void asyncDocData(Long deptId, String bodyStr) {
        //防止多次操作同时执行，将同步内容放入队列，根据先后时间执行同步动作
        String cmsSyncDeptIdKey=CacheConstants.CMS_SYNC_DEPT_ID_KEY+deptId;
        //为当前同步操作生成UUID，若拿到的UUID为自身，则执行本次同步动作
        String UUID= IdUtils.fastSimpleUUID();
        redisService.leftPush(cmsSyncDeptIdKey, UUID);
        //设置缓存过期时间，防止异常情况导致同步无法继续执行
        redisService.expire(cmsSyncDeptIdKey, 3600, TimeUnit.SECONDS);
        String currentUUID = String.valueOf(redisService.listIndexOf(cmsSyncDeptIdKey, -1));
        //设置最大循环阈值，防止意外情况导致死循环(7200次，约1小时左右)
        int threshold=7200;
        while (!UUID.equals(currentUUID)&&threshold!=0){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                logger.error("同步文章时Sleep失败：{}", e.getMessage());
            }
            currentUUID = String.valueOf(redisService.listIndexOf(cmsSyncDeptIdKey, -1));
            threshold--;
        }

        try{
            CmsProject cmsProject=cmsProjectService.selectCmsProjectByDeptId(deptId);
            JSONObject body=JSONObject.parseObject(bodyStr);
            //获取本次推送中Commit总数
            Integer totalCommits=body.getInteger("total_commits");
            //从webhook请求中获取本次提交内容
            JSONArray commits=body.getJSONArray("commits");
            //当commit总数大于提交的列表数量时，代表此次PUSH未携带所有commit，此时进行一次全量同步
            if(totalCommits!=null
                    &&commits!=null
                    &&totalCommits>commits.size()){
                fullSyncDocData(cmsProject);
            }else{
                for (int i = commits.size()-1; i >=0 ; i--) {
                    JSONObject commit=commits.getJSONObject(i);
                    //获取新增的文件列表
                    JSONArray addedList=commit.getJSONArray("added");
                    if(addedList!=null){
                        syncDocAddedData(cmsProject,addedList.toJavaList(String.class));
                    }
                    //获取删除的文件列表
                    JSONArray removedList=commit.getJSONArray("removed");
                    if(removedList!=null){
                        syncDocRemovedData(cmsProject,removedList.toJavaList(String.class));
                    }
                    //获取更新的文件列表
                    JSONArray modifiedList=commit.getJSONArray("modified");
                    if(modifiedList!=null){
                        syncDocModifiedData(cmsProject, modifiedList.toJavaList(String.class));
                    }
                }
            }
        }catch (Exception e) {
            logger.error("同步文章时发送异常：{}", e.getMessage());
        }finally {
            //本次同步执行完成后，再弹出该UUID
            redisService.rightPop(cmsSyncDeptIdKey, 500, TimeUnit.MICROSECONDS);
        }
    }

    @Override
    public CmsDoc syncCreateDoc(EntryDto entry, String dirName, Long deptId, LastCommitDto lastCommitDto) {
        CmsDoc cmsDoc = new CmsDoc();
        cmsDoc.setName(CmsUtils.getFileNameNoSuffix(entry.getName()));
        cmsDoc.setFileName(entry.getName());
        cmsDoc.setFilePath(dirName + "/" + entry.getName());
        cmsDoc.setDirName(dirName);
        cmsDoc.setIsDir(false);
        cmsDoc.setDeptId(deptId);
        cmsDoc.setFileSize(entry.getSize());
        cmsDoc.setFileSha(entry.getSha());
        if (entry.getCommit() != null && entry.getCommit().getCreated_at_unix() != null) {
            cmsDoc.setUpdateTime(new Date(entry.getCommit().getCreated_at_unix() * 1000L));
        }
        if (lastCommitDto != null && lastCommitDto.getAuthor() != null) {
            cmsDoc.setCreateBy(lastCommitDto.getAuthor().getLogin());
        }

        //若该文章不存在，则在数据库中创建该文章
        boolean insertResult = cmsDocService.insertCmsDocDatabase(cmsDoc, entry.getContent());
        if (!insertResult) {
            throw new ServiceException("同步GitLink仓库创建文章时出错(文章名称[" + cmsDoc.getName() + "])");
        }
        return cmsDoc;
    }

    @Override
    public void syncCreateDir(String dirName,EntryDto entry,CmsProject cmsProject,boolean isCreateKeep){
        CmsDoc cmsDir = new CmsDoc();
        cmsDir.setName(dirName);
        cmsDir.setCreateTime(entry.getCommit().getCreated_at());
        boolean insertResult;
        if(isCreateKeep){
            //若该栏目不存在，检查文件夹中是否存在.keep文件
            JSONObject subEntriesResult = gitLinkRequestHelper.doGet(
                    CmsGitLinkRequestUrl.GET_FILE_SUB_ENTRIES(cmsProject, cmsDir.getName(), CmsConstants.BRANCH_MASTER));
            EntryDto keepEntry = cmsDocService.getEntriesFromRequestResult(subEntriesResult, cmsProject, false)
                    .stream()
                    .filter(x -> CmsConstants.KEEP_FILE_NAME.equals(x.getName())).findFirst().orElse(null);

            if (keepEntry != null) {
                //若存在，则在数据库中创建该栏目
                insertResult=createCmsDir(cmsDir,cmsProject.getDeptId(),keepEntry);
            } else {
                //若不存在，则在数据库中创建该栏目，同时在仓库的该文件夹下创建.keep文件
                insertResult = cmsDocService.insertCmsDocDir(cmsProject.getDeptId(), cmsDir.copyToCmsDir());
            }
        }else{
            //若不自动创建，则在数据库中创建根据文件名该栏目
            insertResult=createCmsDir(cmsDir,cmsProject.getDeptId(),entry);
        }


        if (!insertResult) {
            throw new ServiceException("同步GitLink仓库创建栏目时出错(栏目名称[" + cmsDir.getName() + "])");
        }
    }

    private boolean createCmsDir(CmsDoc cmsDir,Long deptId,EntryDto entry){
        cmsDir.setIsDir(true);
        cmsDir.setFilePath(cmsDir.getDirPath());
        cmsDir.setDeptId(deptId);
        cmsDir.setFileName(entry.getName());
        cmsDir.setFileSize(entry.getSize());
        cmsDir.setFileSha(entry.getSha());

        return cmsDocService.insertCmsDocDatabase(cmsDir, "");
    }

    @Async
    @Override
    public void asyncUpdateProtectedBranchSetting(String userName, String identifier, Long deptId) {
        Map<String, String> params = getUpdateOrDeleteProtectedBranchParamsMap();
        //通过deptId获取平台管理员和平台运营人员usernames
        List<String> pushWhitelistUsernames = FeignUtils.getReturnData(remoteDeptService.getGitLinkUserNamesByDeptIdAndRoleKeys(deptId, SystemRole.ZONE_ADMIN.getRoleKey(), SecurityConstants.INNER));
        try {
            gitLinkRequestHelper.doPatch(CmsGitLinkRequestUrl.UPDATE_PROTECTED_BRANCHES(userName, identifier, params, pushWhitelistUsernames), null);
        } catch (URISyntaxException e) {
            logger.error("同步更新保护分支设置失败：{}", e.getMessage());
            ;
        }
    }

    @Async
    @Override
    public void asyncDeleteProtectedBranchSetting(String userName, String identifier, Long deptId) {
        Map<String, String> params = getUpdateOrDeleteProtectedBranchParamsMap();
        //通过deptId获取平台管理员和平台运营人员usernames
        List<String> pushWhitelistUsernames = FeignUtils.getReturnData(remoteDeptService.getGitLinkUserNamesByDeptIdAndRoleKeys(deptId, SystemRole.ZONE_ADMIN.getRoleKey(), SecurityConstants.INNER));
        try {
            gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_PROTECTED_BRANCHES(userName, identifier, params, pushWhitelistUsernames), null);
        } catch (URISyntaxException e) {
            logger.error("同步删除保护分支设置失败：{}", e.getMessage());
            ;
        }
    }

    @Async
    @Override
    public void asyncCreateProtectedBranchSetting(String userName, String identifier, Long deptId) {
        Map<String, String> params = new HashMap<>();
        params.put("branch_name", CmsConstants.BRANCH_MASTER);
        params.put("enable_push", "2");
        params.put("enable_push_whitelist", "true");
        params.put("branchProtect", "true");
        //通过deptId获取平台管理员和平台运营人员identifier
        List<String> pushWhitelistUsernames = FeignUtils.getReturnData(remoteDeptService.getGitLinkUserNamesByDeptIdAndRoleKeys(deptId, SystemRole.ZONE_ADMIN.getRoleKey(), SecurityConstants.INNER));
        try {
            gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.CREATE_PROTECTED_BRANCHES(userName, identifier, params, pushWhitelistUsernames), null);
        } catch (URISyntaxException e) {
            logger.error("同步创建保护分支设置失败：{}", e.getMessage());
            ;
        }
    }

    private Map<String, String> getUpdateOrDeleteProtectedBranchParamsMap() {
        Map<String, String> params = new HashMap<>();
        params.put("branch_name", CmsConstants.BRANCH_MASTER);
        params.put("enable_push", "2");
        params.put("enable_push_whitelist", "true");
        params.put("enable_merge_whitelist", "false");
        params.put("enable_status_check", "false");
        params.put("required_approvals", "0");
        params.put("enable_approvals_whitelist", "false");
        params.put("block_on_rejected_reviews", "false");
        params.put("dismiss_stale_approvals", "false");
        params.put("require_signed_commits", "false");
        params.put("block_on_outdated_branch", "false");
        return params;
    }

    @Override
    public void asyncCreateBranchAndFileAndPR(CmsDoc cmsDoc, String message, String content) {
        CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
        //创建临时分支
        String branchName = generateBranchName(cmsDoc);
        createBranchByGitLink(cmsProject, cmsDoc, branchName);
        //提交文件至临时分支
        createFileForBranchByGitLink(cmsProject, cmsDoc, message, content, branchName);
        //创建合并请求
        createPullRequestByGitLink(cmsProject, cmsDoc, message, branchName);
        cmsDocService.updateCmsCommonDatabase(cmsDoc, branchName);
    }

    @Override
    public void asyncUpdateBranchAndFileAndCreatePR(CmsDoc cmsDoc, CmsDocDto cmsDocDto) {
        CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
        String tmpBranchName = null;
        if (StringUtils.isEmpty(cmsDoc.getAuditTmpBranchName())) {
            //2.不存在临时分支时，创建临时分支
            tmpBranchName = generateBranchName(cmsDoc);
            createBranchByGitLink(cmsProject, cmsDoc, tmpBranchName);
        }
        if (StringUtils.isNotEmpty(cmsDoc.getAuditTmpBranchName())) {
            Long cmsDocIdInTmpBranch = Long.parseLong(cmsDoc.getAuditTmpBranchName().split("-")[1]);
            if (!cmsDocIdInTmpBranch.equals(cmsDoc.getId())) {
                //2.临时分支与文章id不匹配，创建临时分支
                tmpBranchName = generateBranchName(cmsDoc);
                createBranchByGitLink(cmsProject, cmsDoc, tmpBranchName);
            } else {
                tmpBranchName = cmsDoc.getAuditTmpBranchName();
            }
        }
        //3.将文件变更同步至新分支
        cmsDoc = updateCmsDocDatabaseAndUpdateForGitLink(cmsDoc, cmsDocDto, tmpBranchName);
        //4.创建合并请求
        try {
            createPullRequestByGitLink(cmsProject,
                    cmsDoc, "更新文章：" + StringUtils.truncateStringAndConcatenatingSpecifiedString(cmsDoc.getName(),
                            100, "..."), tmpBranchName);
        } catch (ServiceException e) {
            //忽略重复创建PR异常
            if (!"请求GitLink失败(合并请求已存在)".equals(e.getMessage())) {
                throw new ServiceException(e.getMessage());
            }
        }

        cmsDocService.updateCmsCommonDatabase(cmsDoc, tmpBranchName);
    }

    @Async
    @Override
    public void asyncCreateBranchAndDeleteFileAndCreatePR(CmsDoc cmsDoc, CmsProject cmsProject) {
        //2.创建临时分支
        String tmpBranchName = generateBranchName(cmsDoc);
        createBranchByGitLink(cmsProject, cmsDoc, tmpBranchName);
        //3.将文件变更同步至新分支
        deleteCmsDocForGitLink(cmsDoc, cmsProject, tmpBranchName);
        //4.创建合并请求
        createPullRequestByGitLink(cmsProject, cmsDoc,
                "删除文章：" + StringUtils.truncateStringAndConcatenatingSpecifiedString(cmsDoc.getName(), 100, "..."),
                tmpBranchName);
        cmsDocService.updateCmsCommonDatabase(cmsDoc, CmsConstants.BRANCH_MASTER);
    }

    private String generateBranchName(CmsDoc cmsDoc) {
        return CmsConstants.AUDIT_BRANCH_PREFIX + SecurityUtils.getUsername() + "-" + cmsDoc.getId();
    }

    private void createBranchByGitLink(CmsProject cmsProject, CmsDoc cmsDoc, String newBranchName) {
        //调用GitLink创建分支接口
        JSONObject requestBody = new JSONObject();
        requestBody.put("new_branch_name", newBranchName);
        requestBody.put("old_branch_name", CmsConstants.BRANCH_MASTER);
        JSONObject result = gitLinkRequestHelper.doPost(
                CmsGitLinkRequestUrl.CREATE_BRANCH(cmsProject),
                requestBody);
        cmsDoc.setAuditTmpBranchName(newBranchName);
    }

    private void createFileForBranchByGitLink(CmsProject cmsProject, CmsDoc cmsDoc, String message, String content, String branchName) {
        //调用GitLink创建文件接口
        JSONObject requestBody = new JSONObject();
        requestBody.put("filepath", cmsDoc.getFilePath());
        requestBody.put("branch", branchName);
        requestBody.put("content", contentToBase64(content));
        requestBody.put("message", message);
        JSONObject result = gitLinkRequestHelper.doPost(
                CmsGitLinkRequestUrl.CREATE_FILE(cmsProject),
                requestBody);
        cmsDoc.setFileName(result.getString("name"));
        cmsDoc.setFileSize(result.getLong("size"));
        cmsDoc.setFileSha(result.getString("sha"));
    }

    private void createPullRequestByGitLink(CmsProject cmsProject, CmsDoc cmsDoc, String title, String newBranchName) {
        //调用GitLink创建合并请求接口
        JSONObject requestBody = new JSONObject();
        requestBody.put("head", newBranchName);
        requestBody.put("base", CmsConstants.BRANCH_MASTER);
        requestBody.put("title", title);
        JSONObject result = gitLinkRequestHelper.doPost(
                CmsGitLinkRequestUrl.CREATE_PULL_REQUEST(cmsProject),
                requestBody);
        cmsDoc.setAuditPrNumber(result.getString("pull_request_number") + "-" + result.getString("pull_request_id"));
    }
    @Override
    public CmsDoc updateCmsDocDatabaseAndUpdateForGitLink(CmsDoc oldCmsDoc, CmsDocDto cmsDocDto, String branchName) {
        if (oldCmsDoc == null) {
            throw new ServiceException("该文章不存在(文章Id[" + oldCmsDoc.getId() + "])");
        }
        cmsDocService.setCmsSort(cmsDocDto.getOrder(), oldCmsDoc, cmsDocDto.isChangeOnDir(), oldCmsDoc.getIsHomepage());
        //获取专区项目
        CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(oldCmsDoc.getDeptId());
        String content = cmsDocDto.getContent();
        //获取原文章内容
        String oldContent = cmsDocService.getCmsDocFileContent(cmsProject, oldCmsDoc);
        Boolean isChangeName = false;
        Boolean isChangeDir = false;
        String newDirName = null;
        String newName = null;

        //检查文章是否需要更换栏目
        if (cmsDocDto.getDirId() != null) {
            CmsDoc newCmsDir = cmsDocMapper.selectCmsDocDirById(cmsDocDto.getDirId());
            if (newCmsDir == null) {
                throw new ServiceException("该栏目不存在(栏目Id[" + cmsDocDto.getDirId() + "])");
            }
            if (!newCmsDir.getName().equals(oldCmsDoc.getDirName())) {
                isChangeDir = true;
                newDirName = newCmsDir.getName();
            }
        }

        // 此时gitlink未提供重命名文件接口，故采用此方案
        // 若文章名称发生了变更，则删除原文件创建新的文章
        if (StringUtils.isNotEmpty(cmsDocDto.getName())
                && !oldCmsDoc.getName().equals(cmsDocDto.getName())) {
            isChangeName = true;
            newName = cmsDocDto.getName();
        } else {
            newName = oldCmsDoc.getName();
        }

        if (isChangeName || isChangeDir) {
            oldCmsDoc = renameAndChangeDirCmsDoc(oldCmsDoc, cmsProject, newName, newDirName, branchName);
            //todo 此处是否需要更新数据库待讨论
            //updateCmsCommonDatabase(oldCmsDoc);
        }

        boolean isChangeContent = false;
        if (content != null) {
            String newMd5 = DigestUtils.md5DigestAsHex(content.getBytes());
            String oldMd5 = null;
            if (StringUtils.isNotEmpty(oldContent)) {
                oldMd5 = DigestUtils.md5DigestAsHex(oldContent.getBytes());
            }
            if (!newMd5.equals(oldMd5)) {
                isChangeContent = true;
            }
        }

        //当更改了文件名或更新了文章内容时
        if (isChangeName || isChangeContent || isChangeDir) {
            if (StringUtils.isEmpty(content)) {
                content = oldContent;
            }
            updateCmsDocContentForGitLink(cmsProject, oldCmsDoc, content, branchName);
        }
        oldCmsDoc.setSummary(cmsDocDto.getSummary());
        oldCmsDoc.setHeadImg(cmsDocDto.getHeadImg());
        return oldCmsDoc;
    }

    @Override
    public boolean deleteCmsDocForGitLink(CmsDoc cmsDoc, CmsProject cmsProject, String branchName) {
        if (cmsDoc.getIsDir()) {
            //当删除文章为文件夹时，判断该文件夹下是否存在文章，若存在需先删除所有文章
            JSONObject getSubEntriesResult = gitLinkRequestHelper.doGet(
                    CmsGitLinkRequestUrl.GET_DIR_SUB_ENTRIES(
                            cmsProject,
                            cmsDoc.getName(),
                            branchName));
            JSONArray entries = getSubEntriesResult.getJSONArray("entries");
            if (null != entries) {
                if (entries.size() != 1) {
                    throw new ServiceException("该栏目下存在文章，请先删除栏目下所有文章(栏目名称[" + cmsDoc.getName() + "])");
                } else {
                    //当该文件夹下仅一个文件且名称为.keep时，允许删除
                    String fileName = entries.getJSONObject(0).getString("name");
                    if (!CmsConstants.KEEP_FILE_NAME.equals(fileName)) {
                        throw new ServiceException("该栏目下存在非保留文件，请联系开发人员处理(非保留文件名称[" + fileName + "])");
                    }
                }
            }
        }
        // 删除前需获取该文件的最新SHA，基于最新SHA进行删除
        FileEntryDto deleteBeforeFileEntryDto = cmsDocService.getFileEntryDto(cmsProject, cmsDoc.getFilePath(), branchName);
        if (deleteBeforeFileEntryDto == null || deleteBeforeFileEntryDto.getEntries() == null) {
            throw new ServiceException("文章更新失败！");
        }
        JSONObject deleteResult = gitLinkRequestHelper.doDelete(
                CmsGitLinkRequestUrl.DELETE_FILE(
                        cmsProject,
                        cmsDoc.getFilePath(),
                        deleteBeforeFileEntryDto.getEntries().getSha(),
                        branchName));
        if (deleteResult.containsKey(GitLinkConstants.STATUS_KEY)) {
            //若请求GitLink删除操作返回正确的状态值，返回删除成功
            return deleteResult.getInteger(GitLinkConstants.STATUS_KEY).equals(1);
        }
        return false;
    }

    private void updateCmsDocContentForGitLink(CmsProject cmsProject, CmsDoc oldCmsDoc, String content, String branchName) {
        //更新前需获取该文件的最新SHA，基于最新SHA进行更新
        FileEntryDto updateBeforeFileEntryDto = cmsDocService.getFileEntryDto(cmsProject, oldCmsDoc.getFilePath(), branchName);
        if (updateBeforeFileEntryDto == null || updateBeforeFileEntryDto.getEntries() == null) {
            throw new ServiceException("文章更新失败！");
        }
        JSONObject updateFile = new JSONObject();
        updateFile.put("base64_filepath", contentToBase64(oldCmsDoc.getFilePath()));
        updateFile.put("branch", branchName);
        updateFile.put("content", content);
        updateFile.put("message", "更新文章：" + oldCmsDoc.getName());
        updateFile.put("filepath", oldCmsDoc.getFilePath());
        updateFile.put("sha", updateBeforeFileEntryDto.getEntries().getSha());
        gitLinkRequestHelper.doPut(CmsGitLinkRequestUrl.UPDATE_FILE(cmsProject), updateFile);
        FileEntryDto updateAfterFileEntryDto = cmsDocService.getFileEntryDto(cmsProject, oldCmsDoc.getFilePath(), branchName);
        if (updateAfterFileEntryDto != null && updateAfterFileEntryDto.getEntries() != null) {
            EntryDto entryDto = updateAfterFileEntryDto.getEntries();
            oldCmsDoc.setFileSha(entryDto.getSha());
            oldCmsDoc.setFileSize(entryDto.getSize());
        }
    }

    private CmsDoc renameAndChangeDirCmsDoc(CmsDoc oldCmsDoc, CmsProject cmsProject, String newName, String newDirName, String branchName) {
        JSONArray batchUpdateFiles = new JSONArray();
        JSONObject requestBody = new JSONObject();
        JSONObject addFile = new JSONObject();
        JSONObject deleteFile = new JSONObject();

        deleteFile.put("action_type", "delete");
        deleteFile.put("content", "");
        deleteFile.put("encoding", "text");
        deleteFile.put("file_path", oldCmsDoc.getFilePath());
        batchUpdateFiles.add(deleteFile);
        CmsDoc dirDoc = cmsDocMapper.selectCmsDocDirByNameAndDeptId(oldCmsDoc.getDirName(), oldCmsDoc.getDeptId());
        if (dirDoc == null) {
            throw new ServiceException("该栏目不存在(栏目名称[" + oldCmsDoc.getDirName() + "])");
        }
        String msg = "";
        if (StringUtils.isNotEmpty(newName) && !newName.equals(oldCmsDoc.getName())) {
            msg = String.format("重命名文章：由[%s]重命名为[%s];", oldCmsDoc.getName(), newName);
        } else {
            newName = oldCmsDoc.getName();
        }

        if (StringUtils.isNotEmpty(newDirName) && !oldCmsDoc.getDirName().equals(newDirName)) {
            String changeNameMsg = String.format("切换文章所在栏目：文章[%s]由[%s]栏目切换为[%s]栏目;", oldCmsDoc.getName(), oldCmsDoc.getDirName(), newDirName);
            if (StringUtils.isNotEmpty(msg)) {
                msg = String.format("1、%s\n2、%s", changeNameMsg, msg);
            } else {
                msg = changeNameMsg;
            }
        } else {
            newDirName = oldCmsDoc.getDirName();
        }

        String newFileName = newName + CmsConstants.MARKDOWN_SUFFIX;
        String newFilePath = newDirName + "/" + newFileName;

        addFile.put("action_type", "add");
        addFile.put("content", "");
        addFile.put("encoding", "text");
        addFile.put("file_path", newFilePath);
        batchUpdateFiles.add(addFile);
        requestBody.put("files", batchUpdateFiles);

        doUpdateFileRequest(cmsProject, requestBody, msg, branchName);
        oldCmsDoc.setName(newName);
        oldCmsDoc.setDirName(newDirName);
        oldCmsDoc.setFileName(newFileName);
        oldCmsDoc.setFilePath(newFilePath);
        return oldCmsDoc;
    }

    private void doUpdateFileRequest(CmsProject cmsProject, JSONObject requestBody, String msg, String branchName) {
        requestBody.put("branch", branchName);
        requestBody.put("message", msg);

        //update_file接口不返回更新文件的新SHA值，故需要通过批量更新接口来操作
        //调用GitLink批量更新文件接口，更新文章内容
        gitLinkRequestHelper.doPost(
                CmsGitLinkRequestUrl.BATCH_UPDATE_FILE(cmsProject),
                requestBody);
    }

    @Override
    @Async
    public void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, CmsDoc newCmsDir) {
        try {
            remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 1, SecurityConstants.INNER);
            //创建新栏目
            String message = String.format("重命名栏目：由[%s]重命名为[%s]", oldCmsDir.getName(), newCmsDir.getName());
            cmsDocService.createFileByGitLink(newCmsDir, message, "");
            //在数据库中重命名该栏目，防止后续操作推送的WebHook重复创建栏目
            cmsDocService.updateCmsCommonDatabase(newCmsDir, CmsConstants.BRANCH_MASTER);
            //将原栏目中所有文章移动到新栏目中
            moveCmsDocToNewCmsDir(cmsProject, oldCmsDir.getName(), newCmsDir.getName(), message);
            //删除旧栏目
            deleteCmsDocByGitLink(cmsProject, oldCmsDir);
        } catch (Exception e) {
            logger.error("重命名栏目失败(原栏目名称[{}],新栏目名称[{}])：{}", oldCmsDir.getName(), newCmsDir.getName(), e.getMessage());
            throw new ServiceException("重命名栏目失败(原栏目名称[" + oldCmsDir.getName() + "],新栏目名称[" + newCmsDir.getName() + "])");
        } finally {
            remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 0, SecurityConstants.INNER);
        }
    }

    @Async
    @Override
    public void pushDocDataSearchEngine(CmsDoc cmsDoc) {
        String docDetailUrl = cmsDocService.getDocDetailUrl(cmsDoc.getDeptId(), cmsDoc.getId());
        String gitlinkUrl = gitLinkRequestHelper.gitLinkUrl;
        if (!gitlinkUrl.toLowerCase().contains("gitlink")) {
            logger.warn("测试环境不推送文章至搜索引擎");
            return;
        }

        try {
            // 推送至百度搜索
            String baiduSearchPushUrl = String.format("%s?site=%s&token=%s", baiduSearchUrl, gitlinkUrl, baiduSearchToken);
            // 声明httpPost请求
            HttpPost httpPost = new HttpPost(baiduSearchPushUrl);
            // 加入配置信息
            httpPost.setConfig(config);
            String[] param = {
                    docDetailUrl
            };

            StringEntity stringEntity = new StringEntity(String.join(",", param), Constants.UTF8);
            stringEntity.setContentEncoding(Constants.UTF8);
            stringEntity.setContentType(Constants.TEXT_CONTENT_TYPE);
            // 把表单放到post里
            httpPost.setEntity(stringEntity);
            JSONObject res = httpAPIService.doRequest(httpPost, null);
            logger.info("推送文章【{}】至百度搜索成功，请求响应为：{}", cmsDoc.getName(), res);
        } catch (Exception e) {
            logger.error("推送文章【{}】至百度搜索引擎失败：{0}", cmsDoc.getName(), e);
        }
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("siteUrl", gitlinkUrl);
            JSONArray jsonArray = new JSONArray();
            jsonArray.add(docDetailUrl);
            jsonObject.put("urlList", jsonArray);
            // 推送至Bing搜索
            String bingSearchPushUrl = String.format("%s?apikey=%s", bingSearchUrl, bingSearchToken);
            JSONObject res = httpAPIService.doPost(bingSearchPushUrl, jsonObject);
            logger.info("推送文章【{}】至Bing搜索成功，请求响应为：{}", cmsDoc.getName(), res);
        } catch (Exception e) {
            logger.error("推送文章【{}】至Bing搜索引擎失败：{0}", cmsDoc.getName(), e);
        }
    }

    private void moveCmsDocToNewCmsDir(CmsProject cmsProject, String oldDirName, String newDirName, String message) {
        CmsDocSearchVo cmsDocSearch = new CmsDocSearchVo();
        cmsDocSearch.setIsDir(false);
        cmsDocSearch.setDeptId(cmsProject.getDeptId());
        cmsDocSearch.setDirName(oldDirName);
        List<CmsDoc> oldCmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearch);
        for (CmsDoc oldCmsDoc : oldCmsDocList) {
            //TODO:需调整为并行处理（当前因并行请求GitLink创建文件接口提示系统错误）
            long start = System.currentTimeMillis();
            String log = String.format("移动文章[%s]：", oldCmsDoc.getName());
            System.out.println(log + "开始移动");
            CmsDoc updateCmsDoc = new CmsDoc();
            String newFilePath = newDirName + "/" + oldCmsDoc.getFileName();
            updateCmsDoc.setId(oldCmsDoc.getId());
            updateCmsDoc.setDirName(newDirName);
            updateCmsDoc.setFilePath(newFilePath);
            updateCmsDoc.setDeptId(oldCmsDoc.getDeptId());
            updateCmsDoc.setUpdateTime(DateUtils.getNowDate());
            updateCmsDoc.setUpdateBy(SecurityUtils.getUsername());
            boolean success = cmsDocMapper.updateCmsDoc(updateCmsDoc) > 0;
            if (success) {
                long time = System.currentTimeMillis() - start;
                System.out.println(log + "更新数据库成功，耗时：" + time);
                String content = cmsDocService.getCmsDocFileContent(cmsProject, oldCmsDoc);
                time = System.currentTimeMillis() - start;
                System.out.println(log + "获取文章内容成功，耗时：" + time);

                cmsDocService.createFileByGitLink(updateCmsDoc, message, content);
                time = System.currentTimeMillis() - start;
                System.out.println(log + "在新栏目中创建文章成功，耗时：" + time);
                //删除旧文章
                deleteCmsDocByGitLink(cmsProject, oldCmsDoc);
                time = System.currentTimeMillis() - start;
                System.out.println(log + "删除旧文章成功，耗时：" + time);
            }
            cmsDocService.updateCmsPublishData(updateCmsDoc, CmsConstants.BRANCH_MASTER);
        }
    }

    private void deleteCmsDocByGitLink(CmsProject cmsProject, CmsDoc cmsDoc) {
        FileEntryDto oldCmsDirFileEntry = cmsDocService.getFileEntryDto(cmsProject, cmsDoc.getFilePath(), CmsConstants.BRANCH_MASTER);
        if (oldCmsDirFileEntry != null && oldCmsDirFileEntry.getEntries() != null) {
            //删除原栏目
            gitLinkRequestHelper.doDelete(
                    CmsGitLinkRequestUrl.DELETE_FILE(
                            cmsProject,
                            cmsDoc.getFilePath(),
                            oldCmsDirFileEntry.getEntries().getSha(),
                            CmsConstants.BRANCH_MASTER));
        }
    }

}
