Forráskód Böngészése

1、接口&函数锁定和解锁。2、修复无法测试上传的问题

mxd 3 éve
szülő
commit
617f15aa0b

+ 33 - 2
magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicAPIController.java

@@ -1,5 +1,6 @@
 package org.ssssssss.magicapi.controller;
 
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
@@ -8,6 +9,7 @@ import org.ssssssss.magicapi.config.Valid;
 import org.ssssssss.magicapi.interceptor.Authorization;
 import org.ssssssss.magicapi.model.ApiInfo;
 import org.ssssssss.magicapi.model.Backup;
+import org.ssssssss.magicapi.model.Constants;
 import org.ssssssss.magicapi.model.JsonBean;
 
 import javax.servlet.http.HttpServletRequest;
@@ -33,7 +35,9 @@ public class MagicAPIController extends MagicController implements MagicExceptio
 	@ResponseBody
 	@Valid(readonly = false)
 	public JsonBean<Boolean> delete(HttpServletRequest request, String id) {
-		isTrue(allowVisit(request, Authorization.DELETE, getApiInfo(id)), PERMISSION_INVALID);
+		ApiInfo apiInfo = getApiInfo(id);
+		isTrue(allowVisit(request, Authorization.DELETE, apiInfo), PERMISSION_INVALID);
+		isTrue(!Constants.LOCK.equals(apiInfo.getLock()), RESOURCE_LOCKED);
 		return new JsonBean<>(magicAPIService.deleteApi(id));
 	}
 
@@ -102,6 +106,7 @@ public class MagicAPIController extends MagicController implements MagicExceptio
 		// 新的分组ID
 		apiInfo.setGroupId(groupId);
 		isTrue(allowVisit(request, Authorization.SAVE, apiInfo), PERMISSION_INVALID);
+		isTrue(!Constants.LOCK.equals(apiInfo.getLock()), RESOURCE_LOCKED);
 		return new JsonBean<>(magicAPIService.moveApi(id, groupId));
 	}
 
@@ -113,10 +118,36 @@ public class MagicAPIController extends MagicController implements MagicExceptio
 	@Valid(readonly = false)
 	public JsonBean<String> save(HttpServletRequest request, @RequestBody ApiInfo info) {
 		isTrue(allowVisit(request, Authorization.SAVE, info), PERMISSION_INVALID);
+		if (StringUtils.isNotBlank(info.getId())) {
+			ApiInfo oldInfo = getApiInfo(info.getId());
+			isTrue(!Constants.LOCK.equals(oldInfo.getLock()), RESOURCE_LOCKED);
+		}
 		return new JsonBean<>(magicAPIService.saveApi(info));
 	}
 
