From 470b0de70dcc6f2002cd9506a3eb251f3abde7b3 Mon Sep 17 00:00:00 2001
From: Ryan Wang
Date: Tue, 26 Sep 2023 23:34:16 +0800
Subject: [PATCH 1/3] refactor: user detail page structure (#4664)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
#### What type of PR is this?
/area console
/kind improvement
/milestone 2.10.x
#### What this PR does / why we need it:
重构 Console 端用户详情页面的结构。
1. 提高代码可读性。
2. 使用问号参数来区分不同的选项卡。
3. 封装头像修改相关的代码为组件。
#### Special notes for your reviewer:
测试用户详情页面的所有功能是否正常。
#### Does this PR introduce a user-facing change?
```release-note
重构 Console 端用户详情页面的代码结构。
```
---
.../src/modules/system/users/UserDetail.vue | 319 +++++++++-------
.../system/users/components/UserAvatar.vue | 186 +++++++++
.../users/layouts/UserProfileLayout.vue | 355 ------------------
console/src/modules/system/users/module.ts | 14 +-
.../src/modules/system/users/tabs/Detail.vue | 168 +++++++++
.../users/{ => tabs}/PersonalAccessTokens.vue | 4 +-
6 files changed, 533 insertions(+), 513 deletions(-)
create mode 100644 console/src/modules/system/users/components/UserAvatar.vue
delete mode 100644 console/src/modules/system/users/layouts/UserProfileLayout.vue
create mode 100644 console/src/modules/system/users/tabs/Detail.vue
rename console/src/modules/system/users/{ => tabs}/PersonalAccessTokens.vue (93%)
diff --git a/console/src/modules/system/users/UserDetail.vue b/console/src/modules/system/users/UserDetail.vue
index 73b4b62b461..33915d7df39 100644
--- a/console/src/modules/system/users/UserDetail.vue
+++ b/console/src/modules/system/users/UserDetail.vue
@@ -1,168 +1,199 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ user?.user.spec.displayName }}
+
+
+ @{{ user?.user.metadata.name }}
+
+
+
+
-
-
-
- {{
- role.metadata.annotations?.[rbacAnnotations.DISPLAY_NAME] ||
- role.metadata.name
- }}
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- {{ authProvider.displayName }}
-
-
-
-
- {{ $t("core.user.detail.operations.unbind.button") }}
-
-
- {{ $t("core.user.detail.operations.bind.button") }}
-
-
-
-
-
-
-
-
-
+
+
+ {{ $t("core.common.buttons.edit") }}
+
+
+
+ {{ $t("core.user.detail.actions.update_profile.title") }}
+
+
+ {{ $t("core.user.detail.actions.change_password.title") }}
+
+
+
+
+
+
+
+
diff --git a/console/src/modules/system/users/components/UserAvatar.vue b/console/src/modules/system/users/components/UserAvatar.vue
new file mode 100644
index 00000000000..137e737a243
--- /dev/null
+++ b/console/src/modules/system/users/components/UserAvatar.vue
@@ -0,0 +1,186 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t("core.common.buttons.upload") }}
+
+
+ {{ $t("core.common.buttons.delete") }}
+
+
+
+
+
+
+
+
+
+
+ {{ $t("core.common.buttons.submit") }}
+
+
+ {{ $t("core.common.buttons.cancel") }}
+
+
+
+
+
diff --git a/console/src/modules/system/users/layouts/UserProfileLayout.vue b/console/src/modules/system/users/layouts/UserProfileLayout.vue
deleted file mode 100644
index eaeaf367cb0..00000000000
--- a/console/src/modules/system/users/layouts/UserProfileLayout.vue
+++ /dev/null
@@ -1,355 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ $t("core.common.buttons.upload") }}
-
-
- {{ $t("core.common.buttons.delete") }}
-
-
-
-
-
-
-
- {{ user?.user.spec.displayName }}
-
-
- @{{ user?.user.metadata.name }}
-
-
-
-
-
-
- {{ $t("core.common.buttons.edit") }}
-
-
-
- {{ $t("core.user.detail.actions.update_profile.title") }}
-
-
- {{ $t("core.user.detail.actions.change_password.title") }}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ $t("core.common.buttons.submit") }}
-
-
- {{ $t("core.common.buttons.cancel") }}
-
-
-
-
-
-
diff --git a/console/src/modules/system/users/module.ts b/console/src/modules/system/users/module.ts
index f7f60e94d76..d437af010b4 100644
--- a/console/src/modules/system/users/module.ts
+++ b/console/src/modules/system/users/module.ts
@@ -1,11 +1,9 @@
import { definePlugin } from "@halo-dev/console-shared";
import BasicLayout from "@/layouts/BasicLayout.vue";
import BlankLayout from "@/layouts/BlankLayout.vue";
-import UserProfileLayout from "./layouts/UserProfileLayout.vue";
import UserStatsWidget from "./widgets/UserStatsWidget.vue";
import UserList from "./UserList.vue";
import UserDetail from "./UserDetail.vue";
-import PersonalAccessTokens from "./PersonalAccessTokens.vue";
import Login from "./Login.vue";
import { IconUserSettings } from "@halo-dev/components";
import { markRaw } from "vue";
@@ -61,25 +59,17 @@ export default definePlugin({
},
{
path: ":name",
- component: UserProfileLayout,
+ component: BasicLayout,
name: "User",
children: [
{
- path: "detail",
+ path: "",
name: "UserDetail",
component: UserDetail,
meta: {
title: "core.user.detail.title",
},
},
- {
- path: "tokens",
- name: "PersonalAccessTokens",
- component: PersonalAccessTokens,
- meta: {
- title: "个人令牌",
- },
- },
],
},
],
diff --git a/console/src/modules/system/users/tabs/Detail.vue b/console/src/modules/system/users/tabs/Detail.vue
new file mode 100644
index 00000000000..73b4b62b461
--- /dev/null
+++ b/console/src/modules/system/users/tabs/Detail.vue
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ role.metadata.annotations?.[rbacAnnotations.DISPLAY_NAME] ||
+ role.metadata.name
+ }}
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ {{ authProvider.displayName }}
+
+
+
+
+ {{ $t("core.user.detail.operations.unbind.button") }}
+
+
+ {{ $t("core.user.detail.operations.bind.button") }}
+
+
+
+
+
+
+
+
+
+
diff --git a/console/src/modules/system/users/PersonalAccessTokens.vue b/console/src/modules/system/users/tabs/PersonalAccessTokens.vue
similarity index 93%
rename from console/src/modules/system/users/PersonalAccessTokens.vue
rename to console/src/modules/system/users/tabs/PersonalAccessTokens.vue
index 55a32754707..9b9f24624af 100644
--- a/console/src/modules/system/users/PersonalAccessTokens.vue
+++ b/console/src/modules/system/users/tabs/PersonalAccessTokens.vue
@@ -10,9 +10,9 @@ import { ref } from "vue";
import { apiClient } from "@/utils/api-client";
import type { PersonalAccessToken } from "@halo-dev/api-client";
import { useQuery } from "@tanstack/vue-query";
-import PersonalAccessTokenCreationModal from "./components/PersonalAccessTokenCreationModal.vue";
+import PersonalAccessTokenCreationModal from "../components/PersonalAccessTokenCreationModal.vue";
import { nextTick } from "vue";
-import PersonalAccessTokenListItem from "./components/PersonalAccessTokenListItem.vue";
+import PersonalAccessTokenListItem from "../components/PersonalAccessTokenListItem.vue";
const {
data: pats,
From 1f0cfc18e39dbc22cb97a08f221b0f81f52875b9 Mon Sep 17 00:00:00 2001
From: guqing <38999863+guqing@users.noreply.github.com>
Date: Wed, 27 Sep 2023 10:16:16 +0800
Subject: [PATCH 2/3] feat: support running plugins from JAR in development
mode (#4589)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
#### What type of PR is this?
/kind feature
/milestone 2.10.x
/area core
#### What this PR does / why we need it:
支持在开发模式下通过 JAR 运行插件
*从此版本开始 BasePlugin 的子类建议使用 BasePlugin(PluginContext context) 构造函数,而不要使用之前的 BasePlugin(PluginWrapper wrapper) 构造函数。BasePlugin(PluginWrapper wrapper) 构造函数将计划在后续版本移除* ,当移除构造函数后不再将 PluginWrapper 暴露给插件使用,它只应该在 halo core 使用。
how to test it?
1. 测试开发模式下配置的 `halo.plugin.fixed-plugin-path` 插件是否正确运行
2. 测试开发模式下通过 JAR 包安装插件是否正确运行
3. 测试生产模式下是否能通过项目目录的方式运行插件,期望是生产模式不可以运行开发模式的插件
4. 测试开发模式和生产模式的插件卸载功能是否正确
#### Which issue(s) this PR fixes:
Fixes #2908
#### Does this PR introduce a user-facing change?
```release-note
支持在开发模式下通过 JAR 运行插件
```
---
.../java/run/halo/app/plugin/BasePlugin.java | 36 ++++++
.../run/halo/app/plugin/PluginContext.java | 27 +++++
.../reconciler/PluginReconciler.java | 23 +++-
.../halo/app/plugin/BasePluginFactory.java | 8 +-
.../halo/app/plugin/HaloPluginManager.java | 11 ++
.../halo/app/plugin/HaloPluginWrapper.java | 34 ++++++
.../plugin/PluginApplicationInitializer.java | 12 ++
.../app/plugin/PluginAutoConfiguration.java | 72 ++++++------
.../app/plugin/SpringExtensionFactory.java | 103 ++++++------------
.../reconciler/PluginReconcilerTest.java | 3 +-
10 files changed, 216 insertions(+), 113 deletions(-)
create mode 100644 api/src/main/java/run/halo/app/plugin/PluginContext.java
create mode 100644 application/src/main/java/run/halo/app/plugin/HaloPluginWrapper.java
diff --git a/api/src/main/java/run/halo/app/plugin/BasePlugin.java b/api/src/main/java/run/halo/app/plugin/BasePlugin.java
index f513514fec4..d010998c56c 100644
--- a/api/src/main/java/run/halo/app/plugin/BasePlugin.java
+++ b/api/src/main/java/run/halo/app/plugin/BasePlugin.java
@@ -3,6 +3,8 @@
import lombok.extern.slf4j.Slf4j;
import org.pf4j.Plugin;
import org.pf4j.PluginWrapper;
+import org.springframework.lang.NonNull;
+import org.springframework.util.Assert;
/**
* This class will be extended by all plugins and serve as the common class between a plugin and
@@ -14,12 +16,46 @@
@Slf4j
public class BasePlugin extends Plugin {
+ protected PluginContext context;
+
@Deprecated
public BasePlugin(PluginWrapper wrapper) {
super(wrapper);
log.info("Initialized plugin {}", wrapper.getPluginId());
}
+ /**
+ * Constructor a plugin with the given plugin context.
+ * TODO Mark {@link PluginContext} as final to prevent modification.
+ *
+ * @param pluginContext plugin context must not be null.
+ */
+ public BasePlugin(PluginContext pluginContext) {
+ this.context = pluginContext;
+ }
+
+ /**
+ * use {@link #BasePlugin(PluginContext)} instead of.
+ *
+ * @deprecated since 2.10.0
+ */
public BasePlugin() {
}
+
+ /**
+ * Compatible with old constructors, if the plugin is not use
+ * {@link #BasePlugin(PluginContext)} constructor then base plugin factory will use this
+ * method to set plugin context.
+ *
+ * @param context plugin context must not be null.
+ */
+ final void setContext(PluginContext context) {
+ Assert.notNull(context, "Plugin context must not be null");
+ this.context = context;
+ }
+
+ @NonNull
+ public PluginContext getContext() {
+ return context;
+ }
}
diff --git a/api/src/main/java/run/halo/app/plugin/PluginContext.java b/api/src/main/java/run/halo/app/plugin/PluginContext.java
new file mode 100644
index 00000000000..01bae2f9670
--- /dev/null
+++ b/api/src/main/java/run/halo/app/plugin/PluginContext.java
@@ -0,0 +1,27 @@
+package run.halo.app.plugin;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.pf4j.RuntimeMode;
+
+/**
+ *
This class will provide a context for the plugin, which will be used to store some
+ * information about the plugin.
+ * An instance of this class is provided to plugins in their constructor.
+ * It's safe for plugins to keep a reference to the instance for later use.
+ * This class facilitates communication with application and plugin manager.
+ * Pf4j recommends that you use a custom PluginContext instead of PluginWrapper.
+ * Use application custom PluginContext instead of PluginWrapper
+ *
+ * @author guqing
+ * @since 2.10.0
+ */
+@Getter
+@RequiredArgsConstructor
+public class PluginContext {
+ private final String name;
+
+ private final String version;
+
+ private final RuntimeMode runtimeMode;
+}
diff --git a/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java b/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java
index 92d0750bf7e..5361b08a8fc 100644
--- a/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java
+++ b/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java
@@ -60,6 +60,7 @@
import run.halo.app.infra.utils.PathUtils;
import run.halo.app.infra.utils.YamlUnstructuredLoader;
import run.halo.app.plugin.HaloPluginManager;
+import run.halo.app.plugin.HaloPluginWrapper;
import run.halo.app.plugin.PluginConst;
import run.halo.app.plugin.PluginExtensionLoaderUtils;
import run.halo.app.plugin.PluginStartingError;
@@ -184,11 +185,12 @@ Optional lookupPluginSetting(String name, String settingName) {
Assert.notNull(name, "Plugin name must not be null");
Assert.notNull(settingName, "Setting name must not be null");
PluginWrapper pluginWrapper = getPluginWrapper(name);
+ var runtimeMode = getRuntimeMode(name);
var resourceLoader =
new DefaultResourceLoader(pluginWrapper.getPluginClassLoader());
return PluginExtensionLoaderUtils.lookupExtensions(pluginWrapper.getPluginPath(),
- pluginWrapper.getRuntimeMode())
+ runtimeMode)
.stream()
.map(resourceLoader::getResource)
.filter(Resource::exists)
@@ -215,6 +217,7 @@ boolean waitForSettingCreation(Plugin plugin) {
return false;
}
+ var runtimeMode = getRuntimeMode(pluginName);
Optional settingOption = lookupPluginSetting(pluginName, settingName)
.map(setting -> {
// This annotation is added to prevent it from being deleted when stopped.
@@ -802,11 +805,19 @@ static String initialReverseProxyName(String pluginName) {
}
private boolean isDevelopmentMode(String name) {
- PluginWrapper pluginWrapper = haloPluginManager.getPlugin(name);
- RuntimeMode runtimeMode = haloPluginManager.getRuntimeMode();
- if (pluginWrapper != null) {
- runtimeMode = pluginWrapper.getRuntimeMode();
+ return RuntimeMode.DEVELOPMENT.equals(getRuntimeMode(name));
+ }
+
+ private RuntimeMode getRuntimeMode(String name) {
+ var pluginWrapper = haloPluginManager.getPlugin(name);
+ if (pluginWrapper == null) {
+ return haloPluginManager.getRuntimeMode();
+ }
+ if (pluginWrapper instanceof HaloPluginWrapper haloPluginWrapper) {
+ return haloPluginWrapper.getRuntimeMode();
}
- return RuntimeMode.DEVELOPMENT.equals(runtimeMode);
+ return Files.isDirectory(pluginWrapper.getPluginPath())
+ ? RuntimeMode.DEVELOPMENT
+ : RuntimeMode.DEPLOYMENT;
}
}
diff --git a/application/src/main/java/run/halo/app/plugin/BasePluginFactory.java b/application/src/main/java/run/halo/app/plugin/BasePluginFactory.java
index c769ab8e291..211cdee0d7f 100644
--- a/application/src/main/java/run/halo/app/plugin/BasePluginFactory.java
+++ b/application/src/main/java/run/halo/app/plugin/BasePluginFactory.java
@@ -23,13 +23,17 @@ public Plugin create(PluginWrapper pluginWrapper) {
return getPluginContext(pluginWrapper)
.map(context -> {
try {
- return context.getBean(BasePlugin.class);
+ var basePlugin = context.getBean(BasePlugin.class);
+ var pluginContext = context.getBean(PluginContext.class);
+ basePlugin.setContext(pluginContext);
+ return basePlugin;
} catch (NoSuchBeanDefinitionException e) {
log.info(
"No bean named 'basePlugin' found in the context create default instance");
DefaultListableBeanFactory beanFactory =
context.getDefaultListableBeanFactory();
- BasePlugin pluginInstance = new BasePlugin();
+ var pluginContext = beanFactory.getBean(PluginContext.class);
+ BasePlugin pluginInstance = new BasePlugin(pluginContext);
beanFactory.registerSingleton(Plugin.class.getName(), pluginInstance);
return pluginInstance;
}
diff --git a/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java b/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java
index 7abcb1d5f4d..41a61a86e74 100644
--- a/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java
+++ b/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java
@@ -108,6 +108,17 @@ protected PluginDescriptorFinder createPluginDescriptorFinder() {
return new YamlPluginDescriptorFinder();
}
+ @Override
+ protected PluginWrapper createPluginWrapper(PluginDescriptor pluginDescriptor, Path pluginPath,
+ ClassLoader pluginClassLoader) {
+ // create the plugin wrapper
+ log.debug("Creating wrapper for plugin '{}'", pluginPath);
+ HaloPluginWrapper pluginWrapper =
+ new HaloPluginWrapper(this, pluginDescriptor, pluginPath, pluginClassLoader);
+ pluginWrapper.setPluginFactory(getPluginFactory());
+ return pluginWrapper;
+ }
+
@Override
protected void firePluginStateEvent(PluginStateEvent event) {
rootApplicationContext.publishEvent(
diff --git a/application/src/main/java/run/halo/app/plugin/HaloPluginWrapper.java b/application/src/main/java/run/halo/app/plugin/HaloPluginWrapper.java
new file mode 100644
index 00000000000..f784400ab4b
--- /dev/null
+++ b/application/src/main/java/run/halo/app/plugin/HaloPluginWrapper.java
@@ -0,0 +1,34 @@
+package run.halo.app.plugin;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.pf4j.PluginDescriptor;
+import org.pf4j.PluginManager;
+import org.pf4j.PluginWrapper;
+import org.pf4j.RuntimeMode;
+
+/**
+ * A wrapper over plugin instance for Halo.
+ *
+ * @author guqing
+ * @since 2.10.0
+ */
+public class HaloPluginWrapper extends PluginWrapper {
+
+ private final RuntimeMode runtimeMode;
+
+ /**
+ * Creates a new plugin wrapper to manage the specified plugin.
+ */
+ public HaloPluginWrapper(PluginManager pluginManager, PluginDescriptor descriptor,
+ Path pluginPath, ClassLoader pluginClassLoader) {
+ super(pluginManager, descriptor, pluginPath, pluginClassLoader);
+ this.runtimeMode = Files.isDirectory(pluginPath)
+ ? RuntimeMode.DEVELOPMENT : RuntimeMode.DEPLOYMENT;
+ }
+
+ @Override
+ public RuntimeMode getRuntimeMode() {
+ return runtimeMode;
+ }
+}
diff --git a/application/src/main/java/run/halo/app/plugin/PluginApplicationInitializer.java b/application/src/main/java/run/halo/app/plugin/PluginApplicationInitializer.java
index d437b61981d..45c9d367f63 100644
--- a/application/src/main/java/run/halo/app/plugin/PluginApplicationInitializer.java
+++ b/application/src/main/java/run/halo/app/plugin/PluginApplicationInitializer.java
@@ -9,6 +9,7 @@
import java.util.Set;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
+import org.pf4j.PluginRuntimeException;
import org.pf4j.PluginWrapper;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.env.PropertySourceLoader;
@@ -88,6 +89,8 @@ private PluginApplicationContext createPluginApplicationContext(String pluginId)
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
stopWatch.stop();
+ beanFactory.registerSingleton("pluginContext", createPluginContext(plugin));
+ // TODO deprecated
beanFactory.registerSingleton("pluginWrapper", haloPluginManager.getPlugin(pluginId));
populateSettingFetcher(pluginId, beanFactory);
@@ -131,6 +134,15 @@ private void initApplicationContext(String pluginId) {
stopWatch.getTotalTimeMillis(), stopWatch.prettyPrint());
}
+ PluginContext createPluginContext(PluginWrapper pluginWrapper) {
+ if (pluginWrapper instanceof HaloPluginWrapper haloPluginWrapper) {
+ return new PluginContext(haloPluginWrapper.getPluginId(),
+ pluginWrapper.getDescriptor().getVersion(),
+ haloPluginWrapper.getRuntimeMode());
+ }
+ throw new PluginRuntimeException("PluginWrapper must be instance of HaloPluginWrapper");
+ }
+
private void populateSettingFetcher(String pluginName,
DefaultListableBeanFactory listableBeanFactory) {
ReactiveExtensionClient extensionClient =
diff --git a/application/src/main/java/run/halo/app/plugin/PluginAutoConfiguration.java b/application/src/main/java/run/halo/app/plugin/PluginAutoConfiguration.java
index 40d4df246f7..bd740314381 100644
--- a/application/src/main/java/run/halo/app/plugin/PluginAutoConfiguration.java
+++ b/application/src/main/java/run/halo/app/plugin/PluginAutoConfiguration.java
@@ -5,6 +5,7 @@
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import lombok.extern.slf4j.Slf4j;
@@ -109,33 +110,7 @@ protected PluginLoader createPluginLoader() {
}
} else {
return new CompoundPluginLoader()
- .add(new DevelopmentPluginLoader(this) {
-
- @Override
- protected PluginClassLoader createPluginClassLoader(Path pluginPath,
- PluginDescriptor pluginDescriptor) {
- return new PluginClassLoader(pluginManager, pluginDescriptor,
- getClass().getClassLoader(), ClassLoadingStrategy.APD);
- }
-
- @Override
- public ClassLoader loadPlugin(Path pluginPath,
- PluginDescriptor pluginDescriptor) {
- if (pluginProperties.getClassesDirectories() != null) {
- for (String classesDirectory :
- pluginProperties.getClassesDirectories()) {
- pluginClasspath.addClassesDirectories(classesDirectory);
- }
- }
- if (pluginProperties.getLibDirectories() != null) {
- for (String libDirectory :
- pluginProperties.getLibDirectories()) {
- pluginClasspath.addJarsDirectories(libDirectory);
- }
- }
- return super.loadPlugin(pluginPath, pluginDescriptor);
- }
- }, this::isDevelopment)
+ .add(createDevelopmentPluginLoader(this), this::isDevelopment)
.add(new JarPluginLoader(this) {
@Override
public ClassLoader loadPlugin(Path pluginPath,
@@ -145,9 +120,8 @@ public ClassLoader loadPlugin(Path pluginPath,
getClass().getClassLoader(), ClassLoadingStrategy.APD);
pluginClassLoader.addFile(pluginPath.toFile());
return pluginClassLoader;
-
}
- }, this::isNotDevelopment);
+ });
}
}
@@ -167,9 +141,8 @@ protected PluginRepository createPluginRepository() {
.setFixedPaths(pluginProperties.getFixedPluginPath());
return new CompoundPluginRepository()
.add(developmentPluginRepository, this::isDevelopment)
- .add(new JarPluginRepository(getPluginsRoots()), this::isNotDevelopment)
- .add(new DefaultPluginRepository(getPluginsRoots()),
- this::isNotDevelopment);
+ .add(new JarPluginRepository(getPluginsRoots()))
+ .add(new DefaultPluginRepository(getPluginsRoots()));
}
};
@@ -181,6 +154,41 @@ protected PluginRepository createPluginRepository() {
return pluginManager;
}
+ DevelopmentPluginLoader createDevelopmentPluginLoader(PluginManager pluginManager) {
+ return new DevelopmentPluginLoader(pluginManager) {
+ @Override
+ protected PluginClassLoader createPluginClassLoader(Path pluginPath,
+ PluginDescriptor pluginDescriptor) {
+ return new PluginClassLoader(pluginManager, pluginDescriptor,
+ getClass().getClassLoader(), ClassLoadingStrategy.APD);
+ }
+
+ @Override
+ public ClassLoader loadPlugin(Path pluginPath,
+ PluginDescriptor pluginDescriptor) {
+ if (pluginProperties.getClassesDirectories() != null) {
+ for (String classesDirectory :
+ pluginProperties.getClassesDirectories()) {
+ pluginClasspath.addClassesDirectories(classesDirectory);
+ }
+ }
+ if (pluginProperties.getLibDirectories() != null) {
+ for (String libDirectory :
+ pluginProperties.getLibDirectories()) {
+ pluginClasspath.addJarsDirectories(libDirectory);
+ }
+ }
+ return super.loadPlugin(pluginPath, pluginDescriptor);
+ }
+
+ @Override
+ public boolean isApplicable(Path pluginPath) {
+ return Files.exists(pluginPath)
+ && Files.isDirectory(pluginPath);
+ }
+ };
+ }
+
String getSystemVersion() {
return systemVersionSupplier.get().getNormalVersion();
}
diff --git a/application/src/main/java/run/halo/app/plugin/SpringExtensionFactory.java b/application/src/main/java/run/halo/app/plugin/SpringExtensionFactory.java
index 4bf0c5b22f3..6477f48115c 100644
--- a/application/src/main/java/run/halo/app/plugin/SpringExtensionFactory.java
+++ b/application/src/main/java/run/halo/app/plugin/SpringExtensionFactory.java
@@ -6,11 +6,12 @@
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.pf4j.Extension;
import org.pf4j.ExtensionFactory;
-import org.pf4j.Plugin;
import org.pf4j.PluginManager;
+import org.pf4j.PluginRuntimeException;
import org.pf4j.PluginWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
@@ -52,46 +53,18 @@
* @since 2.0.0
*/
@Slf4j
+@RequiredArgsConstructor
public class SpringExtensionFactory implements ExtensionFactory {
- public static final boolean AUTOWIRE_BY_DEFAULT = true;
-
/**
* The plugin manager is used for retrieving a plugin from a given extension class and as a
* fallback supplier of an application context.
*/
protected final PluginManager pluginManager;
- /**
- * Indicates if springs autowiring possibilities should be used.
- */
- protected final boolean autowire;
-
- public SpringExtensionFactory(PluginManager pluginManager) {
- this(pluginManager, AUTOWIRE_BY_DEFAULT);
- }
-
- public SpringExtensionFactory(final PluginManager pluginManager, final boolean autowire) {
- this.pluginManager = pluginManager;
- this.autowire = autowire;
- if (!autowire) {
- log.warn(
- "Autowiring is disabled although the only reason for existence of this special "
- + "factory is"
- +
- " supporting spring and its application context.");
- }
- }
-
@Override
@Nullable
public T create(Class extensionClass) {
- if (!this.autowire) {
- log.warn("Create instance of '" + nameOf(extensionClass)
- + "' without using springs possibilities as"
- + " autowiring is disabled.");
- return createWithoutSpring(extensionClass);
- }
Optional contextOptional =
getPluginApplicationContextBy(extensionClass);
if (contextOptional.isPresent()) {
@@ -154,52 +127,38 @@ private Object[] nullParameters(final Constructor> constructor) {
protected Optional getPluginApplicationContextBy(
final Class extensionClass) {
- final Plugin plugin = Optional.ofNullable(this.pluginManager.whichPlugin(extensionClass))
+ return Optional.ofNullable(this.pluginManager.whichPlugin(extensionClass))
.map(PluginWrapper::getPlugin)
- .orElse(null);
-
- final PluginApplicationContext applicationContext;
-
- if (plugin instanceof BasePlugin) {
- log.debug(
- " Extension class ' " + nameOf(extensionClass) + "' belongs to halo-plugin '"
- + nameOf(plugin)
- + "' and will be autowired by using its application context.");
- applicationContext = ExtensionContextRegistry.getInstance()
- .getByPluginId(plugin.getWrapper().getPluginId());
- return Optional.of(applicationContext);
- } else if (this.pluginManager instanceof HaloPluginManager && plugin != null) {
- log.debug(" Extension class ' " + nameOf(extensionClass)
- + "' belongs to a non halo-plugin (or main application)"
- + " '" + nameOf(plugin)
- + ", but the used Halo plugin-manager is a spring-plugin-manager. Therefore"
- + " the extension class will be autowired by using the managers application "
- + "contexts");
- String pluginId = plugin.getWrapper().getPluginId();
- applicationContext = ((HaloPluginManager) this.pluginManager)
- .getPluginApplicationContext(pluginId);
- } else {
- log.warn(" No application contexts can be used for instantiating extension class '"
- + nameOf(extensionClass) + "'."
- + " This extension neither belongs to a halo-plugin (id: '" + nameOf(plugin)
- + "') nor is the used"
- + " plugin manager a spring-plugin-manager (used manager: '"
- + nameOf(this.pluginManager.getClass()) + "')."
- + " At perspective of PF4J this seems highly uncommon in combination with a factory"
- + " which only reason for existence"
- + " is using spring (and its application context) and should at least be reviewed. "
- + "In fact no autowiring can be"
- + " applied although autowire flag was set to 'true'. Instantiating will fallback "
- + "to standard Java reflection.");
- applicationContext = null;
- }
-
- return Optional.ofNullable(applicationContext);
+ .map(plugin -> {
+ if (plugin instanceof BasePlugin basePlugin) {
+ return basePlugin;
+ }
+ throw new PluginRuntimeException(
+ "The plugin must be an instance of BasePlugin");
+ })
+ .map(plugin -> {
+ var pluginName = plugin.getContext().getName();
+ if (this.pluginManager instanceof HaloPluginManager haloPluginManager) {
+ log.debug(" Extension class ' " + nameOf(extensionClass)
+ + "' belongs to a non halo-plugin (or main application)"
+ + " '" + nameOf(plugin)
+ + ", but the used Halo plugin-manager is a spring-plugin-manager. Therefore"
+ + " the extension class will be autowired by using the managers "
+ + "application "
+ + "contexts");
+ return haloPluginManager.getPluginApplicationContext(pluginName);
+ }
+ log.debug(
+ " Extension class ' " + nameOf(extensionClass) + "' belongs to halo-plugin '"
+ + nameOf(plugin)
+ + "' and will be autowired by using its application context.");
+ return ExtensionContextRegistry.getInstance().getByPluginId(pluginName);
+ });
}
- private String nameOf(final Plugin plugin) {
+ private String nameOf(final BasePlugin plugin) {
return Objects.nonNull(plugin)
- ? plugin.getWrapper().getPluginId()
+ ? plugin.getContext().getName()
: "system";
}
diff --git a/application/src/test/java/run/halo/app/core/extension/reconciler/PluginReconcilerTest.java b/application/src/test/java/run/halo/app/core/extension/reconciler/PluginReconcilerTest.java
index 811e2c92713..a2e46134e51 100644
--- a/application/src/test/java/run/halo/app/core/extension/reconciler/PluginReconcilerTest.java
+++ b/application/src/test/java/run/halo/app/core/extension/reconciler/PluginReconcilerTest.java
@@ -50,6 +50,7 @@
import run.halo.app.infra.utils.FileUtils;
import run.halo.app.infra.utils.JsonUtils;
import run.halo.app.plugin.HaloPluginManager;
+import run.halo.app.plugin.HaloPluginWrapper;
import run.halo.app.plugin.PluginConst;
import run.halo.app.plugin.PluginStartingError;
@@ -69,7 +70,7 @@ class PluginReconcilerTest {
ExtensionClient extensionClient;
@Mock
- PluginWrapper pluginWrapper;
+ HaloPluginWrapper pluginWrapper;
@Mock
ApplicationEventPublisher eventPublisher;
From 9b310ca65e4fd75168761ab59f6a6e3beb0fb9db Mon Sep 17 00:00:00 2001
From: Ryan Wang
Date: Wed, 27 Sep 2023 10:22:16 +0800
Subject: [PATCH 3/3] feat: add configration route for auth provider item
(#4635)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
#### What type of PR is this?
/area console
/kind improvement
/milestone 2.10.x
#### What this PR does / why we need it:
为认证方式添加更直观的配置页面入口
#### Which issue(s) this PR fixes:
Fixes #4634
#### Does this PR introduce a user-facing change?
```release-note
为 Console 端认证方式管理添加更直观的配置页面入口
```
---
.../components/AuthProviderListItem.vue | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/console/src/modules/system/auth-providers/components/AuthProviderListItem.vue b/console/src/modules/system/auth-providers/components/AuthProviderListItem.vue
index 371d5172fb6..9b0cbf2217e 100644
--- a/console/src/modules/system/auth-providers/components/AuthProviderListItem.vue
+++ b/console/src/modules/system/auth-providers/components/AuthProviderListItem.vue
@@ -3,6 +3,7 @@ import { apiClient } from "@/utils/api-client";
import type { ListedAuthProvider } from "@halo-dev/api-client";
import {
Dialog,
+ IconSettings,
Toast,
VAvatar,
VEntity,
@@ -93,6 +94,19 @@ const handleChangeStatus = async () => {
+
+
+
+
+
+
+