content: /*
   * Copyright 1999-2018 Alibaba Group Holding Ltd.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.alibaba.nacos.config.server.controller;
  
  import com.alibaba.nacos.auth.annotation.Secured;
  import com.alibaba.nacos.common.model.RestResult;
  import com.alibaba.nacos.common.model.RestResultUtils;
  import com.alibaba.nacos.common.notify.NotifyCenter;
  import com.alibaba.nacos.common.utils.StringUtils;
  import com.alibaba.nacos.config.server.configuration.ConfigCommonConfig;
  import com.alibaba.nacos.config.server.constant.Constants;
  import com.alibaba.nacos.config.server.paramcheck.ConfigDefaultHttpParamExtractor;
  import com.alibaba.nacos.config.server.service.dump.DumpService;
  import com.alibaba.nacos.config.server.utils.LogUtil;
  import com.alibaba.nacos.core.controller.compatibility.Compatibility;
  import com.alibaba.nacos.core.paramcheck.ExtractorManager;
  import com.alibaba.nacos.core.utils.WebUtils;
  import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
  import com.alibaba.nacos.persistence.datasource.DynamicDataSource;
  import com.alibaba.nacos.persistence.datasource.LocalDataSourceServiceImpl;
  import com.alibaba.nacos.persistence.model.event.DerbyImportEvent;
  import com.alibaba.nacos.persistence.repository.embedded.operate.DatabaseOperate;
  import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
  import com.alibaba.nacos.plugin.auth.constant.ApiType;
  import com.alibaba.nacos.plugin.auth.constant.SignType;
  import com.alibaba.nacos.sys.utils.ApplicationUtils;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.jdbc.core.JdbcTemplate;
  import org.springframework.web.bind.annotation.GetMapping;
  import org.springframework.web.bind.annotation.PostMapping;
  import org.springframework.web.bind.annotation.PutMapping;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RequestParam;
  import org.springframework.web.bind.annotation.RestController;
  import org.springframework.web.context.request.async.DeferredResult;
  import org.springframework.web.multipart.MultipartFile;
  
  import jakarta.servlet.http.HttpServletResponse;
  import java.util.List;
  import java.util.Map;
  import java.util.Objects;
  
  /**
   * Manage controllers.
   *
   * @author Nacos
   */
  @Deprecated
  @RestController
  @RequestMapping(Constants.OPS_CONTROLLER_PATH)
  @ExtractorManager.Extractor(httpExtractor = ConfigDefaultHttpParamExtractor.class)
  public class ConfigOpsController {
      
      private static final Logger LOGGER = LoggerFactory.getLogger(ConfigOpsController.class);
      
      private final DumpService dumpService;
      
      public ConfigOpsController(DumpService dumpService) {
          this.dumpService = dumpService;
      }
      
      /**
       * Manually trigger dump of a local configuration file.
       */
      @PostMapping(value = "/localCache")
      @Secured(resource = Constants.OPS_CONTROLLER_PATH, action = ActionTypes.WRITE, signType = SignType.CONSOLE)
      @Compatibility(apiType = ApiType.ADMIN_API, alternatives = "POST {contextPath:nacos}/v3/admin/cs/ops/localCache")
      public String updateLocalCacheFromStore() {
          LOGGER.info("start to dump all data from store.");
          dumpService.dumpAll();
          LOGGER.info("finish to dump all data from store.");
          return HttpServletResponse.SC_OK + "";
      }
      
      @PutMapping(value = "/log")
      @Secured(resource = Constants.OPS_CONTROLLER_PATH, action = ActionTypes.WRITE, signType = SignType.CONSOLE)
      @Compatibility(apiType = ApiType.ADMIN_API, alternatives = "PUT {contextPath:nacos}/v3/admin/cs/ops/log")
      public String setLogLevel(@RequestParam String logName, @RequestParam String logLevel) {
          LogUtil.setLogLevel(logName, logLevel);
          return HttpServletResponse.SC_OK + "";
      }
      
      /**
       * // TODO In a future release, the front page should appear operable The interface to the Derby operations query
       * can only run select statements and is a direct query to the native Derby database without any additional logic.
       *
       * @param sql The query
       * @return {@link RestResult}
       */
      @GetMapping(value = "/derby")
      @Secured(action = ActionTypes.READ, resource = "nacos/admin")
      @Compatibility(apiType = ApiType.ADMIN_API, alternatives = "GET {contextPath:nacos}/v3/admin/cs/ops/derby")
      public RestResult<Object> derbyOps(@RequestParam(value = "sql") String sql) {
          String selectSign = "SELECT";
          String limitSign = "ROWS FETCH NEXT";
          String limit = " OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY";
          try {
              if (!DatasourceConfiguration.isEmbeddedStorage()) {
                  return RestResultUtils.failed("The current storage mode is not Derby");
              }
              if (!ConfigCommonConfig.getInstance().isDerbyOpsEnabled()) {
                  return RestResultUtils.failed(
                          "Derby ops is disabled, please set `nacos.config.derby.ops.enabled=true` to enabled this feature.");
              }
              LocalDataSourceServiceImpl dataSourceService = (LocalDataSourceServiceImpl) DynamicDataSource.getInstance()
                      .getDataSource();
              if (StringUtils.startsWithIgnoreCase(sql, selectSign)) {
                  if (!StringUtils.containsIgnoreCase(sql, limitSign)) {
                      sql += limit;
                  }
                  JdbcTemplate template = dataSourceService.getJdbcTemplate();
                  List<Map<String, Object>> result = template.queryForList(sql);
                  return RestResultUtils.success(result);
              }
              return RestResultUtils.failed("Only query statements are allowed to be executed");
          } catch (Exception e) {
              return RestResultUtils.failed(e.getMessage());
          }
      }
      
      /**
       * // TODO the front page should appear operable The external data source is imported into derby.
       *
       * <p>mysqldump --defaults-file="XXX" --host=0.0.0.0 --protocol=tcp --user=XXX --extended-insert=FALSE \
       * --complete-insert=TRUE \ --skip-triggers --no-create-info --skip-column-statistics "{SCHEMA}" "{TABLE_NAME}"
       *
       * @param multipartFile {@link MultipartFile}
       * @return {@link DeferredResult}
       */
      @PostMapping(value = "/data/removal")
      @Secured(action = ActionTypes.WRITE, resource = "nacos/admin")
      @Compatibility(apiType = ApiType.ADMIN_API, alternatives = "POST {contextPath:nacos}/v3/admin/cs/ops/derby/import")
      public DeferredResult<RestResult<String>> importDerby(@RequestParam(value = "file") MultipartFile multipartFile) {
          DeferredResult<RestResult<String>> response = new DeferredResult<>();
          if (!DatasourceConfiguration.isEmbeddedStorage()) {
              response.setResult(RestResultUtils.failed("Limited to embedded storage mode"));
              return response;
          }
          if (!ConfigCommonConfig.getInstance().isDerbyOpsEnabled()) {
              response.setResult(RestResultUtils.failed(
                      "Derby ops is disabled, please set `nacos.config.derby.ops.enabled=true` to enabled this feature."));
              return response;
          }
          DatabaseOperate databaseOperate = ApplicationUtils.getBean(DatabaseOperate.class);
          WebUtils.onFileUpload(multipartFile, file -> {
              NotifyCenter.publishEvent(new DerbyImportEvent(false));
              databaseOperate.dataImport(file).whenComplete((result, ex) -> {
                  NotifyCenter.publishEvent(new DerbyImportEvent(true));
                  if (Objects.nonNull(ex)) {
                      response.setResult(RestResultUtils.failed(ex.getMessage()));
                      return;
                  }
                  response.setResult(result);
              });
          }, response);
          return response;
      }
      
  }
  