# EventController.java

    package cloud.wconnect.rateshop.controller.rateshop;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.cons.CommonFieldI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.ForbiddenException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.commonlib.util.UpdateLogUtil;
    import cloud.wconnect.commonlib.util.UploadUtils;
    import cloud.wconnect.rateshop.cons.rateshop.EventDatasourceEnum;
    import cloud.wconnect.rateshop.entity.rateshop.Event;
    import cloud.wconnect.rateshop.entity.rateshop.EventSourceLocation;
    import cloud.wconnect.rateshop.entity.rateshop.EventSourceSetting;
    import cloud.wconnect.rateshop.entity.rateshop.EventSourceUrl;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.event.EventDTO;
    import cloud.wconnect.rateshop.pojo.query.rateshop.EventQuery;
    import cloud.wconnect.rateshop.pojo.vo.rateshop.event.CalendarEventVO;
    import cloud.wconnect.rateshop.pojo.vo.rateshop.event.EventSourceSettingVO;
    import cloud.wconnect.rateshop.service.rateshop.IEventService;
    import cloud.wconnect.rateshop.service.rateshop.IEventSourceLocationService;
    import cloud.wconnect.rateshop.service.rateshop.IEventSourceSettingService;
    import cloud.wconnect.rateshop.service.rateshop.IEventSourceUrlService;
    import com.google.common.collect.Lists;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;

    import jakarta.validation.Valid;

    import java.text.MessageFormat;
    import java.util.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * 事件 控制层
     *
     * @author lichen
     * @date 2023/6/19
     */
    @RestController
    @RequestMapping("/rate-shop/event")
    public class EventController {

        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private IEventService eventService;
        @Autowired
        private UpdateLogUtil updateLogUtil;
        @Autowired
        private IEventSourceSettingService eventSourceSettingService;
        @Autowired
        private IEventSourceLocationService eventSourceLocationService;
        @Autowired
        private IEventSourceUrlService eventSourceUrlService;
        @Autowired
        private BeanMapper beanMapper;
        @Value("${file-max-size.rate-shop}")
        private long fileMaxSize;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 查询事件
         *
         * @param property   资产标识
         * @param eventQuery 事件查询对象
         * @return java.util.List<cloud.wconnect.rateshop.pojo.vo.event.CalendarEventVO>
         * @author lichen
         * @date 2023/6/19
         */
        @ApiId(359)
        @GetMapping
        public List<CalendarEventVO> list(String property, @Valid EventQuery eventQuery) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //把yyyy-MM-dd的日期转化成时间戳
            long fromTimestamp = DateTimeUtils.dateStrToEpochSecond(eventQuery.getFromDate(), BaseConstant.DATE_FORMAT_YYYY_MM_DD, propertyDTO.getTimezone());
            long toTimestamp = DateTimeUtils.dateStrToEpochSecond(eventQuery.getToDate(), BaseConstant.DATE_FORMAT_YYYY_MM_DD, propertyDTO.getTimezone());
            //开始时间不能大于结束时间
            if (fromTimestamp > toTimestamp) {
                throw new BadRequestException(CommonErrorI18nConstant.START_DATE_CANNOT_GREATER_THAN_END_DATE,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "The toDate must be greater than or equal to the fromDate");
            }
            //判断时间间隔必须小于70天
            long diffDay = DateTimeUtils.dateDiffOfDays(fromTimestamp, toTimestamp, propertyDTO.getTimezone());
            //此处限制最大区间70天
            if (Math.abs(diffDay) > 70) {
                throw new BadRequestException(CommonErrorI18nConstant.SELECT_DATE_LIMIT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate(70),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "The interval between fromDate and toDate must be less than or equal to 70 days");
            }
            //查询事件信息
            return eventService.list(propertyDTO, eventQuery);
        }

        /**
         * 新增事件
         *
         * @param property 资产标识
         * @param eventDTO 事件dto
         * @return java.util.Map
         * @author lichen
         * @date 2023/6/19
         */
        @ApiId(360)
        @PostMapping
        public Map save(String property, @Valid @RequestBody EventDTO eventDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();
            //校验locationId是否存在
            eventSourceLocationService.checkExist(eventDTO.getLocationId());
            //校验资产是否关联locationId
            eventSourceSettingService.checkLocationBelong(eventDTO.getLocationId(), propertyDTO.getId());
            //设置资产id
            eventDTO.setPropertyId(propertyDTO.getId());
            //设置租户id
            eventDTO.setTenantId(sessionContext.getTenantSymbolBO().getId());
            //设置updateLog日志信息
            eventDTO.setUpdateLog(updateLogUtil.get(loginUserId));
            //新增事件
            return eventService.saveOrUpdate(propertyDTO, eventDTO);
        }

        /**
         * 修改事件
         *
         * @param id       事件主键id
         * @param property 资产标识
         * @param eventDTO 事件dto
         * @return java.util.Map
         * @author lichen
         * @date 2023/6/19
         */
        @ApiId(361)
        @PutMapping("/{id:\\d+}")
        public Map update(@PathVariable Integer id, String property,
                          @Valid @RequestBody EventDTO eventDTO) {
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();
            //校验事件是否存在 且 是否手动创建
            Event event = eventService.checkExistAndIsManualCreate(id);
            //校验事件归属
            checkBelong(tenantId, propertyId, event);
            //校验locationId是否存在
            eventSourceLocationService.checkExist(eventDTO.getLocationId());
            //校验资产是否关联locationId
            eventSourceSettingService.checkLocationBelong(eventDTO.getLocationId(), propertyId);
            //设置资产id
            eventDTO.setPropertyId(propertyId);
            //设置租户id
            eventDTO.setTenantId(tenantId);
            //设置事件id
            eventDTO.setId(id);
            //设置updateLog日志信息
            eventDTO.setUpdateLog(updateLogUtil.append(event.getUpdateLog(), loginUserId));
            //修改事件
            return eventService.saveOrUpdate(propertyDTO, eventDTO);
        }

        /**
         * 删除事件
         *
         * @param id       事件id
         * @param property 资产标识
         * @return java.util.Map
         * @author lichen
         * @date 2023/6/19
         */
        @ApiId(362)
        @DeleteMapping("/{id:\\d+}")
        public Map delete(@PathVariable Integer id, String property) {
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            int propertyId = sessionContext.getPropertyId(property);
            //校验事件是否存在 且 是否手动创建
            Event event = eventService.checkExistAndIsManualCreate(id);
            //校验事件归属
            checkBelong(tenantId, propertyId, event);
            //删除事件
            eventService.removeById(id);
            return Collections.emptyMap();
        }

        /**
         * 导入事件
         *
         * @param property 资产标识
         * @param file     excel文件
         * @return java.util.Map
         * @author lichen
         * @date 2023/12/20
         */
        @ApiId(1013)
        @PostMapping("/import")
        public Map importExcel(String property, MultipartFile file) {
            if (Objects.isNull(file)) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(CommonFieldI18nConstant.FILE),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "The file cannot be null");
            }
            //校验文件
            UploadUtils.checkFileFormat(file, Lists.newArrayList("xls", "xlsx"));
            //校验文件大小
            if (file.getSize() > fileMaxSize) {
                throw new BadRequestException(CommonErrorI18nConstant.FILE_SIZE_ERROR,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "The fileSize max is 20 MB");
            }
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();
            //导入
            eventService.importExcel(propertyDTO, file, loginUserId);
            return Collections.emptyMap();
        }

        /**
         * 查询资产的事件源配置
         *
         * @param property 资产
         * @return java.util.List<cloud.wconnect.rateshop.pojo.vo.rateshop.event.EventSourceSettingVO>
         * @author lichen
         * @date 2024/3/2
         */
        @ApiId(1033)
        @GetMapping("/event-source-setting")
        public List<EventSourceSettingVO> listEventSourceSetting(String property) {
            int propertyId = sessionContext.getPropertyId(property);
            List<EventSourceSetting> eventSourceSettings = eventSourceSettingService.listByPropertyId(propertyId);
            if (CollectionUtils.isEmpty(eventSourceSettings)) return Collections.emptyList();

            //查询location信息
            Set<Integer> locationSet = eventSourceSettings.stream().map(EventSourceSetting::getLocationId).collect(Collectors.toSet());
            Map<Integer, String> locationId2Location = eventSourceLocationService.listByIds(locationSet)
                    .stream().collect(Collectors.toMap(EventSourceLocation::getId, EventSourceLocation::getLocation));

            //查询url信息
            List<Integer> urlIds = eventSourceSettings.stream().map(EventSourceSetting::getUrlId).collect(Collectors.toList());
            Map<Integer, EventSourceUrl> urlId2Url = eventSourceUrlService.listByIds(urlIds)
                    .stream().collect(Collectors.toMap(EventSourceUrl::getId, Function.identity()));

            return beanMapper.mapList(eventSourceSettings, EventSourceSettingVO.class, (entity, vo) -> {
                //设置location信息
                vo.setLocation(locationId2Location.get(entity.getLocationId()));
                //设置url信息
                EventSourceUrl eventSourceUrl = urlId2Url.get(entity.getUrlId());
                vo.setSymbol(EventDatasourceEnum.getSymbol(eventSourceUrl.getDatasourceId()));
                vo.setDatasourceId(eventSourceUrl.getDatasourceId());
            });
        }

        /**
         * 校验事件归属
         *
         * @param tenantId   租户id
         * @param propertyId 资产id
         * @param event      事件对象
         * @return void
         * @author lichen
         * @date 2023/6/19
         */
        private void checkBelong(Integer tenantId, Integer propertyId, Event event) {
            if (!event.getTenantId().equals(tenantId) || !event.getPropertyId().equals(propertyId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("The event is not affiliation to tenantId:{0}," +
                                        " propertyId:{1}; eventTenantId:{2}, eventPropertyId:{3}",
                                tenantId, propertyId, event.getTenantId(), event.getPropertyId()));
            }
        }

    }