-	private ApiInfo getApiInfo(String id){
+	/**
+	 * 锁定接口
+	 */
+	@RequestMapping("/lock")
+	@ResponseBody
+	@Valid(readonly = false)
+	public JsonBean<Boolean> lock(HttpServletRequest request, String id) {
+		isTrue(allowVisit(request, Authorization.LOCK, getApiInfo(id)), PERMISSION_INVALID);
+		return new JsonBean<>(magicAPIService.lockApi(id));
+	}
+
+	/**
+	 * 解锁接口
+	 */
+	@RequestMapping("/unlock")
+	@ResponseBody
+	@Valid(readonly = false)
+	public JsonBean<Boolean> unlock(HttpServletRequest request, String id) {
+		isTrue(allowVisit(request, Authorization.UNLOCK, getApiInfo(id)), PERMISSION_INVALID);
+		return new JsonBean<>(magicAPIService.unlockApi(id));
+	}
+
+	private ApiInfo getApiInfo(String id) {
 		ApiInfo apiInfo = magicAPIService.getApiInfo(id);
 		notNull(apiInfo, API_NOT_FOUND);
 		return apiInfo;

+ 32 - 1
magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicFunctionController.java

@@ -1,5 +1,6 @@
 package org.ssssssss.magicapi.controller;
 
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
@@ -7,6 +8,7 @@ import org.ssssssss.magicapi.config.MagicConfiguration;
 import org.ssssssss.magicapi.config.Valid;
 import org.ssssssss.magicapi.interceptor.Authorization;
 import org.ssssssss.magicapi.model.Backup;
+import org.ssssssss.magicapi.model.Constants;
 import org.ssssssss.magicapi.model.FunctionInfo;
 import org.ssssssss.magicapi.model.JsonBean;
 
@@ -63,6 +65,7 @@ public class MagicFunctionController extends MagicController implements MagicExc
 		FunctionInfo functionInfo = getFunctionInfo(id);
 		functionInfo.setGroupId(groupId);
 		isTrue(allowVisit(request, Authorization.SAVE, functionInfo), PERMISSION_INVALID);
+		isTrue(!Constants.LOCK.equals(functionInfo.getLock()), RESOURCE_LOCKED);
 		return new JsonBean<>(magicAPIService.moveFunction(id, groupId));
 	}
 
@@ -72,6 +75,10 @@ public class MagicFunctionController extends MagicController implements MagicExc
 	@Valid(readonly = false)
 	public JsonBean<String> save(HttpServletRequest request, @RequestBody FunctionInfo functionInfo) {
 		isTrue(allowVisit(request, Authorization.SAVE, functionInfo), PERMISSION_INVALID);
+		if (StringUtils.isNotBlank(functionInfo.getId())) {
+			FunctionInfo oldInfo = getFunctionInfo(functionInfo.getId());
+			isTrue(!Constants.LOCK.equals(oldInfo.getLock()), RESOURCE_LOCKED);
+		}
 		return new JsonBean<>(magicAPIService.saveFunction(functionInfo));
 	}
 
@@ -79,10 +86,34 @@ public class MagicFunctionController extends MagicController implements MagicExc
 	@ResponseBody
 	@Valid(readonly = false)
 	public JsonBean<Boolean> delete(HttpServletRequest request, String id) {
-		isTrue(allowVisit(request, Authorization.DELETE, getFunctionInfo(id)), PERMISSION_INVALID);
+		FunctionInfo info = getFunctionInfo(id);
+		isTrue(allowVisit(request, Authorization.DELETE, info), PERMISSION_INVALID);
+		isTrue(!Constants.LOCK.equals(info.getLock()), RESOURCE_LOCKED);
 		return new JsonBean<>(magicAPIService.deleteFunction(id));
 	}
 
+	/**
+	 * 锁定函数
+	 */
+	@RequestMapping("/function/lock")
+	@ResponseBody
+	@Valid(readonly = false)
+	public JsonBean<Boolean> lock(HttpServletRequest request, String id) {
+		isTrue(allowVisit(request, Authorization.LOCK, getFunctionInfo(id)), PERMISSION_INVALID);
+		return new JsonBean<>(magicAPIService.lockFunction(id));
+	}
+
+	/**
+	 * 解锁函数
+	 */
+	@RequestMapping("/function/unlock")
+	@ResponseBody
+	@Valid(readonly = false)
+	public JsonBean<Boolean> unlock(HttpServletRequest request, String id) {
+		isTrue(allowVisit(request, Authorization.UNLOCK, getFunctionInfo(id)), PERMISSION_INVALID);
+		return new JsonBean<>(magicAPIService.unlockFunction(id));
+	}
+
 	public FunctionInfo getFunctionInfo(String id) {
 		FunctionInfo functionInfo = magicAPIService.getFunctionInfo(id);
 		notNull(functionInfo, FUNCTION_NOT_FOUND);

+ 9 - 1
magic-api/src/main/java/org/ssssssss/magicapi/interceptor/Authorization.java

@@ -28,5 +28,13 @@ public enum Authorization {
 	/**
 	 * 执行推送动作
 	 */
-	PUSH
+	PUSH,
+	/**
+	 * 锁定动作
+	 */
+	LOCK,
+	/**
+	 * 解锁动作
+	 */
+	UNLOCK
 }

+ 1 - 0
magic-api/src/main/java/org/ssssssss/magicapi/model/ApiInfo.java

@@ -264,6 +264,7 @@ public class ApiInfo extends MagicEntity {
 		target.setGroupId(this.getGroupId());
 		target.setPath(this.getPath());
 		target.setMethod(this.getMethod());
+		target.setLock(this.getLock());
 		return target;
 	}
 

+ 4 - 0
magic-api/src/main/java/org/ssssssss/magicapi/model/Constants.java

@@ -107,6 +107,10 @@ public class Constants {
 
 	public static final String UPLOAD_MODE_FULL = "full";
 
+	public static final String LOCK = "1";
+
+	public static final String UNLOCK = "0";
+
 	/**
 	 * 执行成功的code值
 	 */

+ 2 - 0
magic-api/src/main/java/org/ssssssss/magicapi/model/JsonCodeConstants.java

@@ -19,6 +19,8 @@ public interface JsonCodeConstants {
 
 	JsonCode NAME_CONFLICT = new JsonCode(0, "移动后名称会重复,请修改名称后在试。");
 
+	JsonCode RESOURCE_LOCKED = new JsonCode(0, "当前资源已被锁定,请解锁后在操作。");
+
 	JsonCode REQUEST_PATH_CONFLICT = new JsonCode(0, "该路径已被映射,请换一个请求方法或路径");
 
 	JsonCode FUNCTION_PATH_CONFLICT = new JsonCode(0, "该路径已被映射,请换一个请求方法或路径");

+ 10 - 0
magic-api/src/main/java/org/ssssssss/magicapi/model/MagicEntity.java

@@ -14,6 +14,8 @@ public class MagicEntity extends Attributes<Object> implements Cloneable {
 
 	protected Long updateTime;
 
+	protected String lock;
+
 	public String getId() {
 		return id;
 	}
@@ -62,6 +64,14 @@ public class MagicEntity extends Attributes<Object> implements Cloneable {
 		this.name = name;
 	}
 
+	public String getLock() {
+		return lock;
+	}
+
+	public void setLock(String lock) {
+		this.lock = lock;
+	}
+
 	public MagicEntity clone() {
 		try {
 			return (MagicEntity) super.clone();

+ 8 - 0
magic-api/src/main/java/org/ssssssss/magicapi/provider/MagicAPIService.java

@@ -47,6 +47,14 @@ public interface MagicAPIService extends MagicModule {
 	 */
 	String saveApi(ApiInfo apiInfo);
 
+	boolean lockApi(String id);
+
+	boolean unlockApi(String id);
+
+	boolean lockFunction(String id);
+
+	boolean unlockFunction(String id);
+
 	/**
 	 * 获取接口详情
 	 *

+ 19 - 0
magic-api/src/main/java/org/ssssssss/magicapi/provider/StoreServiceProvider.java

@@ -4,6 +4,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.ssssssss.magicapi.adapter.Resource;
+import org.ssssssss.magicapi.model.Constants;
 import org.ssssssss.magicapi.model.MagicEntity;
 import org.ssssssss.magicapi.utils.JsonUtils;
 
@@ -84,6 +85,24 @@ public abstract class StoreServiceProvider<T extends MagicEntity> {
 		return false;
 	}
 
+	public boolean lock(String id){
+		T info = get(id);
+		if(info != null){
+			info.setLock(Constants.LOCK);
+			return update(info);
+		}
+		return false;
+	}
+
+	public boolean unlock(String id){
+		T info = get(id);
+		if(info != null){
+			info.setLock(Constants.UNLOCK);
+			return update(info);
+		}
+		return false;
+	}
+
 	/**
 	 * 查询所有(提供给页面,无需带script)
 	 */

+ 27 - 0
magic-api/src/main/java/org/ssssssss/magicapi/provider/impl/DefaultMagicAPIService.java

@@ -228,6 +228,33 @@ public class DefaultMagicAPIService implements MagicAPIService, JsonCodeConstant
 		return info.getId();
 	}
 
+	@Override
+	public boolean lockApi(String id) {
+		return lockWithNotify(apiServiceProvider.lock(id), id, NOTIFY_ACTION_API);
+	}
+
+	@Override
+	public boolean unlockApi(String id) {
+		return lockWithNotify(apiServiceProvider.unlock(id), id, NOTIFY_ACTION_API);
+	}
+
+	@Override
+	public boolean lockFunction(String id) {
+		return lockWithNotify(functionServiceProvider.lock(id), id, NOTIFY_ACTION_FUNCTION);
+	}
+
+	@Override
+	public boolean unlockFunction(String id) {
+		return lockWithNotify(functionServiceProvider.unlock(id), id, NOTIFY_ACTION_FUNCTION);
+	}
+
+	private boolean lockWithNotify(boolean success, String id, int type){
+		if(success){
+			magicNotifyService.sendNotify(new MagicNotify(instanceId, id, NOTIFY_ACTION_UPDATE, type));
+		}
+		return success;
+	}
+
 	@Override
 	public ApiInfo getApiInfo(String id) {
 		return apiServiceProvider.get(id);

+ 8 - 0
magic-editor/src/console/src/assets/iconfont/iconfont.css

@@ -11,6 +11,14 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.ma-icon-lock:before {
+  content: "\e64f";
+}
+
+.ma-icon-unlock:before {
+  content: "\e783";
+}
+
 .ma-icon-collapse:before {
   content: "\e609";
 }

BIN
magic-editor/src/console/src/assets/iconfont/iconfont.ttf


+ 7 - 4
magic-editor/src/console/src/components/editor/magic-script-editor.vue

@@ -18,7 +18,8 @@
         >
           <i class="ma-svg-icon" v-if="item._type === 'api'" :class="['request-method-' + item.method]" />
           <i class="ma-svg-icon" v-if="item._type !== 'api'" :class="['icon-function']" />
-          {{item.name}}<span v-show="!item.id || item.script !== item.ext.tmpScript">*</span>
+          {{item.name}}<i class="ma-icon ma-icon-lock" v-if="item.lock === '1'" />
+          <span v-show="!item.id || item.script !== item.ext.tmpScript">*</span>
           <i class="ma-icon ma-icon-close" @click.stop="close(item.id || item.tmp_id)"/>
         </li>
       </ul>
@@ -548,7 +549,7 @@ export default {
         requestConfig.headers['Content-Type'] = 'multipart/form-data';
         let formData = new FormData()
         Object.keys(params).forEach(key => {
-          let value = requestConfig.data[key];
+          let value = params[key];
           if(value instanceof FileList){
             value.forEach(file => formData.append(key, file, file.name))
           }else{
@@ -958,12 +959,14 @@ ul li.draggableTargetItem {
   background: var(--hover-background);
 }
 
-ul li i {
+ul li i:not(.ma-icon-lock) {
   color: var(--icon-color);
   margin-left: 5px;
   font-size: 0.5em;
 }
-
+.ma-icon-lock{
+  margin-left: 5px;
+}
 .ma-editor-container > div {
   flex: 1;
 }

+ 20 - 0
magic-editor/src/console/src/components/resources/magic-api-list.vue

@@ -64,6 +64,7 @@
           <i class="ma-svg-icon" :class="['request-method-' + item.method]" />
           <label>{{ item.name }}</label>
           <span>({{ item.path }})</span>
+          <i class="ma-icon ma-icon-lock" v-if="item.lock === '1'"></i>
         </div>
       </template>
     </magic-tree>
@@ -320,6 +321,7 @@ export default {
                 parameters: null,
                 paths: null,
                 option: null,
+                lock: '0',
                 requestBody: null,
                 headers: null,
                 responseBody: null,
@@ -449,9 +451,27 @@ export default {
               this.copyPathToClipboard(item, true)
             }
           },
+          {
+            label: `${item.lock === '1' ? '解锁' : '锁定'}`,
+            icon: `ma-icon-${item.lock === '1' ? 'unlock' : 'lock'}`,
+            onClick: () => {
+              let action = item.lock === '1' ? '解锁接口' : '锁定接口';
+              request.send(item.lock === '1' ? 'unlock' : 'lock', {id: item.id}).success(data => {
+                if (data) {
+                  bus.$emit('status', `${action}「${item.name}(${item.path})」`)
+                  bus.$emit('report', `api_${item.lock === '1' ? 'unlock' : 'lock'}`)
+                  item['lock'] = item.lock === '1' ? '0' : '1';
+                  this.changeForceUpdate()
+                } else {
+                  this.$magicAlert({content: `${action}失败`})
+                }
+              })
+            }
+          },
           {
             label: '刷新接口',
             icon: 'ma-icon-refresh',
+            divided: true,
             onClick: () => {
               this.initData()
             }

+ 20 - 0
magic-editor/src/console/src/components/resources/magic-function-list.vue

@@ -62,6 +62,7 @@
           <i class="ma-svg-icon icon-function" />
           <label>{{ item.name }}</label>
           <span>({{ item.path }})</span>
+          <i class="ma-icon ma-icon-lock" v-if="item.lock === '1'"></i>
         </div>
       </template>
     </magic-tree>
@@ -319,6 +320,7 @@ export default {
                 path: '',
                 script: null,
                 name: '未定义名称',
+                lock: '0',
                 parameters: null,
                 description: null,
                 level: item.level + 1,
@@ -413,9 +415,27 @@ export default {
               this.open(newItem)
             }
           },
+          {
+            label: `${item.lock === '1' ? '解锁' : '锁定'}`,
+            icon: `ma-icon-${item.lock === '1' ? 'unlock' : 'lock'}`,
+            onClick: () => {
+              let action = item.lock === '1' ? '解锁函数' : '锁定函数';
+              request.send(item.lock === '1' ? 'function/unlock' : 'function/lock', {id: item.id}).success(data => {
+                if (data) {
+                  bus.$emit('status', `${action}「${item.name}(${item.path})」`)
+                  bus.$emit('report', `function_${item.lock === '1' ? 'unlock' : 'lock'}`)
+                  item['lock'] = item.lock === '1' ? '0' : '1';
+                  this.changeForceUpdate()
+                } else {
+                  this.$magicAlert({content: `${action}失败`})
+                }
+              })
+            }
+          },
           {
             label: '刷新函数',
             icon: 'ma-icon-refresh',
+            divided: true,
             onClick: () => {
               this.initData()
             }

+ 11 - 0
magic-editor/src/console/src/components/resources/magic-resource.css

@@ -41,10 +41,21 @@
 
 .ma-tree-wrapper span {
     color: var(--toolbox-list-span-color);
+    display: inline-block;
+    height: 22px;
+    line-height: 22px;
+}
+
+.ma-tree-wrapper .ma-icon-lock {
+    color: var(--toolbox-list-label-color);
+    margin-left: 5px;
 }
 
 .ma-tree-wrapper label {
     color: var(--toolbox-list-label-color);
+    display: inline-block;
+    height: 22px;
+    line-height: 22px;
 }
 
 .ma-tree-wrapper .ma-tree-toolbar-search {