diff --git a/.gitignore b/.gitignore index 5e83b44..a31f584 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,5 @@ replay_pid* target/ *.iml +hooks/*.iml dependency-reduced-pom.xml diff --git a/hooks/only-assignee-can-delete/.gitignore b/hooks/only-assignee-can-delete/.gitignore new file mode 100644 index 0000000..824ec60 --- /dev/null +++ b/hooks/only-assignee-can-delete/.gitignore @@ -0,0 +1,31 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* +.idea/* + +# code style config +!.idea/codeStyles +.idea/codeStyles/* +!.idea/codeStyles/Project.xml +!.idea/codeStyles/codeStyleConfig.xml + +target/ +*.iml diff --git a/hooks/only-assignee-can-delete/pom.xml b/hooks/only-assignee-can-delete/pom.xml index 929aaec..4493d98 100644 --- a/hooks/only-assignee-can-delete/pom.xml +++ b/hooks/only-assignee-can-delete/pom.xml @@ -8,7 +8,7 @@ jar - 1.0.0-SNAPSHOT + 1.1.1 ch.sbb.polarion.extension.interceptor_hooks.only_assignee_can_delete only-assignee-can-delete @@ -18,7 +18,7 @@ 17 17 - 2310 + 2404 UTF-8 yyyy-MM-dd HH:mm diff --git a/hooks/plan-save/.gitignore b/hooks/plan-save/.gitignore new file mode 100644 index 0000000..824ec60 --- /dev/null +++ b/hooks/plan-save/.gitignore @@ -0,0 +1,31 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* +.idea/* + +# code style config +!.idea/codeStyles +.idea/codeStyles/* +!.idea/codeStyles/Project.xml +!.idea/codeStyles/codeStyleConfig.xml + +target/ +*.iml diff --git a/hooks/plan-save/pom.xml b/hooks/plan-save/pom.xml index 18ff6c9..bd8a6e8 100644 --- a/hooks/plan-save/pom.xml +++ b/hooks/plan-save/pom.xml @@ -8,7 +8,7 @@ jar - 1.0.0-SNAPSHOT + 1.1.1 ch.sbb.polarion.extension.interceptor_hooks.plan_save plan-save @@ -18,7 +18,7 @@ 17 17 - 2310 + 2404 UTF-8 yyyy-MM-dd HH:mm diff --git a/hooks/single-assignee/.gitignore b/hooks/single-assignee/.gitignore new file mode 100644 index 0000000..824ec60 --- /dev/null +++ b/hooks/single-assignee/.gitignore @@ -0,0 +1,31 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* +.idea/* + +# code style config +!.idea/codeStyles +.idea/codeStyles/* +!.idea/codeStyles/Project.xml +!.idea/codeStyles/codeStyleConfig.xml + +target/ +*.iml diff --git a/hooks/single-assignee/pom.xml b/hooks/single-assignee/pom.xml index d550bd3..10643d9 100644 --- a/hooks/single-assignee/pom.xml +++ b/hooks/single-assignee/pom.xml @@ -8,7 +8,7 @@ jar - 1.0.0-SNAPSHOT + 1.1.1 ch.sbb.polarion.extension.interceptor_hooks.single_assignee single-assignee @@ -18,7 +18,7 @@ 17 17 - 2310 + 2404 UTF-8 yyyy-MM-dd HH:mm diff --git a/hooks/testrun/.gitignore b/hooks/testrun/.gitignore new file mode 100644 index 0000000..824ec60 --- /dev/null +++ b/hooks/testrun/.gitignore @@ -0,0 +1,31 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* +.idea/* + +# code style config +!.idea/codeStyles +.idea/codeStyles/* +!.idea/codeStyles/Project.xml +!.idea/codeStyles/codeStyleConfig.xml + +target/ +*.iml diff --git a/hooks/testrun/pom.xml b/hooks/testrun/pom.xml index 88c3e61..b23b687 100644 --- a/hooks/testrun/pom.xml +++ b/hooks/testrun/pom.xml @@ -8,7 +8,7 @@ jar - 1.0.0-SNAPSHOT + 1.1.1 ch.sbb.polarion.extension.interceptor_hooks.testrun testrun @@ -18,7 +18,7 @@ 17 17 - 2310 + 2404 UTF-8 yyyy-MM-dd HH:mm diff --git a/hooks/title-length-check/.gitignore b/hooks/title-length-check/.gitignore new file mode 100644 index 0000000..824ec60 --- /dev/null +++ b/hooks/title-length-check/.gitignore @@ -0,0 +1,31 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* +.idea/* + +# code style config +!.idea/codeStyles +.idea/codeStyles/* +!.idea/codeStyles/Project.xml +!.idea/codeStyles/codeStyleConfig.xml + +target/ +*.iml diff --git a/hooks/title-length-check/pom.xml b/hooks/title-length-check/pom.xml index cf37d1f..88db481 100644 --- a/hooks/title-length-check/pom.xml +++ b/hooks/title-length-check/pom.xml @@ -8,7 +8,7 @@ jar - 1.0.0-SNAPSHOT + 1.1.1 ch.sbb.polarion.extension.interceptor_hooks.title_length_check title-length-check @@ -18,7 +18,7 @@ 17 17 - 2310 + 2404 UTF-8 yyyy-MM-dd HH:mm diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/InterceptorAdminUiServlet.java b/src/main/java/ch/sbb/polarion/extension/interceptor/InterceptorAdminUiServlet.java index 66eab9c..08431bd 100644 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/InterceptorAdminUiServlet.java +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/InterceptorAdminUiServlet.java @@ -1,60 +1,14 @@ package ch.sbb.polarion.extension.interceptor; -import com.polarion.core.util.logging.Logger; -import org.apache.commons.io.IOUtils; -import org.jetbrains.annotations.NotNull; +import ch.sbb.polarion.extension.generic.GenericUiServlet; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStream; import java.io.Serial; -public class InterceptorAdminUiServlet extends HttpServlet { - - private static final Logger logger = Logger.getLogger(InterceptorAdminUiServlet.class); - +public class InterceptorAdminUiServlet extends GenericUiServlet { @Serial - private static final long serialVersionUID = 4323903250755251706L; - private static final String WEB_APP_NAME = "interceptor-admin"; - - private static void setContentType(@NotNull String uri, @NotNull HttpServletResponse response) { - if (uri.endsWith(".js")) { - response.setContentType("text/javascript"); - } else if (uri.endsWith(".html")) { - response.setContentType("text/html"); - } else if (uri.endsWith(".png")) { - response.setContentType("image/png"); - } else if (uri.endsWith(".css")) { - response.setContentType("text/css"); - } - } - - @Override - protected void service(HttpServletRequest request, HttpServletResponse response) { - String uri = request.getRequestURI(); - String relativeUri = uri.substring("/polarion/".length()); - - if (relativeUri.startsWith(WEB_APP_NAME + "/ui/")) { - serveResource(response, relativeUri.substring((WEB_APP_NAME + "/ui").length())); - } - } - - private void serveResource(@NotNull HttpServletResponse response, @NotNull String uri) { - try (InputStream inputStream = getServletContext().getResourceAsStream(uri)) { + private static final long serialVersionUID = 1652935384860901702L; - if (inputStream == null) { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - } else { - try (ServletOutputStream outputStream = response.getOutputStream()) { - setContentType(uri, response); - IOUtils.copy(inputStream, outputStream); - } - } - } catch (IOException e) { - logger.error(e.getMessage(), e); - } + public InterceptorAdminUiServlet() { + super("interceptor-admin"); } } diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/model/ActionHook.java b/src/main/java/ch/sbb/polarion/extension/interceptor/model/ActionHook.java index b2f7f65..0cfdf60 100644 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/model/ActionHook.java +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/model/ActionHook.java @@ -1,8 +1,9 @@ package ch.sbb.polarion.extension.interceptor.model; -import ch.sbb.polarion.extension.interceptor.settings.SettingsRegistry; +import ch.sbb.polarion.extension.generic.settings.NamedSettings; +import ch.sbb.polarion.extension.generic.settings.NamedSettingsRegistry; +import ch.sbb.polarion.extension.generic.settings.SettingId; import ch.sbb.polarion.extension.interceptor.settings.HookModel; -import ch.sbb.polarion.extension.interceptor.util.ScopeUtils; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.polarion.alm.projects.model.IUniqueObject; @@ -46,7 +47,7 @@ public ActionHook(List itemTypes, ActionType actionType, String versio public HookModel loadSettings(boolean forceUpdate) { if (forceUpdate || settings == null) { - settings = SettingsRegistry.INSTANCE.getByHookName(getName()).read(ScopeUtils.SCOPE_DEFAULT, null); + settings = (HookModel) NamedSettingsRegistry.INSTANCE.getByFeatureName(getName()).read("", SettingId.fromName(NamedSettings.DEFAULT_NAME), null); } return settings; } diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/model/HooksRegistry.java b/src/main/java/ch/sbb/polarion/extension/interceptor/model/HooksRegistry.java index f617212..ce712f1 100644 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/model/HooksRegistry.java +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/model/HooksRegistry.java @@ -1,13 +1,12 @@ package ch.sbb.polarion.extension.interceptor.model; +import ch.sbb.polarion.extension.generic.settings.NamedSettingsRegistry; import ch.sbb.polarion.extension.interceptor.settings.HookSettings; -import ch.sbb.polarion.extension.interceptor.settings.SettingsRegistry; import ch.sbb.polarion.extension.interceptor.util.HookJarUtils; import com.polarion.core.util.logging.Logger; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; public enum HooksRegistry { @@ -22,8 +21,8 @@ public synchronized void refresh() { hooks.clear(); hooks.addAll(HookJarUtils.loadHooks()); logger.info(hooks.size() + " hooks loaded."); - SettingsRegistry.INSTANCE - .register(HooksRegistry.HOOKS.list().stream().map(HookSettings::new).collect(Collectors.toList())); + NamedSettingsRegistry.INSTANCE.getAll().clear(); + hooks.forEach(hook -> NamedSettingsRegistry.INSTANCE.getAll().add(new HookSettings(hook))); } public List list() { diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/InterceptorRestApplication.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/InterceptorRestApplication.java index ee9e9be..4d76006 100644 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/InterceptorRestApplication.java +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/InterceptorRestApplication.java @@ -1,73 +1,37 @@ package ch.sbb.polarion.extension.interceptor.rest; -import ch.sbb.polarion.extension.interceptor.rest.controller.ExtensionInfoApiController; -import ch.sbb.polarion.extension.interceptor.rest.controller.ExtensionInfoInternalController; -import ch.sbb.polarion.extension.interceptor.rest.controller.SettingsApiController; -import ch.sbb.polarion.extension.interceptor.rest.controller.SettingsInternalController; -import ch.sbb.polarion.extension.interceptor.rest.controller.SwaggerController; -import ch.sbb.polarion.extension.interceptor.rest.controller.SwaggerDefinitionController; -import ch.sbb.polarion.extension.interceptor.rest.exception.BadRequestExceptionMapper; -import ch.sbb.polarion.extension.interceptor.rest.exception.ForbiddenExceptionMapper; -import ch.sbb.polarion.extension.interceptor.rest.exception.IllegalArgumentExceptionMapper; -import ch.sbb.polarion.extension.interceptor.rest.exception.InternalServerErrorExceptionMapper; -import ch.sbb.polarion.extension.interceptor.rest.exception.NotFoundExceptionMapper; -import ch.sbb.polarion.extension.interceptor.rest.exception.UncaughtExceptionMapper; -import ch.sbb.polarion.extension.interceptor.rest.filter.AuthenticationFilter; -import ch.sbb.polarion.extension.interceptor.rest.filter.LogoutFilter; +import ch.sbb.polarion.extension.generic.rest.GenericRestApplication; +import ch.sbb.polarion.extension.generic.rest.controller.NamedSettingsApiController; +import ch.sbb.polarion.extension.generic.rest.controller.NamedSettingsApiScopeAgnosticController; +import ch.sbb.polarion.extension.generic.rest.controller.NamedSettingsInternalController; import ch.sbb.polarion.extension.interceptor.rest.controller.ApiController; +import ch.sbb.polarion.extension.interceptor.rest.controller.HooksSettingsApiController; +import ch.sbb.polarion.extension.interceptor.rest.controller.HooksSettingsInternalController; import ch.sbb.polarion.extension.interceptor.rest.controller.InternalController; -import org.glassfish.jersey.jackson.JacksonFeature; import org.jetbrains.annotations.NotNull; -import javax.ws.rs.core.Application; -import java.util.Arrays; -import java.util.HashSet; import java.util.Set; -public class InterceptorRestApplication extends Application { +public class InterceptorRestApplication extends GenericRestApplication { @Override - @NotNull - public Set> getClasses() { - Set> classes = new HashSet<>(); - classes.addAll(getExceptionMappers()); - classes.addAll(getFilters()); - classes.addAll(getControllerClasses()); - classes.add(JacksonFeature.class); + protected @NotNull Set> getControllerClasses() { + Set> classes = super.getControllerClasses(); + classes.add(HooksSettingsInternalController.class); + classes.add(HooksSettingsApiController.class); + //standard settings internal controller still needed for fetching revisions list + classes.add(NamedSettingsInternalController.class); + //remove other standard settings controllers + classes.remove(NamedSettingsApiController.class); + classes.remove(NamedSettingsApiScopeAgnosticController.class); return classes; } - @NotNull - protected Set> getExceptionMappers() { - return new HashSet<>(Arrays.asList( - BadRequestExceptionMapper.class, - IllegalArgumentExceptionMapper.class, - InternalServerErrorExceptionMapper.class, - ForbiddenExceptionMapper.class, - NotFoundExceptionMapper.class, - UncaughtExceptionMapper.class - )); - } - - @NotNull - protected Set> getFilters() { - return new HashSet<>(Arrays.asList( - AuthenticationFilter.class, - LogoutFilter.class - )); - } - - @NotNull - protected Set> getControllerClasses() { - return new HashSet<>(Arrays.asList( - ExtensionInfoApiController.class, - ExtensionInfoInternalController.class, - SwaggerController.class, - SwaggerDefinitionController.class, - SettingsApiController.class, - SettingsInternalController.class, - ApiController.class, - InternalController.class - )); + @Override + public Set getSingletons() { + return Set.of( + new InternalController(), + new ApiController() + ); } } diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/ApiController.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/ApiController.java index 8a737c8..85da2dc 100644 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/ApiController.java +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/ApiController.java @@ -1,7 +1,7 @@ package ch.sbb.polarion.extension.interceptor.rest.controller; +import ch.sbb.polarion.extension.generic.rest.filter.Secured; import ch.sbb.polarion.extension.interceptor.model.ActionHook; -import ch.sbb.polarion.extension.interceptor.rest.filter.Secured; import javax.ws.rs.Path; import java.util.List; diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/ExtensionInfoApiController.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/ExtensionInfoApiController.java deleted file mode 100644 index 2e82130..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/ExtensionInfoApiController.java +++ /dev/null @@ -1,20 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.controller; - -import ch.sbb.polarion.extension.interceptor.rest.filter.Secured; -import ch.sbb.polarion.extension.interceptor.rest.model.Context; -import ch.sbb.polarion.extension.interceptor.rest.model.Version; - -import javax.ws.rs.Path; - -@Secured -@Path("/api") -public class ExtensionInfoApiController extends ExtensionInfoInternalController { - - public Context getContext() { - return super.getContext(); - } - - public Version getVersion() { - return super.getVersion(); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/ExtensionInfoInternalController.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/ExtensionInfoInternalController.java deleted file mode 100644 index c6f2fba..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/ExtensionInfoInternalController.java +++ /dev/null @@ -1,39 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.controller; - -import ch.sbb.polarion.extension.interceptor.rest.model.Context; -import ch.sbb.polarion.extension.interceptor.rest.model.Version; -import ch.sbb.polarion.extension.interceptor.util.ExtensionInfo; -import io.swagger.v3.oas.annotations.Hidden; -import io.swagger.v3.oas.annotations.OpenAPIDefinition; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.info.Info; -import io.swagger.v3.oas.annotations.tags.Tag; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -@Hidden -@Tag(name = "Extension Information") -@OpenAPIDefinition(info = @Info(title = "REST API")) -@Path("/internal") -public class ExtensionInfoInternalController { - - @GET - @Produces(MediaType.APPLICATION_JSON) - @Path("/context") - @Operation(summary = "Returns basic context information of Polarion's extension") - public Context getContext() { - return ExtensionInfo.getInstance().getContext(); - } - - @GET - @Produces(MediaType.APPLICATION_JSON) - @Path("/version") - @Operation(summary = "Returns version of Polarion's extension") - public Version getVersion() { - return ExtensionInfo.getInstance().getVersion(); - } - -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/HooksSettingsApiController.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/HooksSettingsApiController.java new file mode 100644 index 0000000..7942c75 --- /dev/null +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/HooksSettingsApiController.java @@ -0,0 +1,37 @@ +package ch.sbb.polarion.extension.interceptor.rest.controller; + +import ch.sbb.polarion.extension.generic.rest.filter.Secured; +import ch.sbb.polarion.extension.generic.service.PolarionService; +import ch.sbb.polarion.extension.generic.settings.Revision; +import ch.sbb.polarion.extension.generic.settings.SettingsModel; +import org.jetbrains.annotations.NotNull; + +import javax.ws.rs.Path; +import java.util.List; + +@Secured +@Path("/api") +public class HooksSettingsApiController extends HooksSettingsInternalController { + + private final PolarionService polarionService = new PolarionService(); + + @Override + public @NotNull List readRevisionsList(String hook) { + return polarionService.callPrivileged(() -> super.readRevisionsList(hook)); + } + + @Override + public SettingsModel readSetting(String hook, String revision) { + return polarionService.callPrivileged(() -> super.readSetting(hook, revision)); + } + + @Override + public void saveSetting(String hook, final String content) { + polarionService.callPrivileged(() -> super.saveSetting(hook, content)); + } + + @Override + public SettingsModel getDefaultValues(String hook) { + return polarionService.callPrivileged(() -> super.getDefaultValues(hook)); + } +} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/HooksSettingsInternalController.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/HooksSettingsInternalController.java new file mode 100644 index 0000000..2bfc246 --- /dev/null +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/HooksSettingsInternalController.java @@ -0,0 +1,62 @@ +package ch.sbb.polarion.extension.interceptor.rest.controller; + +import ch.sbb.polarion.extension.generic.rest.controller.NamedSettingsInternalController; +import ch.sbb.polarion.extension.generic.settings.NamedSettings; +import ch.sbb.polarion.extension.generic.settings.Revision; +import ch.sbb.polarion.extension.generic.settings.SettingsModel; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.jetbrains.annotations.NotNull; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import java.util.List; + +import static ch.sbb.polarion.extension.generic.settings.GenericNamedSettings.DEFAULT_SCOPE; + +@Hidden +@Tag(name = "Hooks settings") +@Path("/internal") +public class HooksSettingsInternalController { + + private final NamedSettingsInternalController settingsController = new NamedSettingsInternalController(); + + @GET + @Path("/hook-settings/{hook}/revisions") + @Produces(MediaType.APPLICATION_JSON) + @Operation(summary = "Returns revisions history of specified hook setting") + public @NotNull List readRevisionsList(@PathParam("hook") String hook) { + return settingsController.readRevisionsList(hook, NamedSettings.DEFAULT_NAME, DEFAULT_SCOPE); + } + + @GET + @Path("/hook-settings/{hook}/content") + @Produces(MediaType.APPLICATION_JSON) + @Operation(summary = "Returns values (content) of specified hook setting") + public SettingsModel readSetting(@PathParam("hook") String hook, @QueryParam("revision") String revision) { + return settingsController.readSetting(hook, NamedSettings.DEFAULT_NAME, DEFAULT_SCOPE, revision); + } + + @PUT + @Path("/hook-settings/{hook}/content") + @Consumes(MediaType.APPLICATION_JSON) + @Operation(summary = "Creates or updates hook setting. Creation scenario will use default setting value if no body specified in the request.") + public void saveSetting(@PathParam("hook") String hook, final String content) { + settingsController.saveSetting(hook, NamedSettings.DEFAULT_NAME, DEFAULT_SCOPE, content); + } + + @GET + @Path("/hook-settings/{hook}/default-content") + @Produces(MediaType.APPLICATION_JSON) + @Operation(summary = "Returns default values of specified hook setting") + public SettingsModel getDefaultValues(@PathParam("hook") String hook) { + return settingsController.getDefaultValues(hook); + } +} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/InternalController.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/InternalController.java index e889109..060dd0d 100644 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/InternalController.java +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/InternalController.java @@ -1,6 +1,6 @@ package ch.sbb.polarion.extension.interceptor.rest.controller; -import ch.sbb.polarion.extension.interceptor.service.PolarionService; +import ch.sbb.polarion.extension.generic.service.PolarionService; import ch.sbb.polarion.extension.interceptor.model.ActionHook; import ch.sbb.polarion.extension.interceptor.model.HooksRegistry; import io.swagger.v3.oas.annotations.Hidden; diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SettingsApiController.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SettingsApiController.java deleted file mode 100644 index e2a9455..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SettingsApiController.java +++ /dev/null @@ -1,35 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.controller; - -import ch.sbb.polarion.extension.interceptor.rest.filter.Secured; -import ch.sbb.polarion.extension.interceptor.settings.Revision; -import ch.sbb.polarion.extension.interceptor.settings.SettingsModel; -import org.jetbrains.annotations.NotNull; - -import javax.ws.rs.Path; -import javax.ws.rs.core.Response; -import java.util.List; - -@Secured -@Path("/api") -public class SettingsApiController extends SettingsInternalController { - - @Override - public SettingsModel readSetting(String hook, String revision) { - return polarionService.callPrivileged(() -> super.readSetting(hook, revision)); - } - - @Override - public Response saveSetting(String hook, String content) { - return polarionService.callPrivileged(() -> super.saveSetting(hook, content)); - } - - @Override - public SettingsModel readDefaultSetting(String hook) { - return polarionService.callPrivileged(() -> super.readDefaultSetting(hook)); - } - - @Override - public @NotNull List readRevisionsList(String hook) { - return polarionService.callPrivileged(() -> super.readRevisionsList(hook)); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SettingsInternalController.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SettingsInternalController.java deleted file mode 100644 index 6a5a64d..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SettingsInternalController.java +++ /dev/null @@ -1,82 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.controller; - -import ch.sbb.polarion.extension.interceptor.service.PolarionService; -import ch.sbb.polarion.extension.interceptor.settings.HookSettings; -import ch.sbb.polarion.extension.interceptor.settings.Revision; -import ch.sbb.polarion.extension.interceptor.settings.SettingsModel; -import ch.sbb.polarion.extension.interceptor.settings.SettingsRegistry; -import ch.sbb.polarion.extension.interceptor.util.ScopeUtils; -import com.polarion.subterra.base.location.ILocation; -import io.swagger.v3.oas.annotations.Hidden; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.jetbrains.annotations.NotNull; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.NotFoundException; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.util.List; - -import static ch.sbb.polarion.extension.interceptor.util.ScopeUtils.SCOPE_DEFAULT; - -@Hidden -@Tag(name = "Settings") -@Path("/internal") -public class SettingsInternalController { - - protected final PolarionService polarionService = new PolarionService(); - - @GET - @Path("/settings/{hook}") - @Produces(MediaType.APPLICATION_JSON) - @Operation(summary = "Read settings for the hook") - public SettingsModel readSetting(@PathParam("hook") @Parameter(description = "hook name") String hook, @QueryParam("revision") String revision) { - HookSettings settings = SettingsRegistry.INSTANCE.getByHookName(hook); - ILocation scopeLocation = ScopeUtils.getContextLocation(SCOPE_DEFAULT); - SettingsModel model = settings.read(scopeLocation, revision); - if (model != null) { - return model; - } else { - throw new NotFoundException("Cannot find data using specified parameters"); - } - } - - @POST - @Path("/settings/{hook}") - @Consumes(MediaType.APPLICATION_JSON) - @Operation(summary = "Save settings for the hook") - public Response saveSetting(@PathParam("hook") @Parameter(description = "hook name") String hook, final String content) { - HookSettings settings = SettingsRegistry.INSTANCE.getByHookName(hook); - ILocation scopeLocation = ScopeUtils.getContextLocation(SCOPE_DEFAULT); - - settings.save(scopeLocation, settings.fromJson(content)); - return Response.noContent().build(); - } - - @GET - @Path("/settings/{hook}/default") - @Produces(MediaType.APPLICATION_JSON) - @Operation(summary = "Read default settings for the hook") - public SettingsModel readDefaultSetting(@PathParam("hook") @Parameter(description = "hook name") String hook) { - HookSettings settings = SettingsRegistry.INSTANCE.getByHookName(hook); - return settings.defaultValues(); - } - - @GET - @Path("/settings/{hook}/revisions") - @Produces(MediaType.APPLICATION_JSON) - @Operation(summary = "Read settings revisions for the hook") - public @NotNull List readRevisionsList(@PathParam("hook") @Parameter(description = "hook name") String hook) { - HookSettings settings = SettingsRegistry.INSTANCE.getByHookName(hook); - ILocation scopeLocation = ScopeUtils.getContextLocation(SCOPE_DEFAULT); - return settings.listRevisions(scopeLocation); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SwaggerController.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SwaggerController.java deleted file mode 100644 index bd1dbb5..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SwaggerController.java +++ /dev/null @@ -1,47 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.controller; - -import com.polarion.core.config.Configuration; -import com.polarion.core.config.IRestConfiguration; -import io.swagger.v3.oas.annotations.Hidden; -import org.jetbrains.annotations.NotNull; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.Objects; - -@Hidden -@Path("/swagger") -public class SwaggerController { - private static final String URI_PATTERN = "$uri_replace"; - private static final String PERSISTENCE_PATTERN = "$persistence_replace"; - - @Context - private UriInfo uriInfo; - - @GET - @Produces({MediaType.TEXT_HTML}) - @NotNull - public Response swagger() throws IOException { - IRestConfiguration configuration = Configuration.getInstance().rest(); - if (!(configuration.enabled() && configuration.swaggerUiEnabled())) { - return Response.status(Response.Status.SERVICE_UNAVAILABLE).build(); - } - - try (InputStream inputStream = getClass().getResourceAsStream("/swagger_ui.html")) { - URI uri = uriInfo.getAbsolutePath().resolve("swagger/definition.json"); - String html = new String(Objects.requireNonNull(inputStream).readAllBytes(), StandardCharsets.UTF_8) - .replace(URI_PATTERN, uri.toString()) - .replace(PERSISTENCE_PATTERN, String.valueOf(configuration.swaggerUiPersistAuthorization())); - return Response.status(Response.Status.OK).entity(html).build(); - } - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SwaggerDefinitionController.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SwaggerDefinitionController.java deleted file mode 100644 index d6b0fd0..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/controller/SwaggerDefinitionController.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2020 Polarion AG - */ -package ch.sbb.polarion.extension.interceptor.rest.controller; - -import com.polarion.core.config.Configuration; -import io.swagger.v3.jaxrs2.integration.resources.BaseOpenApiResource; -import io.swagger.v3.oas.annotations.Hidden; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.integration.SwaggerConfiguration; -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.security.SecurityRequirement; -import io.swagger.v3.oas.models.security.SecurityScheme; -import io.swagger.v3.oas.models.servers.Server; -import org.jetbrains.annotations.NotNull; - -import javax.servlet.ServletConfig; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Application; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; -import javax.ws.rs.core.UriInfo; -import java.util.List; -import java.util.Set; - -@Hidden -@Path("/swagger/definition.json") -public class SwaggerDefinitionController extends BaseOpenApiResource { - - public static final String BEARER_AUTH = "bearerAuth"; - - @Context - private ServletConfig config; - @Context - private Application application; - - @GET - @Produces({MediaType.APPLICATION_JSON}) - @Operation(hidden = true) - @NotNull - public Response openApi(@NotNull @Context HttpHeaders headers, @NotNull @Context UriInfo uriInfo) throws Exception { - SwaggerConfiguration swaggerConfig = new SwaggerConfiguration() - .openAPI(createOpenApi(uriInfo)) - .prettyPrint(true) - .resourcePackages(Set.of("io.swagger.sample.resource")); // must be set to remove /application.wadl - setOpenApiConfiguration(swaggerConfig); - - return super.getOpenApi(headers, config, application, uriInfo, "json"); - } - - @NotNull - private OpenAPI createOpenApi(@NotNull UriInfo uriInfo) { - OpenAPI openApiSettings = new OpenAPI(); - openApiSettings.info(createInfo()); - openApiSettings.setServers(createServers(uriInfo)); - openApiSettings.addSecurityItem(new SecurityRequirement().addList(BEARER_AUTH)); - openApiSettings.components(createComponents()); - return openApiSettings; - } - - @NotNull - private Info createInfo() { - return new Info() - .title("REST API"); - } - - @NotNull - private List createServers(@NotNull UriInfo uriInfo) { - Server defaultServer = new Server(); - String url = UriBuilder.fromUri(Configuration.getInstance().rest().baseURL().toString()).path(uriInfo.getBaseUri().getPath()).build().toString(); - defaultServer.setUrl(url); - return List.of(defaultServer); - } - - @NotNull - private Components createComponents() { - final Components components = new Components(); - components.addSecuritySchemes(BEARER_AUTH, getBearerScheme()); - return components; - } - - @NotNull - private SecurityScheme getBearerScheme() { - return new SecurityScheme() - .name(BEARER_AUTH) - .type(SecurityScheme.Type.HTTP) - .scheme("bearer") - .bearerFormat("JWT"); - } - -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/BadRequestExceptionMapper.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/BadRequestExceptionMapper.java deleted file mode 100644 index e4a606b..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/BadRequestExceptionMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.exception; - -import javax.ws.rs.BadRequestException; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; - -@Provider -public class BadRequestExceptionMapper implements ExceptionMapper { - - public Response toResponse(BadRequestException e) { - return Response.status(Response.Status.BAD_REQUEST.getStatusCode()) - .entity(e.getMessage()) - .build(); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/ForbiddenExceptionMapper.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/ForbiddenExceptionMapper.java deleted file mode 100644 index 49e9596..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/ForbiddenExceptionMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.exception; - -import javax.ws.rs.ForbiddenException; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; - -@Provider -public class ForbiddenExceptionMapper implements ExceptionMapper { - - public Response toResponse(ForbiddenException e) { - return Response.status(Response.Status.FORBIDDEN.getStatusCode()) - .entity(e.getMessage()) - .build(); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/IllegalArgumentExceptionMapper.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/IllegalArgumentExceptionMapper.java deleted file mode 100644 index f7c82a6..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/IllegalArgumentExceptionMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.exception; - -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; - -@Provider -public class IllegalArgumentExceptionMapper implements ExceptionMapper { - - public Response toResponse(IllegalArgumentException e) { - return Response.status(Response.Status.BAD_REQUEST.getStatusCode()) - .entity(e.getMessage()) - .build(); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/InternalServerErrorExceptionMapper.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/InternalServerErrorExceptionMapper.java deleted file mode 100644 index bd21253..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/InternalServerErrorExceptionMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.exception; - -import javax.ws.rs.InternalServerErrorException; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; - -@Provider -public class InternalServerErrorExceptionMapper implements ExceptionMapper { - - public Response toResponse(InternalServerErrorException e) { - return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) - .entity(e.getMessage()) - .build(); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/NotFoundExceptionMapper.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/NotFoundExceptionMapper.java deleted file mode 100644 index d726fb5..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/NotFoundExceptionMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.exception; - -import javax.ws.rs.NotFoundException; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; - -@Provider -public class NotFoundExceptionMapper implements ExceptionMapper { - - public Response toResponse(NotFoundException e) { - return Response.status(Response.Status.NOT_FOUND.getStatusCode()) - .entity(e.getMessage()) - .build(); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/UncaughtExceptionMapper.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/UncaughtExceptionMapper.java deleted file mode 100644 index 3f3c9d7..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/exception/UncaughtExceptionMapper.java +++ /dev/null @@ -1,34 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.exception; - -import ch.sbb.polarion.extension.interceptor.rest.filter.LogoutFilter; -import com.polarion.core.util.logging.Logger; - -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; - -/** - * Default mapper for all unmapped exceptions. - * If you delete this mapper then {@link LogoutFilter} - * will stop working. - */ -@Provider -public class UncaughtExceptionMapper implements ExceptionMapper { - - private static final Logger logger = Logger.getLogger(UncaughtExceptionMapper.class); - - public Response toResponse(Throwable throwable) { - if (throwable instanceof WebApplicationException webapplicationexception) { - - //this block covers cases when the specific WebApplicationException was thrown but - //there is no explicit mapper for it (e.g. NotAuthorizedException) - return webapplicationexception.getResponse(); - } else { - logger.error("Uncaught exception", throwable); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) - .entity(throwable.getMessage()) - .build(); - } - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/filter/AuthenticationFilter.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/filter/AuthenticationFilter.java deleted file mode 100644 index 5e01a1e..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/filter/AuthenticationFilter.java +++ /dev/null @@ -1,61 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.filter; - -import com.polarion.platform.core.PlatformContext; -import com.polarion.platform.security.AuthenticationFailedException; -import com.polarion.platform.security.ISecurityService; -import com.polarion.platform.security.login.AccessToken; -import com.polarion.platform.security.login.IToken; - -import javax.security.auth.Subject; -import javax.ws.rs.NotAuthorizedException; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerRequestFilter; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.Provider; -import java.io.IOException; - -@Secured -@Provider -public class AuthenticationFilter implements ContainerRequestFilter { - - public static final String BEARER = "Bearer"; - public static final String USER_SUBJECT = "user_subject"; - private final ISecurityService securityService; - - public AuthenticationFilter(ISecurityService securityService) { - this.securityService = securityService; - } - - public AuthenticationFilter() { - this.securityService = PlatformContext.getPlatform().lookupService(ISecurityService.class); - } - - @Override - public void filter(ContainerRequestContext requestContext) throws IOException { - final String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); - - if (authorizationHeader == null || !authorizationHeader.startsWith(BEARER)) { - throw new NotAuthorizedException("Authorization header must be provided", Response.status(Response.Status.UNAUTHORIZED).header("WWW-Authenticate", BEARER).build()); - } - - final String token = authorizationHeader.substring(BEARER.length()).trim(); - - try { - Subject subject = validateToken(token); - requestContext.setProperty(USER_SUBJECT, subject); - } catch (AuthenticationFailedException e) { - requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build()); - } - } - - private Subject validateToken(String token) throws AuthenticationFailedException { - final IToken accessToken = AccessToken.token(token); - - return securityService.login() - .from("REST") - .authenticator(AccessToken.id()) - .with(accessToken) - .perform(); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/filter/LogoutFilter.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/filter/LogoutFilter.java deleted file mode 100644 index 51ad66a..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/filter/LogoutFilter.java +++ /dev/null @@ -1,36 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.filter; - -import com.polarion.platform.core.PlatformContext; -import com.polarion.platform.security.ISecurityService; - -import javax.security.auth.Subject; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerResponseContext; -import javax.ws.rs.container.ContainerResponseFilter; -import javax.ws.rs.ext.Provider; -import java.io.IOException; - -@Secured -@Provider -public class LogoutFilter implements ContainerResponseFilter { - - private final ISecurityService securityService; - - public LogoutFilter(ISecurityService securityService) { - this.securityService = securityService; - } - - @SuppressWarnings("unused") - public LogoutFilter() { - this.securityService = PlatformContext.getPlatform().lookupService(ISecurityService.class); - } - - @Override - public void filter(ContainerRequestContext requestContext, - ContainerResponseContext responseContext) throws IOException { - Subject subject = (Subject) requestContext.getProperty(AuthenticationFilter.USER_SUBJECT); - if (subject != null) { - securityService.logout(subject); - } - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/filter/Secured.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/filter/Secured.java deleted file mode 100644 index 0afe620..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/filter/Secured.java +++ /dev/null @@ -1,14 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.filter; - -import javax.ws.rs.NameBinding; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@NameBinding -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.TYPE}) -public @interface Secured { - -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/model/Context.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/model/Context.java deleted file mode 100644 index 6c9db03..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/model/Context.java +++ /dev/null @@ -1,24 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.model; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class Context { - private String extensionContext; - - public String getBaseUrl() { - return "/polarion/" + extensionContext; - } - - public String getRestUrl() { - return "/polarion/" + extensionContext + "/rest"; - } - - public String getSwaggerUiUrl() { - return getRestUrl() + "/swagger"; - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/model/Version.java b/src/main/java/ch/sbb/polarion/extension/interceptor/rest/model/Version.java deleted file mode 100644 index d562cc6..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/rest/model/Version.java +++ /dev/null @@ -1,20 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.model; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class Version { - private String bundleName; - private String bundleVendor; - private String automaticModuleName; - private String bundleVersion; - private String bundleBuildTimestamp; - - public String getBundleBuildTimestampDigitsOnly() { - return bundleBuildTimestamp.replaceAll("\\D", ""); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/service/PolarionService.java b/src/main/java/ch/sbb/polarion/extension/interceptor/service/PolarionService.java deleted file mode 100644 index 3be2e5e..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/service/PolarionService.java +++ /dev/null @@ -1,40 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.service; - -import ch.sbb.polarion.extension.interceptor.util.RequestContextUtil; -import com.polarion.platform.core.PlatformContext; -import com.polarion.platform.security.ISecurityService; -import lombok.Getter; -import lombok.SneakyThrows; -import org.jetbrains.annotations.NotNull; - -import java.security.PrivilegedAction; -import java.security.PrivilegedExceptionAction; -import java.util.concurrent.Callable; - -@Getter -public class PolarionService { - - protected final ISecurityService securityService; - - public PolarionService() { - securityService = PlatformContext.getPlatform().lookupService(ISecurityService.class); - } - - public PolarionService(@NotNull ISecurityService securityService) { - this.securityService = securityService; - } - - @SneakyThrows - public T callPrivileged(Callable callable) { - return securityService.doAsUser(RequestContextUtil.getUserSubject(), (PrivilegedExceptionAction) callable::call); - } - - @SneakyThrows - public void callPrivileged(Runnable runnable) { - securityService.doAsUser(RequestContextUtil.getUserSubject(), (PrivilegedAction) () -> { - runnable.run(); - return null; - } - ); - } -} \ No newline at end of file diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/HookModel.java b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/HookModel.java index 24ba629..32c9eae 100644 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/HookModel.java +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/HookModel.java @@ -1,5 +1,6 @@ package ch.sbb.polarion.extension.interceptor.settings; +import ch.sbb.polarion.extension.generic.settings.SettingsModel; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/HookSettings.java b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/HookSettings.java index 0bc77f1..931e9c2 100644 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/HookSettings.java +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/HookSettings.java @@ -1,100 +1,29 @@ package ch.sbb.polarion.extension.interceptor.settings; +import ch.sbb.polarion.extension.generic.settings.GenericNamedSettings; import ch.sbb.polarion.extension.interceptor.model.ActionHook; -import ch.sbb.polarion.extension.interceptor.util.ScopeUtils; -import com.polarion.core.util.StringUtils; -import com.polarion.subterra.base.location.ILocation; import org.jetbrains.annotations.NotNull; -import java.util.List; -import java.util.Objects; - -public class HookSettings implements Settings { - - public static final String LOCATION = ".polarion/extensions/interceptor/%s.settings"; - private final SettingsService settingsService; +public class HookSettings extends GenericNamedSettings { private final ActionHook hook; public HookSettings(ActionHook hook) { + super(hook.getName()); this.hook = hook; - this.settingsService = new SettingsService(); - } - - public @NotNull String getHookName() { - return hook.getName(); - } - - @Override - public String relativeLocation() { - return String.format(LOCATION, hook.getName()); - } - - @Override - public HookModel read(@NotNull String scope, String revisionName) { - return read(ScopeUtils.getContextLocation(scope), revisionName); } @Override - public HookModel read(@NotNull ILocation contextLocation, String revisionName) { - final ILocation location = contextLocation.append(relativeLocation()); - String value = settingsService.read(location, revisionName); - if (value == null) { - if (!StringUtils.isEmpty(revisionName)) { - return null; - } - ILocation defaultLocation = ScopeUtils.getDefaultLocation().append(relativeLocation()); - if (!settingsService.exists(defaultLocation)) { - try { - return save(ScopeUtils.SCOPE_DEFAULT, defaultValues()); - } catch (Exception e) { - return defaultValues(); - } - } - value = settingsService.read(defaultLocation, null); - } - return fromString(value); - } - - @Override - public HookModel save(@NotNull String scope, @NotNull HookModel what) { - final ILocation contextLocation = ScopeUtils.getContextLocation(scope); - return save(contextLocation, what); + public void beforeSave(@NotNull HookModel what) { + what.setHookVersion(hook.getVersion()); } @Override - public HookModel save(@NotNull ILocation contextLocation, @NotNull HookModel what) { - final ILocation location = contextLocation.append(relativeLocation()); - what.setBundleTimestamp(currentBundleTimestamp()); - what.setHookVersion(hook.getVersion()); - String content = toString(what); - settingsService.save(location, content); + public void afterSave(@NotNull HookModel what) { hook.loadSettings(true); - return what; - } - - public @NotNull List listRevisions(ILocation location) { - final ILocation contextLocation = location.append(relativeLocation()); - return settingsService.listRevisions(contextLocation); } @Override public @NotNull HookModel defaultValues() { return HookModel.builder().enabled(true).hookVersion(hook.getVersion()).properties(hook.getDefaultSettings()).build(); } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - return Objects.equals(getHookName(), ((HookSettings) o).getHookName()); - } - - @Override - public int hashCode() { - return Objects.hash(getHookName()); - } } diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/Revision.java b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/Revision.java deleted file mode 100644 index 2815b1f..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/Revision.java +++ /dev/null @@ -1,51 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.settings; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.polarion.core.util.logging.Logger; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import lombok.ToString; -import org.jetbrains.annotations.NotNull; - -/** - * Used to keep and transfer information about particular revision. - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@ToString -@EqualsAndHashCode -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Revision implements Comparable { - - private static final Logger logger = Logger.getLogger((Object) Revision.class); - - private String name; - private String date; - private String author; - private String description; - - @Override - public int compareTo(@NotNull Revision that) { - - long thisRevision = 0L; - long thatRevision = 0L; - - try { - thisRevision = Long.parseLong(name); - } catch (NumberFormatException e) { - logger.warn("Unexpected revision name found: " + name); - } - try { - thatRevision = Long.parseLong(that.name); - } catch (NumberFormatException e) { - logger.warn("Unexpected revision name found: " + name); - } - - return Long.compare(thatRevision, thisRevision); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingId.java b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingId.java deleted file mode 100644 index a990af6..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingId.java +++ /dev/null @@ -1,53 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.settings; - -import java.util.Objects; - -/** - * Settings can be queried/processed using either NAME or ID (fileName). - */ -public class SettingId { - - /** - * ID or NAME depending on {@link SettingId#useName} - */ - final String identifier; - - final boolean useName; - - private SettingId(String identifier, boolean useName) { - this.identifier = identifier; - this.useName = useName; - } - - public static SettingId fromName(String name) { - return new SettingId(name, true); - } - - public static SettingId fromId(String id) { - return new SettingId(id, false); - } - - public String getIdentifier() { - return identifier; - } - - @SuppressWarnings("unused") - public boolean isUseName() { - return useName; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) { - return false; - } - SettingId settingId = (SettingId) o; - return useName == settingId.useName && Objects.equals(identifier, settingId.identifier); - } - - @Override - public int hashCode() { - return Objects.hash(identifier, useName); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingName.java b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingName.java deleted file mode 100644 index d58a5c0..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingName.java +++ /dev/null @@ -1,30 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.settings; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.Builder; -import lombok.Data; - -import java.util.Objects; - -@Data -@Builder -public class SettingName { - - @JsonIgnore - private String id; - private String name; - private String scope; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - SettingName that = (SettingName) o; - return Objects.equals(name, that.name); - } - - @Override - public int hashCode() { - return Objects.hash(name); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/Settings.java b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/Settings.java deleted file mode 100644 index 42623c7..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/Settings.java +++ /dev/null @@ -1,47 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.settings; - -import ch.sbb.polarion.extension.interceptor.util.VersionUtils; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.polarion.subterra.base.location.ILocation; -import lombok.SneakyThrows; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.ParameterizedType; - -public interface Settings { - - String relativeLocation(); - - T read(@NotNull String scope, String revisionName); - - T read(@NotNull ILocation contextLocation, String revisionName); - - T save(@NotNull String scope, @NotNull T what); - - T save(@NotNull ILocation contextLocation, @NotNull T what); - - @NotNull T defaultValues(); - - default @NotNull String currentBundleTimestamp() { - return VersionUtils.getVersion().getBundleBuildTimestamp(); - } - - @SneakyThrows - @SuppressWarnings("unchecked") - @NotNull default T fromString(String content) { - T model = ((Class) ((ParameterizedType) getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0]).getConstructor().newInstance(); - model.deserialize(content); - return model; - } - - @SneakyThrows - @NotNull default String toString(T what) { - return what.serialize(); - } - - @SneakyThrows - @SuppressWarnings("unchecked") - default T fromJson(String jsonString) { - return new ObjectMapper().readValue(jsonString, (Class) ((ParameterizedType) getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0]); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingsModel.java b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingsModel.java deleted file mode 100644 index b56a0d5..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingsModel.java +++ /dev/null @@ -1,101 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.settings; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.polarion.core.util.logging.Logger; -import lombok.Data; -import org.jetbrains.annotations.NotNull; - -@Data -public abstract class SettingsModel { - - private static final Logger logger = Logger.getLogger(SettingsModel.class); - - public static final String BEGIN_ENTRY = "-----BEGIN %s-----"; - public static final String END_ENTRY = "-----END %s-----"; - - public static final String BUNDLE_TIMESTAMP = "BUNDLE TIMESTAMP"; - public static final String NAME = "NAME"; - - @JsonIgnore - protected String name; - protected String bundleTimestamp; - - public String serialize() { - return serializeEntry(NAME, name) + serializeEntry(BUNDLE_TIMESTAMP, bundleTimestamp) + serializeModelData(); - } - - protected String serializeEntry(@NotNull String entryName, String entryContent) { - return entryContent == null ? "" : String.format(BEGIN_ENTRY, entryName) + - System.lineSeparator() + - entryContent + - System.lineSeparator() + - String.format(END_ENTRY, entryName) + - System.lineSeparator(); - } - - protected String serializeEntry(@NotNull String entryName, T entryContent) { - if (entryContent == null) { - return ""; - } - String content; - try { - content = new ObjectMapper().writeValueAsString(entryContent); - } catch (JsonProcessingException e) { - logger.error(String.format("Error serializing '%s' of %s class to String", entryContent, entryContent.getClass()), e); - content = null; - } - return content == null ? "" : String.format(BEGIN_ENTRY, entryName) + - System.lineSeparator() + - content + - System.lineSeparator() + - String.format(END_ENTRY, entryName) + - System.lineSeparator(); - } - - public void deserialize(String serializedString) { - name = deserializeEntry(NAME, serializedString); - bundleTimestamp = deserializeEntry(BUNDLE_TIMESTAMP, serializedString); - deserializeModelData(serializedString); - } - - protected String deserializeEntry(String entryName, String serializedString) { - if (serializedString == null) { - return null; - } - String beginEntry = String.format(BEGIN_ENTRY, entryName); - String endEntry = String.format(END_ENTRY, entryName); - int begin = serializedString.indexOf(beginEntry); - int end = serializedString.indexOf(endEntry); - if (begin != -1 && end > begin) { - int beginPos = begin + beginEntry.length(); - beginPos = serializedString.startsWith(System.lineSeparator(), beginPos) ? beginPos + System.lineSeparator().length() : beginPos; - int endPos = serializedString.substring(0, end).endsWith(System.lineSeparator()) ? end - System.lineSeparator().length() : end; - return beginPos >= endPos ? "" : serializedString.substring(beginPos, endPos); - } - return null; - } - - @SuppressWarnings("unchecked") - protected T deserializeEntry(String entryName, String serializedString, Class aClass) { - String deserializedEntry = deserializeEntry(entryName, serializedString); - if (deserializedEntry == null) { - return null; - } - if (String.class.equals(aClass)) { - return (T) deserializedEntry; - } else { - try { - return new ObjectMapper().readValue(deserializedEntry, aClass); - } catch (JsonProcessingException e) { - logger.error(String.format("Error deserializing '%s' to %s class", deserializedEntry, aClass), e); - return null; - } - } - } - - protected abstract String serializeModelData(); - - protected abstract void deserializeModelData(String serializedString); -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingsRegistry.java b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingsRegistry.java deleted file mode 100644 index f4f7c36..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingsRegistry.java +++ /dev/null @@ -1,27 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.settings; - -import javax.ws.rs.NotFoundException; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public enum SettingsRegistry { - INSTANCE; - - private final Set settingsSet = new HashSet<>(); - - /** - * Register a new setting. It's a good idea to call it before REST application initialization. - */ - public synchronized void register(List settingsList) { - settingsSet.clear(); - settingsSet.addAll(settingsList); - } - - public synchronized HookSettings getByHookName(String hookName) { - return settingsSet.stream() - .filter(s -> s.getHookName().equals(hookName)) - .findFirst() - .orElseThrow(() -> new NotFoundException("No settings found by hookName: " + hookName)); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingsService.java b/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingsService.java deleted file mode 100644 index be66662..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/settings/SettingsService.java +++ /dev/null @@ -1,125 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.settings; - -import com.polarion.alm.projects.IProjectService; -import com.polarion.alm.projects.model.IUser; -import com.polarion.alm.shared.api.transaction.ReadOnlyTransaction; -import com.polarion.alm.shared.api.transaction.TransactionalExecutor; -import com.polarion.core.util.StringUtils; -import com.polarion.core.util.logging.Logger; -import com.polarion.platform.core.PlatformContext; -import com.polarion.platform.internal.service.repository.ExtendedRevisionMetaData; -import com.polarion.platform.service.repository.IRepositoryConnection; -import com.polarion.platform.service.repository.IRepositoryReadOnlyConnection; -import com.polarion.platform.service.repository.IRepositoryService; -import com.polarion.subterra.base.location.ILocation; -import com.polarion.subterra.base.location.Location; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * Contains utility methods for load/save settings data and query revision information. - */ -public class SettingsService { - - private static final String REVISION_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm"; - private static final Logger logger = Logger.getLogger((Object) SettingsService.class); - - private final IRepositoryService repositoryService; - private final IProjectService projectService; - - public SettingsService() { - repositoryService = PlatformContext.getPlatform().lookupService(IRepositoryService.class); - projectService = PlatformContext.getPlatform().lookupService(IProjectService.class); - } - - public void save(@NotNull ILocation location, @NotNull String content) { - save(location, content.getBytes(StandardCharsets.UTF_8)); - } - - public void save(@NotNull ILocation location, byte[] content) { - Runnable runnable = () -> { - IRepositoryConnection connection = repositoryService.getConnection(location); - try (InputStream inputStream = new ByteArrayInputStream(content)) { - if (connection.exists(location)) { - connection.setContent(location, inputStream); - } else { - connection.create(location, inputStream); - } - } catch (IOException e) { - logger.error("Cannot save to location: " + location, e); - } - }; - - if (TransactionalExecutor.currentTransaction() == null) { - TransactionalExecutor.executeInWriteTransaction(transaction -> { - runnable.run(); - return null; - }); - } else { - runnable.run(); - } - } - - @Nullable - public String read(@NotNull ILocation location, String revisionName) { - return TransactionalExecutor.executeSafelyInReadOnlyTransaction(transaction -> { - IRepositoryReadOnlyConnection readOnlyConnection = repositoryService.getReadOnlyConnection(location); - if (!readOnlyConnection.exists(location)) { - logger.warn("Location does not exist: " + location.getLocationPath()); - return null; - } - - try (InputStream inputStream = readOnlyConnection.getContent(StringUtils.isEmpty(revisionName) ? location : Location.getLocationWithRevision(location.getLocationPath(), revisionName))) { - return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); - } catch (Exception e) { - logger.error("Error reading content from: " + location.getLocationPath() + ", revision: " + revisionName, e); - return null; - } - }); - } - - public boolean exists(@NotNull ILocation location) { - return Boolean.TRUE.equals( - TransactionalExecutor.executeSafelyInReadOnlyTransaction(transaction -> { - IRepositoryReadOnlyConnection readOnlyConnection = repositoryService.getReadOnlyConnection(location); - return readOnlyConnection.exists(location); - })); - } - - @SuppressWarnings("unchecked") - public List listRevisions(@NotNull ILocation location) { - return TransactionalExecutor.executeSafelyInReadOnlyTransaction(transaction -> { - IRepositoryReadOnlyConnection readOnlyConnection = repositoryService.getReadOnlyConnection(location); - if (!readOnlyConnection.exists(location)) { - logger.warn("Location does not exist: " + location.getLocationPath()); - return new ArrayList<>(); - } - - List metaDataList = readOnlyConnection.getRevisionsMetaData(location, true); - Map userNamesMap = projectService.getUsers().stream() - .collect(Collectors.toMap(IUser::getId, user -> user.getName() == null ? user.getId() : user.getName())); - - SimpleDateFormat dateFormat = new SimpleDateFormat(REVISION_DATE_TIME_FORMAT); - return metaDataList.stream() - .filter(metaData -> metaData.getChangeLocationTo() == null || metaData.getChangeLocationTo().getLastComponent().equals(location.getLastComponent())) - .map(metaData -> Revision.builder() - .name(metaData.getName()) - .date(dateFormat.format(metaData.getDate())) - .author(userNamesMap.getOrDefault(metaData.getAuthor(), metaData.getAuthor())) - .description(metaData.getDescription()) - .build()) - .sorted() - .toList(); - }); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/util/ContextUtils.java b/src/main/java/ch/sbb/polarion/extension/interceptor/util/ContextUtils.java deleted file mode 100644 index 374fccc..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/util/ContextUtils.java +++ /dev/null @@ -1,20 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.util; - -import ch.sbb.polarion.extension.interceptor.rest.model.Context; -import lombok.experimental.UtilityClass; -import org.jetbrains.annotations.NotNull; - -import java.util.jar.Attributes; - -@UtilityClass -public class ContextUtils { - - public static final String EXTENSION_CONTEXT = "Extension-Context"; - - @NotNull - public static Context getContext() { - final Attributes attributes = ManifestUtils.getManifestAttributes(); - String extensionContext = attributes.getValue(EXTENSION_CONTEXT); - return new Context(extensionContext); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/util/ExtensionInfo.java b/src/main/java/ch/sbb/polarion/extension/interceptor/util/ExtensionInfo.java deleted file mode 100644 index 6335e76..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/util/ExtensionInfo.java +++ /dev/null @@ -1,25 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.util; - -import ch.sbb.polarion.extension.interceptor.rest.model.Context; -import ch.sbb.polarion.extension.interceptor.rest.model.Version; -import lombok.Getter; - -@Getter -public final class ExtensionInfo { - - private final Version version; - private final Context context; - - private ExtensionInfo() { - version = VersionUtils.getVersion(); - context = ContextUtils.getContext(); - } - - public static ExtensionInfo getInstance() { - return ExtensionInfoHolder.INSTANCE; - } - - private static class ExtensionInfoHolder { - private static final ExtensionInfo INSTANCE = new ExtensionInfo(); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/util/ManifestUtils.java b/src/main/java/ch/sbb/polarion/extension/interceptor/util/ManifestUtils.java deleted file mode 100644 index e7d7335..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/util/ManifestUtils.java +++ /dev/null @@ -1,28 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.util; - -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; - -import javax.ws.rs.InternalServerErrorException; -import java.io.InputStream; -import java.net.URL; -import java.util.Enumeration; -import java.util.jar.Attributes; -import java.util.jar.Manifest; - -@UtilityClass -public class ManifestUtils { - - @SneakyThrows - public static Attributes getManifestAttributes() { - Enumeration resources = VersionUtils.class.getClassLoader().getResources("META-INF/MANIFEST.MF"); - if (resources.hasMoreElements()) { - try (InputStream inputStream = resources.nextElement().openStream()) { - Manifest manifest = new Manifest(inputStream); - return manifest.getMainAttributes(); - } - } - - throw new InternalServerErrorException("Manifest information could not be found or read"); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/util/RequestContextUtil.java b/src/main/java/ch/sbb/polarion/extension/interceptor/util/RequestContextUtil.java deleted file mode 100644 index 1be32fb..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/util/RequestContextUtil.java +++ /dev/null @@ -1,23 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.util; - -import ch.sbb.polarion.extension.interceptor.rest.filter.AuthenticationFilter; -import lombok.experimental.UtilityClass; -import org.jetbrains.annotations.Nullable; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import javax.security.auth.Subject; - -@UtilityClass -public final class RequestContextUtil { - - @Nullable - public static Subject getUserSubject() { - ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); - if (requestAttributes != null) { - return (Subject) requestAttributes.getRequest().getAttribute(AuthenticationFilter.USER_SUBJECT); - } else { - throw new IllegalStateException("Cannot find request attributes in the request context"); - } - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/util/ScopeUtils.java b/src/main/java/ch/sbb/polarion/extension/interceptor/util/ScopeUtils.java deleted file mode 100644 index bb10b98..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/util/ScopeUtils.java +++ /dev/null @@ -1,68 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.util; - -import com.polarion.alm.projects.IProjectService; -import com.polarion.alm.projects.internal.model.Project; -import com.polarion.alm.projects.model.IProject; -import com.polarion.core.util.StringUtils; -import com.polarion.platform.core.PlatformContext; -import com.polarion.platform.service.repository.IRepositoryService; -import com.polarion.subterra.base.location.ILocation; -import com.polarion.subterra.base.location.Location; -import lombok.experimental.UtilityClass; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.ws.rs.NotFoundException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -@UtilityClass -public class ScopeUtils { - - public static final String SCOPE_DEFAULT = ""; - - @NotNull - public static ILocation getContextLocation(@NotNull String scope) { - if (StringUtils.isEmpty(scope)) { - return getDefaultLocation(); - } else { - String project = getProjectFromScope(scope); - if (project == null) { - throw new IllegalArgumentException(String.format("Wrong scope format: %s. Should be of form 'project/{projectId}/'", scope)); - } - try { - return getContextLocationByProject(project); - } catch (Exception e) { - throw new NotFoundException("No scope found: " + scope, e); - } - } - } - - @NotNull - public static ILocation getContextLocationByProject(@NotNull String projectId) { - final IProjectService projectService = PlatformContext.getPlatform().lookupService(IProjectService.class); - final IProject project = projectService.getProject(projectId); - if (((Project) project).exists()) { - return project.getLocation(); - } else { - throw new NotFoundException("Project '" + projectId + "' does not exist"); - } - } - - @Nullable - public static String getProjectFromScope(@NotNull String scope) { - if (!StringUtils.isEmptyTrimmed(scope)) { - Pattern pattern = Pattern.compile("project/(.*)/"); - Matcher matcher = pattern.matcher(scope); - if (matcher.matches()) { - return matcher.group(1); // project - } - } - return null; - } - - @NotNull - public static ILocation getDefaultLocation() { - return Location.getLocationWithRepository(IRepositoryService.DEFAULT, "/"); - } -} diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/util/VersionUtils.java b/src/main/java/ch/sbb/polarion/extension/interceptor/util/VersionUtils.java deleted file mode 100644 index 6f966b0..0000000 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/util/VersionUtils.java +++ /dev/null @@ -1,29 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.util; - -import ch.sbb.polarion.extension.interceptor.rest.model.Version; -import lombok.experimental.UtilityClass; -import org.jetbrains.annotations.NotNull; - -import java.util.jar.Attributes; - -@UtilityClass -public class VersionUtils { - - public static final String BUNDLE_NAME = "Bundle-Name"; - public static final String BUNDLE_VENDOR = "Bundle-Vendor"; - public static final String AUTOMATIC_MODULE_NAME = "Automatic-Module-Name"; - public static final String BUNDLE_VERSION = "Bundle-Version"; - public static final String BUNDLE_BUILD_TIMESTAMP = "Bundle-Build-Timestamp"; - - @NotNull - public static Version getVersion() { - final Attributes attributes = ManifestUtils.getManifestAttributes(); - String bundleName = attributes.getValue(BUNDLE_NAME); - String bundleVendor = attributes.getValue(BUNDLE_VENDOR); - String automaticModuleName = attributes.getValue(AUTOMATIC_MODULE_NAME); - String bundleVersion = attributes.getValue(BUNDLE_VERSION); - String bundleBuildTimestamp = attributes.getValue(BUNDLE_BUILD_TIMESTAMP); - return new Version(bundleName, bundleVendor, automaticModuleName, bundleVersion, bundleBuildTimestamp); - } - -} diff --git a/src/main/resources/swagger_ui.html b/src/main/resources/swagger_ui.html deleted file mode 100644 index bcd8a9a..0000000 --- a/src/main/resources/swagger_ui.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - Swagger UI - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - \ No newline at end of file diff --git a/src/main/resources/webapp/interceptor-admin/css/about.css b/src/main/resources/webapp/interceptor-admin/css/about.css deleted file mode 100644 index c3fb0d6..0000000 --- a/src/main/resources/webapp/interceptor-admin/css/about.css +++ /dev/null @@ -1,35 +0,0 @@ -.about-page-text { - font-size: 13px; -} - -.monospace { - font-family: monospace; -} - -.about-page-text table { - border-collapse: collapse; -} - -.about-page-text table th { - height: 12px; - padding: 5px; - text-align: left; - border: 1px solid #CCCCCC; - font-weight: bold; - vertical-align: top; - white-space: nowrap; - background-color: #F0F0F0; -} - -.about-page-text table td { - height: 12px; - text-align: left; - vertical-align: top; - line-height: 18px; - border: 1px solid #CCCCCC; - padding: 5px; -} - -.about-page-text table td:first-child { - padding-left: 10px -} \ No newline at end of file diff --git a/src/main/resources/webapp/interceptor-admin/css/code-input.min.css b/src/main/resources/webapp/interceptor-admin/css/code-input.min.css deleted file mode 100644 index eba00f3..0000000 --- a/src/main/resources/webapp/interceptor-admin/css/code-input.min.css +++ /dev/null @@ -1 +0,0 @@ -code-input{position:relative;top:0;left:0;display:block;overflow:hidden;margin:8px;--padding:16px;height:250px;font-size:normal;font-family:monospace;line-height:1.5;tab-size:2;caret-color:#a9a9a9;white-space:pre;padding:0!important}code-input textarea,code-input.code-input_pre-element-styled pre,code-input:not(.code-input_pre-element-styled) pre code{margin:0!important;padding:var(--padding,16px)!important;border:0;width:calc(100% - var(--padding,16px) * 2);height:calc(100% - var(--padding,16px) * 2)}code-input:not(.code-input_loaded){margin:0!important;margin-bottom:calc(-1 * var(--padding,16px))!important;padding:var(--padding,16px)!important;border:0}code-input.code-input_pre-element-styled pre code,code-input:not(.code-input_pre-element-styled) pre{margin:0!important;padding:0!important;width:100%;height:100%}code-input pre,code-input pre *,code-input textarea{font-size:inherit!important;font-family:inherit!important;line-height:inherit!important;tab-size:inherit!important}code-input pre,code-input textarea{position:absolute;top:0;left:0}code-input textarea{z-index:1}code-input pre{z-index:0}code-input:not(.code-input_loaded) pre,code-input:not(.code-input_loaded) textarea{opacity:0}code-input:not(.code-input_loaded)::after{color:#ccc}code-input textarea{color:transparent;background:0 0;caret-color:inherit!important}code-input textarea::placeholder{color:#d3d3d3}code-input pre,code-input textarea{overflow:auto!important;white-space:inherit;word-spacing:normal;word-break:normal;word-wrap:normal}code-input textarea{resize:none;outline:0!important}code-input:not(.code-input_registered)::after{content:"Use codeInput.registerTemplate to set up.";display:block;color:grey} \ No newline at end of file diff --git a/src/main/resources/webapp/interceptor-admin/css/common.css b/src/main/resources/webapp/interceptor-admin/css/common.css deleted file mode 100644 index 304e0b1..0000000 --- a/src/main/resources/webapp/interceptor-admin/css/common.css +++ /dev/null @@ -1,294 +0,0 @@ -@font-face { - font-family: "Selawik"; - src: url("/polarion/ria/fonts/selawik/selawk.ttf"); -} - -@font-face { - font-family: "Selawik"; - src: url("/polarion/ria/fonts/selawik/selawkb.ttf"); - font-weight: bold; -} - -@font-face { - font-family: "Open Sans"; - src: url("/polarion/ria/fonts/opensans/OpenSans-Regular.ttf"); -} - -@font-face { - font-family: "Open Sans"; - src: url("/polarion/ria/fonts/opensans/OpenSans-Bold.ttf"); - font-weight: bold; -} - -@font-face { - font-family: "Open Sans"; - src: url("/polarion/ria/fonts/opensans/OpenSans-Italic.ttf"); - font-style: italic; -} - -@font-face { - font-family: "Open Sans"; - src: url("/polarion/ria/fonts/opensans/OpenSans-BoldItalic.ttf"); - font-weight: bold; - font-style: italic; -} - -a, td, div, li, ul, input, button, option { - font-family: "Segoe UI", "Selawik", "Open Sans", Arial, sans-serif; -} - -body, input, select { - font-size: 13px; -} - -input { - padding: 3px 6px; -} - -select { - padding: 3px; -} - -.monospace { - font-family: monospace; -} - -.standard-admin-page h1, .standard-admin-page h2, .standard-admin-page h3 { - color: #004d73; - font-weight: bold; -} - -.standard-admin-page h1 { - font-size: 30px; - line-height: 38px; - margin-top: 10px; - border-bottom: 4px solid #EBF0F5; -} - -.standard-admin-page h2 { - font-size: 23px; - line-height: 31px; - margin-top: 24px; - padding: 8px 14px; - background-color: #EBF0F5; -} - -.standard-admin-page h3 { - font-size: 16px; - line-height: 24px; - margin-top: 20px; - padding-left: 4px; - padding-bottom: 0; -} - -.html-input { - overflow: hidden; - display: block; -} - -.html-input.vertical-resizable { - resize: vertical; -} - -code-input.code-input_pre-element-styled { - height: 320px; -} - -code-input { - margin: 0; -} - -.label-block { - font-weight: bold; - font-size: 16px; - padding-left: 10px; - white-space: nowrap; - text-shadow: white 1px 1px 0.01em; - text-align: left; - padding-bottom: 3px; - background: #EBF0F5; - width: auto; - color: #004D73; - padding-top: 5px; - margin-bottom: 3px; -} - -.input-block.wide { - width: 98%; -} - -.input-block { - display: inline-block; - width: 32%; - padding-left: 1%; -} - -.input-block.left { - float: left; -} - -.input-block.right { - float: right; -} - -.input-container .input-block:last-child { - padding-right: 1%; -} - -.action-alerts .alert { - font-size: 12px; - font-weight: bold; - padding-left: 20px; -} - -.action-alerts .alert-error { - color: red; -} - -.action-alerts .alert-success { - color: green; -} - -.notifications .alert { - margin-bottom: 10px; - font-size: 12px; - padding: 8px 16px 5px; - border-radius: 3px; - width: calc(100% - 32px); -} - -.notifications .alert > span { - vertical-align: super; - padding-left: 5px; -} - -.notifications .alert-error { - background-color: #f8d7da; - border: 1px solid #b3626a; -} - -.notifications .alert-warning { - background-color: #fff7cd; - border: 1px solid #ffc328; -} - -.notifications .alert-success { - background-color: #d1e7dd; - border: 1px solid #75b598; -} - -.actions-pane { - background: #f5f5f5; - border-bottom: 1px solid #dedede; - padding: 8px 8px; - vertical-align: middle; - width: auto; - margin-top: 24px; -} - -.toolbar-button { - font-size: 12px; - font-weight: bold; - padding: 3px 6px; - margin-right: 5px; - text-align: left; - vertical-align: middle; - white-space: nowrap; - text-shadow: white 1px 1px 0.01em; - border: 1px solid #DEDEDE; - -moz-border-radius: 2px; - border-radius: 2px; - height: 28px; - color: #595959; - border-collapse: separate; - line-height: 16px; -} - -.toolbar-button:hover { - cursor: pointer; -} - -.button-image { - padding-right: 5px; - float: left; -} - -:not(pre) > code[class*=language-], -pre[class*=language-] { - background: #F2F2F2; -} - -.inline-flex { - display: inline-flex; -} - -#revisions-expand-container { - width:100%; - max-height: 150px; - overflow-y: scroll; - margin-bottom: 8px; - display: none; -} - -#revisions-table { - width: 100%; - border-collapse: collapse; - color: black; - text-align: center; -} - -#revisions-table thead th { - position: sticky; - top: 0; -} - -#revisions-table th { - font-family: Arial, Helvetica, sans-serif; - font-weight: bold; - font-size: 8pt; - background: #75A8E2; - color: black; - border-top: 0; - border-bottom: 3px solid #CCD8E5; - border-right: 1px solid #CCD8E5; - padding: 2px 5px 2px 5px; -} - -#revisions-table td { - font-family: Arial, Helvetica, sans-serif; - font-size: 11px; - background: #E9F3FA; - padding: 0 5px; - border: 1px solid #C0DAEA; -} - -#revisions-table tr:nth-child(even) td { - background: #E9F3FA; -} - -#revisions-table tr:nth-child(odd) td { - background: white; -} - -#revisions-table .empty-message { - padding: 5px; -} - -.revert-to-revision-button { - margin: 0; - padding: 0; - border: none; -} - -.revert-to-revision-button:hover { - cursor: pointer; - background: #FFC328; -} - -.revision-number { - color: blue; -} - -.quick-help-text { - font-size: 13px; -} diff --git a/src/main/resources/webapp/interceptor-admin/css/prism.css b/src/main/resources/webapp/interceptor-admin/css/prism.css deleted file mode 100644 index def066e..0000000 --- a/src/main/resources/webapp/interceptor-admin/css/prism.css +++ /dev/null @@ -1,3 +0,0 @@ -/* PrismJS 1.29.0 -https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ -code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help} diff --git a/src/main/resources/webapp/interceptor-admin/js/code-input.min.js b/src/main/resources/webapp/interceptor-admin/js/code-input.min.js deleted file mode 100644 index 5470617..0000000 --- a/src/main/resources/webapp/interceptor-admin/js/code-input.min.js +++ /dev/null @@ -1 +0,0 @@ -var codeInput={observedAttributes:["value","placeholder","lang","template"],textareaSyncAttributes:["aria-*","value","min","max","type","pattern","autocomplete","autocorrect","autofocus","cols","dirname","disabled","form","maxlength","minlength","name","placeholder","readonly","required","rows","spellcheck","wrap"],textareaSyncEvents:["change","selectionchange","invalid","input"],usedTemplates:{},defaultTemplate:void 0,templateNotYetRegisteredQueue:{},registerTemplate:function(a,b){if(!("string"==typeof a||a instanceof String))throw TypeError(`code-input: Template for "${a}" must be a string.`);if(!("function"==typeof b.highlight||b.highlight instanceof Function))throw TypeError(`code-input: Template for "${a}" invalid, because the highlight function provided is not a function; it is "${b.highlight}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.includeCodeInputInHighlightFunc||b.includeCodeInputInHighlightFunc instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the includeCodeInputInHighlightFunc value provided is not a true or false; it is "${b.includeCodeInputInHighlightFunc}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.preElementStyled||b.preElementStyled instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the preElementStyled value provided is not a true or false; it is "${b.preElementStyled}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.isCode||b.isCode instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the isCode value provided is not a true or false; it is "${b.isCode}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!Array.isArray(b.plugins))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin array provided is not an array; it is "${b.plugins}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(b.plugins.forEach((c,d)=>{if(!(c instanceof codeInput.Plugin))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin provided at index ${d} is not valid; it is "${b.plugins[d]}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`)}),codeInput.usedTemplates[a]=b,a in codeInput.templateNotYetRegisteredQueue){for(let c in codeInput.templateNotYetRegisteredQueue[a])elem=codeInput.templateNotYetRegisteredQueue[a][c],elem.template=b,codeInput.runOnceWindowLoaded(function(a){a.connectedCallback()}.bind(null,elem),elem);console.log(`code-input: template: Added existing elements with template ${a}`)}if(null==codeInput.defaultTemplate){if(codeInput.defaultTemplate=a,void 0 in codeInput.templateNotYetRegisteredQueue)for(let a in codeInput.templateNotYetRegisteredQueue[void 0])elem=codeInput.templateNotYetRegisteredQueue[void 0][a],elem.template=b,codeInput.runOnceWindowLoaded(function(a){a.connectedCallback()}.bind(null,elem),elem);console.log(`code-input: template: Set template ${a} as default`)}console.log(`code-input: template: Created template ${a}`)},Template:class{constructor(a=function(){},b=!0,c=!0,d=!1,e=[]){this.highlight=a,this.preElementStyled=b,this.isCode=c,this.includeCodeInputInHighlightFunc=d,this.plugins=e}highlight=function(){};preElementStyled=!0;isCode=!0;includeCodeInputInHighlightFunc=!1;plugins=[]},templates:{prism(a,b=[]){return{includeCodeInputInHighlightFunc:!1,highlight:a.highlightElement,preElementStyled:!0,isCode:!0,plugins:b}},hljs(a,b=[]){return{includeCodeInputInHighlightFunc:!1,highlight:a.highlightElement,preElementStyled:!1,isCode:!0,plugins:b}},characterLimit(a){return{highlight:function(a,b,c=[]){let d=+b.getAttribute("data-character-limit"),e=b.escapeHtml(b.value.slice(0,d)),f=b.escapeHtml(b.value.slice(d));a.innerHTML=`${e}${f}`,0${b.getAttribute("data-overflow-msg")||"(Character limit reached)"}`)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,plugins:a}},rainbowText(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return{highlight:function(a,b){let c=[],d=b.value.split(b.template.delimiter);for(let e=0;e${b.escapeHtml(d[e])}`);a.innerHTML=c.join(b.template.delimiter)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,rainbowColors:a,delimiter:b,plugins:c}},character_limit(){return this.characterLimit([])},rainbow_text(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return this.rainbowText(a,b,c)},custom(a=function(){},b=!0,c=!0,d=!1,e=[]){return{highlight:a,includeCodeInputInHighlightFunc:d,preElementStyled:b,isCode:c,plugins:e}}},plugins:new Proxy({},{get(a,b){if(a[b]==null)throw ReferenceError(`code-input: Plugin '${b}' is not defined. Please ensure you import the necessary files from the plugins folder in the WebCoder49/code-input repository, in the of your HTML, before the plugin is instatiated.`);return a[b]}}),Plugin:class{constructor(a){console.log("code-input: plugin: Created plugin"),a.forEach(a=>{let b=codeInput.wildcard2regex(a);null==b?codeInput.observedAttributes.push(a):codeInput.observedAttributes.regexp.push(b)})}beforeHighlight(){}afterHighlight(){}beforeElementsAdded(){}afterElementsAdded(){}attributeChanged(){}},CodeInput:class extends HTMLElement{constructor(){super()}_value="";textareaElement=null;preElement=null;codeElement=null;static formAssociated=!0;boundEventCallbacks={};pluginEvt(a,b){for(let c in this.template.plugins){let d=this.template.plugins[c];a in d&&(b===void 0?d[a](this):d[a](this,...b))}}update(a){if(!this.ignoreValueUpdate){if(null==this.textareaElement)return void this.addEventListener("code-input_load",()=>{this.update(a)});this.ignoreValueUpdate=!0,this.value=a,this.ignoreValueUpdate=!1,this.textareaElement.value!=a&&(this.textareaElement.value=a);let b=this.codeElement;"\n"==a[a.length-1]&&(a+=" "),b.innerHTML=this.escapeHtml(a),this.pluginEvt("beforeHighlight"),this.template.includeCodeInputInHighlightFunc?this.template.highlight(b,this):this.template.highlight(b),this.pluginEvt("afterHighlight")}}syncScroll(){let a=this.textareaElement,b=this.template.preElementStyled?this.preElement:this.codeElement;b.scrollTop=a.scrollTop,b.scrollLeft=a.scrollLeft}escapeHtml(a){return a.replace(/&/g,"&").replace(/")}getTemplate(){let a;return a=null==this.getAttribute("template")?codeInput.defaultTemplate:this.getAttribute("template"),a in codeInput.usedTemplates?codeInput.usedTemplates[a]:(a in codeInput.templateNotYetRegisteredQueue||(codeInput.templateNotYetRegisteredQueue[a]=[]),void codeInput.templateNotYetRegisteredQueue[a].push(this))}setup(){if(null!=this.textareaElement)return;this.classList.add("code-input_registered"),this.template.preElementStyled&&this.classList.add("code-input_pre-element-styled"),this.pluginEvt("beforeElementsAdded");let a=this.getAttribute("lang"),b=this.getAttribute("placeholder")||this.getAttribute("lang")||"",c=this.unescapeHtml(this.innerHTML)||this.getAttribute("value")||"";this.initialValue=c;let d=document.createElement("textarea");d.placeholder=b,""!=c&&(d.value=c),d.innerHTML=this.innerHTML,d.setAttribute("spellcheck","false"),this.innerHTML="",codeInput.textareaSyncAttributes.forEach(a=>{this.hasAttribute(a)&&d.setAttribute(a,this.getAttribute(a))}),codeInput.textareaSyncAttributes.regexp.forEach(a=>{for(const b of this.attributes)b.nodeName.match(a)&&d.setAttribute(b.nodeName,b.nodeValue)}),d.addEventListener("input",()=>{d.parentElement.update(d.value),d.parentElement.sync_scroll()}),d.addEventListener("scroll",()=>d.parentElement.sync_scroll()),this.textareaElement=d,this.append(d);let e=document.createElement("code"),f=document.createElement("pre");f.setAttribute("aria-hidden","true"),this.preElement=f,this.codeElement=e,f.append(e),this.append(f),this.template.isCode&&a!=null&&""!=a&&e.classList.add("language-"+a),this.pluginEvt("afterElementsAdded"),this.update(c),this.dispatchEvent(new CustomEvent("code-input_load"))}sync_scroll(){this.syncScroll()}escape_html(a){return this.escapeHtml(a)}get_template(){return this.getTemplate()}connectedCallback(){this.template=this.getTemplate(),this.template!=null&&(this.classList.add("code-input_registered"),codeInput.runOnceWindowLoaded(()=>{this.setup(),this.classList.add("code-input_loaded")},this)),this.mutationObserver=new MutationObserver(this.mutationObserverCallback.bind(this)),this.mutationObserver.observe(this,{attributes:!0,attributeOldValue:!0})}mutationObserverCallback(a){for(const b of a)if("attributes"===b.type){for(let a=0;a{a.match(b)&&(null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c))})}}addEventListener(a,b,c=void 0){let d=b.bind(this);this.boundEventCallbacks[b]=d,codeInput.textareaSyncEvents.includes(a)?c===void 0?null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d)}):this.textareaElement.addEventListener(a,d):null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d,c)}):this.textareaElement.addEventListener(a,d,c):c===void 0?super.addEventListener(a,d):super.addEventListener(a,d,c)}removeEventListener(a,b,c=null){let d=this.boundEventCallbacks[b];"change"==a?null===c?this.textareaElement.removeEventListener("change",d):this.textareaElement.removeEventListener("change",d,c):"selectionchange"==a?null===c?this.textareaElement.removeEventListener("selectionchange",d):this.textareaElement.removeEventListener("selectionchange",d,c):super.removeEventListener(a,b,c)}get value(){return this._value}set value(a){return(null===a||void 0===a)&&(a=""),this._value=a,this.update(a),a}get placeholder(){return this.getAttribute("placeholder")}set placeholder(a){return this.setAttribute("placeholder",a)}get validity(){return this.textareaElement.validity}get validationMessage(){return this.textareaElement.validationMessage}setCustomValidity(a){return this.textareaElement.setCustomValidity(a)}checkValidity(){return this.textareaElement.checkValidity()}reportValidity(){return this.textareaElement.reportValidity()}pluginData={};formResetCallback(){this.update(this.initialValue)}},arrayWildcards2regex(a){for(let b=0;bc.indexOf("*")||(a.regexp.push(new RegExp("^"+c.replace(/[/\-\\^$+?.()|[\]{}]/g,"\\$&").replace("*",".*")+"$","i")),a.splice(b--,1))}},wildcard2regex(a){return 0>a.indexOf("*")?null:new RegExp("^"+a.replace(/[/\-\\^$+?.()|[\]{}]/g,"\\$&").replace("*",".*")+"$","i")},runOnceWindowLoaded(a){codeInput.windowLoaded?a():window.addEventListener("load",a)},windowLoaded:!1};window.addEventListener("load",function(){codeInput.windowLoaded=!0}),Object.defineProperty(codeInput.textareaSyncAttributes,"regexp",{value:[],writable:!1,enumerable:!1,configurable:!1}),codeInput.observedAttributes=codeInput.observedAttributes.concat(codeInput.textareaSyncAttributes),Object.defineProperty(codeInput.observedAttributes,"regexp",{value:[],writable:!1,enumerable:!1,configurable:!1}),codeInput.arrayWildcards2regex(codeInput.textareaSyncAttributes),codeInput.arrayWildcards2regex(codeInput.observedAttributes),customElements.define("code-input",codeInput.CodeInput); \ No newline at end of file diff --git a/src/main/resources/webapp/interceptor-admin/js/context.js b/src/main/resources/webapp/interceptor-admin/js/context.js deleted file mode 100644 index 142a393..0000000 --- a/src/main/resources/webapp/interceptor-admin/js/context.js +++ /dev/null @@ -1,258 +0,0 @@ -const DEFAULT_CONFIGURATION = 'Default'; - -const InterceptorContext = { - - setting: "", - - init: function ({setting = "", initCodeInput = false, propertiesHighlighting = false}) { - this.setting = setting; - if (initCodeInput) { - codeInput.registerTemplate("code-input", codeInput.templates.prism(Prism), []); - if (propertiesHighlighting) { - Prism.languages.properties = { - comment: /^[ \t]*[#!].*$/m, - //ORIGINAL value: {pattern: /(^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+(?: *[=:] *(?! )| ))(?:\\(?:\r\n|[\s\S])|[^\\\r\n])+/m, lookbehind: !0, alias: "attr-value"}, - value: {pattern: /(^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\=])+(?: *= *(?! )| ))(?:\\(?:\r\n|[\s\S])|[^\\\r\n])+/m, lookbehind: !0, alias: "attr-value"}, - //ORIGINAL key: {pattern: /^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+(?= *[=:]| )/m, alias: "attr-name"}, - key: {pattern: /^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\=])+(?= *[=:]| )/m, alias: "attr-name"}, - punctuation: /[=:]/ - }; - } - } - }, - - getValueById: function (id) { - const elem = document.getElementById(id); - return elem && elem.value; - }, - - setValueById: function (id, value) { - const elem = document.getElementById(id); - if (elem) { - elem.value = value; - } - }, - - getCheckboxValueById: function (id) { - const elem = document.getElementById(id); - return elem && elem.checked; - }, - - setCheckboxValueById: function (id, checked) { - const elem = document.getElementById(id); - if (elem) { - elem.checked = checked; - } - }, - - showActionAlert: function ({containerId, message}) { - this.hideActionAlerts(); - - const container = document.getElementById(containerId); - if (container && message) { - container.innerHTML = message; - container.style.display = 'inline-block'; - } - setTimeout(function () { - InterceptorContext.hideActionAlerts(); - }, 5000); - }, - - showRevertedToRevisionAlert(revision) { - this.showActionAlert({ - containerId: 'action-success', - message: `Data reverted to revision ${revision.name}. Don't forget to save the data before leaving.` - }); - }, - - showRevertedToDefaultAlert() { - this.showActionAlert({ - containerId: 'action-success', - message: `Default value set. Don't forget to save the data before leaving.` - }); - }, - - showSaveSuccessAlert() { - this.showActionAlert({ - containerId: 'action-success', - message: `Data successfully saved.` - }); - }, - - showSaveErrorAlert() { - this.showActionAlert({ - containerId: 'action-error', - message: `Error occurred during saving the data.` - }); - }, - - hideActionAlerts: function() { - document.querySelectorAll('.action-alerts .alert').forEach(alertDiv => { - alertDiv.style.display = 'none'; - }); - }, - - setNewerVersionNotificationVisible: function (visible) { - document.getElementById('newer-version-warning').style.display = (visible ? 'block' : 'none') - }, - - setNoHooksNotificationVisible: function (visible) { - document.getElementById('no-hooks-registered').style.display = (visible ? 'block' : 'none') - }, - - setLoadingErrorNotificationVisible: function (visible) { - document.getElementById('data-loading-error').style.display = (visible ? 'block' : 'none') - }, - - setRevisionsLoadingErrorNotificationVisible: function (visible) { - document.getElementById('revisions-loading-error').style.display = (visible ? 'block' : 'none') - }, - - cancelEdit: function () { - if (confirm("Are you sure you want to cancel editing and revert all changes made?")) { - window.location.reload(); - } - }, - - callAsync: function ({method, url, contentType, body, onOk, onError}) { - const xhr = new XMLHttpRequest(); - xhr.open(method, url, true); - if (contentType) { - xhr.setRequestHeader('Content-Type', contentType); - } - xhr.send(body); - - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - if (xhr.status === 200 || xhr.status === 204) { - onOk(xhr.responseText); - } else { - if (onError === undefined) { - try { - InterceptorContext.showActionAlert({containerId: 'action-error', message: xhr.responseText}); - } catch { - alert('Error occurred (' + xhr.responseText + ').'); - } - } else { - onError(xhr.status, xhr.responseText) - } - } - } - }; - xhr.onerror = function () { - onError === undefined ? alert('Error occurred') : onError(); - }; - }, - - readAndFillRevisions: function ({setting, configurationName = DEFAULT_CONFIGURATION, revertToRevisionCallback}) { - const currentSetting = (setting ? setting : this.setting); - this.setRevisionsLoadingErrorNotificationVisible(false); - this.callAsync({ - method: 'GET', - url: `/polarion/interceptor/rest/internal/settings/${currentSetting}/revisions`, - contentType: 'application/json', - onOk: (responseText) => { - const revisions = JSON.parse(responseText); - const tableBody = document.getElementById('revisions-table').getElementsByTagName('tbody')[0]; - tableBody.innerHTML = ''; - for (const revision of revisions) { - const button = InterceptorContext.createRevertToRevisionButton(); - button.addEventListener("click", function () { - InterceptorContext.hideActionAlerts(); - InterceptorContext.callAsync({ - method: 'GET', - url: `/polarion/interceptor/rest/internal/settings/${currentSetting}?revision=${revision.name}`, - contentType: 'application/json', - onOk: (responseText) => { - if (revertToRevisionCallback !== undefined) { - revertToRevisionCallback(responseText); - } - InterceptorContext.showRevertedToRevisionAlert(revision); - } - }); - }); - - InterceptorContext.createRevisionRow(tableBody, revision, button); - } - if (revisions.length === 0) { - let cell = tableBody.insertRow().insertCell(); - cell.setAttribute("colspan", "5") - cell.className = 'empty-message'; - cell.appendChild(document.createTextNode("No saved revisions yet.")); - } - }, - onError: () => InterceptorContext.setRevisionsLoadingErrorNotificationVisible(true) - }); - }, - - createRevisionRow: function (tableBody, revision, revertToRevisionButton) { - const row = tableBody.insertRow(); - row.insertCell().appendChild(document.createTextNode(InterceptorContext.insertRevisionSpaces(revision.name))); - row.insertCell().appendChild(document.createTextNode(revision.date)); - row.insertCell().appendChild(document.createTextNode(revision.author)); - row.insertCell().appendChild(document.createTextNode(revision.description)); - row.insertCell().appendChild(revertToRevisionButton); - return row; - }, - - createRevertToRevisionButton: function () { - const button = document.createElement("button"); - button.title = 'Revert data to this revision'; - button.className = 'revert-to-revision-button'; - button.innerHTML = ''; - return button; - }, - - toggleRevisions: function () { - const revisionsPanel = document.getElementById('revisions-expand-container'); - revisionsPanel.style.display = (window.getComputedStyle(revisionsPanel).display === 'none' ? 'block' : 'none'); - }, - - //for better UX insert spaces after each 3rd digit (e.g. '12345' -> '12 345'), in order to do this we are: - // 1) reversing string - // 2) inserting spaces - // 3) reversing the result back - insertRevisionSpaces: function (revisionName) { - return revisionName.split("").reverse().join("").match(/.{1,3}/g).join(' ').split("").reverse().join(""); - }, - - setCookie: function (name, value, daysToExpire = 1) { - let expires = ''; - if (daysToExpire) { - const date = new Date(); - date.setTime(date.getTime() + (daysToExpire * 24 * 60 * 60 * 1000)); - expires = '; expires=' + date.toUTCString(); - } - document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/'; - }, - - getCookie: function (name) { - const nameEQ = name + '='; - const cookiesArray = document.cookie.split(';'); - for (let i = 0; i < cookiesArray.length; i++) { - let cookie = cookiesArray[i]; - while (cookie.charAt(0) === ' ') { - cookie = cookie.substring(1, cookie.length); - } - if (cookie.indexOf(nameEQ) === 0) { - return decodeURIComponent(cookie.substring(nameEQ.length, cookie.length)); - } - } - return null; - }, - - deleteCookie: function (name) { - this.setCookie(name, '', -1); - }, - - selectOptionByValue: function (id, optionValue) { - const selectElement = document.getElementById(id); - if (!selectElement) { - console.error('Select element with the provided ID not found.'); - return; - } - - selectElement.value = optionValue; - } - -}; \ No newline at end of file diff --git a/src/main/resources/webapp/interceptor-admin/js/prism.js b/src/main/resources/webapp/interceptor-admin/js/prism.js deleted file mode 100644 index 6adbc13..0000000 --- a/src/main/resources/webapp/interceptor-admin/js/prism.js +++ /dev/null @@ -1,7 +0,0 @@ -/* PrismJS 1.29.0 -https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ -var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=g.reach);A+=w.value.length,w=w.next){var E=w.value;if(n.length>e.length)return;if(!(E instanceof i)){var P,L=1;if(y){if(!(P=l(b,A,e,m))||P.index>=e.length)break;var S=P.index,O=P.index+P[0].length,j=A;for(j+=w.value.length;S>=j;)j+=(w=w.next).value.length;if(A=j-=w.value.length,w.value instanceof i)continue;for(var C=w;C!==n.tail&&(jg.reach&&(g.reach=W);var z=w.prev;if(_&&(z=u(n,z,_),A+=_.length),c(n,z,L),w=u(n,z,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),L>1){var I={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,I),g&&I.reach>g.reach&&(g.reach=I.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); -Prism.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",(function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))})),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var t={"included-cdata":{pattern://i,inside:s}};t["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp("(<__[^>]*>)(?:))*\\]\\]>|(?!)".replace(/__/g,(function(){return a})),"i"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(Prism.languages.markup.tag,"addAttribute",{value:function(a,e){Prism.languages.markup.tag.inside["special-attr"].push({pattern:RegExp("(^|[\"'\\s])(?:"+a+")\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))","i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[e,"language-"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml; -!function(s){var e=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;s.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:[^;{\\s\"']|\\s+(?!\\s)|"+e.source+")*?(?:;|(?=\\s*\\{))"),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+e.source+"|(?:[^\\\\\r\n()\"']|\\\\[^])*)\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+e.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+e.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:e,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(Prism); -Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/}; -Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp("(^|[^\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\dA-Fa-f]+(?:_[\\dA-Fa-f]+)*n?|\\d+(?:_\\d+)*n|(?:\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\.\\d+(?:_\\d+)*)(?:[Ee][+-]?\\d+(?:_\\d+)*)?)(?![\\w$])"),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp("((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s]|\\b(?:return|yield))\\s*)/(?:(?:\\[(?:[^\\]\\\\\r\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}|(?:\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.)*\\])*\\])*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\s|/\\*(?:[^*]|\\*(?!/))*\\*/)*(?:$|[\r\n,.;:})\\]]|//))"),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:Prism.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),Prism.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.markup.tag.addAttribute("on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)","javascript")),Prism.languages.js=Prism.languages.javascript; diff --git a/src/main/resources/webapp/interceptor-admin/js/settings.js b/src/main/resources/webapp/interceptor-admin/js/settings.js index b218b61..cb39cf4 100644 --- a/src/main/resources/webapp/interceptor-admin/js/settings.js +++ b/src/main/resources/webapp/interceptor-admin/js/settings.js @@ -1,29 +1,34 @@ +const DEFAULT_SETTING_NAME = 'Default'; +SbbCommon.init({ + extension: 'interceptor', + setting: 'hook', + scope: SbbCommon.getValueById('scope'), + initCodeInput: true, + propertiesHighlighting: true +}); + const Hooks = { list: [], selectedHook: undefined }; -InterceptorContext.init({ - initCodeInput: true, - propertiesHighlighting: true -}); function saveSettings() { - InterceptorContext.hideActionAlerts(); + SbbCommon.hideActionAlerts(); - InterceptorContext.callAsync({ - method: 'POST', - url: `/polarion/interceptor/rest/internal/settings/${Hooks.selectedHook.name}`, + SbbCommon.callAsync({ + method: 'PUT', + url: `/polarion/${SbbCommon.extension}/rest/internal/hook-settings/${Hooks.selectedHook.name}/content`, contentType: 'application/json', body: JSON.stringify({ - 'enabled': InterceptorContext.getCheckboxValueById('enable-hook'), - 'properties': InterceptorContext.getValueById('properties-input') + 'enabled': SbbCommon.getCheckboxValueById('enable-hook'), + 'properties': SbbCommon.getValueById('properties-input') }), onOk: () => { - InterceptorContext.showSaveSuccessAlert(); - InterceptorContext.setNewerVersionNotificationVisible(false); + SbbCommon.showSaveSuccessAlert(); + SbbCommon.setNewerVersionNotificationVisible(false); readAndFillRevisions(); }, - onError: () => InterceptorContext.showSaveErrorAlert() + onError: () => SbbCommon.showSaveErrorAlert() }); } @@ -46,11 +51,11 @@ function getInterceptorTypeName(hookType) { } function readSelectedHook() { - InterceptorContext.setLoadingErrorNotificationVisible(false); + SbbCommon.setLoadingErrorNotificationVisible(false); - InterceptorContext.callAsync({ + SbbCommon.callAsync({ method: 'GET', - url: `/polarion/interceptor/rest/internal/settings/${Hooks.selectedHook.name}`, + url: `/polarion/${SbbCommon.extension}/rest/internal/hook-settings/${Hooks.selectedHook.name}/content`, contentType: 'application/json', onOk: (responseText) => { document.getElementById('hook-description-container').innerHTML = @@ -60,16 +65,16 @@ function readSelectedHook() { parseAndSetSettings(responseText, true); readAndFillRevisions(); }, - onError: () => InterceptorContext.setLoadingErrorNotificationVisible(true) + onError: () => SbbCommon.setLoadingErrorNotificationVisible(true) }); } function readHooksList(reload) { - InterceptorContext.setLoadingErrorNotificationVisible(false); + SbbCommon.setLoadingErrorNotificationVisible(false); - InterceptorContext.callAsync({ + SbbCommon.callAsync({ method: 'GET', - url: `/polarion/interceptor/rest/internal/hooks?reload=${reload}`, + url: `/polarion/${SbbCommon.extension}/rest/internal/hooks?reload=${reload}`, contentType: 'application/json', onOk: (responseText) => { const hooks = JSON.parse(responseText); @@ -78,11 +83,11 @@ function readHooksList(reload) { const container = document.getElementById('hooks-choose-container'); let noHooks = Hooks.list.length === 0; - InterceptorContext.setNoHooksNotificationVisible(noHooks); + setNoHooksNotificationVisible(noHooks); let displayStyle = noHooks ? 'none' : 'block'; container.style.display = displayStyle; document.getElementById('hook-settings-container').style.display = displayStyle; - document.getElementById('actions-container').style.display = displayStyle; + document.getElementsByClassName('actions-pane')[0].style.display = displayStyle; if (noHooks) { return; } @@ -117,7 +122,7 @@ function readHooksList(reload) { document.getElementById(Hooks.selectedHook.name).checked = true; readSelectedHook(); }, - onError: () => InterceptorContext.setLoadingErrorNotificationVisible(true) + onError: () => SbbCommon.setLoadingErrorNotificationVisible(true) }); } @@ -129,36 +134,50 @@ function cancelEdit() { function revertToDefault() { if (confirm("Are you sure you want to return the default values?")) { - InterceptorContext.setLoadingErrorNotificationVisible(false); - InterceptorContext.hideActionAlerts(); - - InterceptorContext.callAsync({ - method: 'GET', - url: `/polarion/interceptor/rest/internal/settings/${Hooks.selectedHook.name}/default`, - contentType: 'application/json', - onOk: (responseText) => { + loadDefaultContent() + .then((responseText) => { parseAndSetSettings(responseText); - InterceptorContext.showRevertedToDefaultAlert(); - }, - onError: () => InterceptorContext.setLoadingErrorNotificationVisible(true) - }); + SbbCommon.showRevertedToDefaultAlert(); + }); } } function parseAndSetSettings(text, checkNewerVersion) { const settings = JSON.parse(text); - InterceptorContext.setCheckboxValueById('enable-hook', settings.enabled); - InterceptorContext.setValueById('properties-input', settings.properties); + SbbCommon.setCheckboxValueById('enable-hook', settings.enabled); + SbbCommon.setValueById('properties-input', settings.properties); if (checkNewerVersion && settings.hookVersion !== Hooks.selectedHook.version) { - InterceptorContext.setNewerVersionNotificationVisible(true); + SbbCommon.setNewerVersionNotificationVisible(true); } } function readAndFillRevisions() { - InterceptorContext.readAndFillRevisions({ + SbbCommon.readAndFillRevisions({ setting: Hooks.selectedHook.name, revertToRevisionCallback: (responseText) => parseAndSetSettings(responseText) }); } +function setNoHooksNotificationVisible(visible) { + document.getElementById('no-hooks-registered').style.display = (visible ? 'block' : 'none') +} + +function loadDefaultContent() { + return new Promise((resolve, reject) => { + SbbCommon.setLoadingErrorNotificationVisible(false); + SbbCommon.hideActionAlerts(); + + SbbCommon.callAsync({ + method: 'GET', + url: `/polarion/${SbbCommon.extension}/rest/internal/hook-settings/${Hooks.selectedHook.name}/default-content`, + contentType: 'application/json', + onOk: (responseText) => resolve(responseText), + onError: () => { + SbbCommon.setLoadingErrorNotificationVisible(true); + reject(); + } + }); + }); +} + readHooksList(false); diff --git a/src/main/resources/webapp/interceptor-admin/pages/about.jsp b/src/main/resources/webapp/interceptor-admin/pages/about.jsp index c82ad7b..352d08f 100644 --- a/src/main/resources/webapp/interceptor-admin/pages/about.jsp +++ b/src/main/resources/webapp/interceptor-admin/pages/about.jsp @@ -1,58 +1 @@ -<%@ page import="ch.sbb.polarion.extension.interceptor.rest.model.Version" %> -<%@ page import="ch.sbb.polarion.extension.interceptor.util.ExtensionInfo" %> - - - -<%! Version version = ExtensionInfo.getInstance().getVersion();%> - - - - - - - - -
-

About

- -
-

Version

- - - - - - - - - - - - - - - - - - - - - - - - -
Bundle-Name - <%= version.getBundleName() %> -
Bundle-Vendor - <%= version.getBundleVendor() %> -
Automatic-Module-Name - <%= version.getAutomaticModuleName() %> -
Bundle-Version - <%= version.getBundleVersion() %> -
Bundle-Build-Timestamp - <%= version.getBundleBuildTimestamp() %> -
-
-
- - \ No newline at end of file + \ No newline at end of file diff --git a/src/main/resources/webapp/interceptor-admin/pages/settings.jsp b/src/main/resources/webapp/interceptor-admin/pages/settings.jsp index 961f3fd..4a4dba6 100644 --- a/src/main/resources/webapp/interceptor-admin/pages/settings.jsp +++ b/src/main/resources/webapp/interceptor-admin/pages/settings.jsp @@ -1,24 +1,21 @@ -<%@ page import="ch.sbb.polarion.extension.interceptor.rest.model.Version" %> -<%@ page import="ch.sbb.polarion.extension.interceptor.util.ExtensionInfo" %> -<%! Version version = ExtensionInfo.getInstance().getVersion();%> +<%! String bundleTimestamp = ch.sbb.polarion.extension.generic.util.VersionUtils.getVersion().getBundleBuildTimestampDigitsOnly(); %> Interceptor: Hooks settings - - - - - - - + + + + + + -
+

Interceptor: Hooks settings

@@ -30,25 +27,12 @@
-
- - - - + + + +
@@ -68,44 +52,13 @@ "/>
-
-
- - - - - - - - - - - - -
RevisionDateAuthorCommentActions
-
- -
- - - - -
-
- - -
-
+ + + + + - + + \ No newline at end of file diff --git a/src/test/java/ch/sbb/polarion/extension/interceptor/rest/filter/AuthenticationFilterTest.java b/src/test/java/ch/sbb/polarion/extension/interceptor/rest/filter/AuthenticationFilterTest.java deleted file mode 100644 index b3a3baf..0000000 --- a/src/test/java/ch/sbb/polarion/extension/interceptor/rest/filter/AuthenticationFilterTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.filter; - -import com.polarion.platform.security.AuthenticationFailedException; -import com.polarion.platform.security.ISecurityService; -import com.polarion.platform.security.login.AccessToken; -import com.polarion.platform.security.login.ILogin; -import com.polarion.platform.security.login.IToken; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import javax.security.auth.Subject; -import javax.ws.rs.NotAuthorizedException; -import javax.ws.rs.container.ContainerRequestContext; -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -@ExtendWith(MockitoExtension.class) -class AuthenticationFilterTest { - - @Mock - private ContainerRequestContext requestContext; - @Mock - private ISecurityService securityService; - @Mock - private ILogin login; - @Mock - private ILogin.IBase base; - @Mock - @SuppressWarnings("rawtypes") - private ILogin.IUsingAuthenticator authenticator; - @Mock - private ILogin.IFinal iFinal; - - @Test - void filterRequestWithoutAuthorizationHeader() { - - when(requestContext.getHeaderString("Authorization")).thenReturn(null); - AuthenticationFilter filter = new AuthenticationFilter(securityService); - - assertThatThrownBy(() -> filter.filter(requestContext)) - .isInstanceOf(NotAuthorizedException.class) - .hasMessageContaining("Authorization header must be provided"); - } - - @Test - void filterRequestWithoutBaererInAuthorizationHeader() { - when(requestContext.getHeaderString("Authorization")).thenReturn("wrong token"); - AuthenticationFilter filter = new AuthenticationFilter(securityService); - - assertThatThrownBy(() -> filter.filter(requestContext)) - .isInstanceOf(NotAuthorizedException.class) - .hasMessageContaining("Authorization header must be provided"); - } - - @Test - @SuppressWarnings("unchecked") - void filterRequest() throws IOException, AuthenticationFailedException { - when(requestContext.getHeaderString("Authorization")).thenReturn("Bearer token"); - when(securityService.login()).thenReturn(login); - when(login.from("REST")).thenReturn(base); - when(base.authenticator(any())).thenReturn(authenticator); - when(authenticator.with((IToken) any())).thenReturn(iFinal); - - Subject subject = new Subject(); - when(iFinal.perform()).thenReturn(subject); - - AuthenticationFilter filter = new AuthenticationFilter(securityService); - filter.filter(requestContext); - verify(requestContext, times(1)).setProperty("user_subject", subject); - } - - - @Test - @SuppressWarnings("unchecked") - void filterRequestWithFailedAuthentication() throws IOException, AuthenticationFailedException { - when(requestContext.getHeaderString("Authorization")).thenReturn("Bearer token"); - when(securityService.login()).thenReturn(login); - when(login.from("REST")).thenReturn(base); - when(base.authenticator(any())).thenReturn(authenticator); - when(authenticator.with((IToken) any())).thenReturn(iFinal); - - when(iFinal.perform()).thenThrow(new AuthenticationFailedException("")); - - AuthenticationFilter filter = new AuthenticationFilter(securityService); - - filter.filter(requestContext); - verify(requestContext, times(1)).abortWith(any()); - } -} diff --git a/src/test/java/ch/sbb/polarion/extension/interceptor/rest/filter/LogoutFilterTest.java b/src/test/java/ch/sbb/polarion/extension/interceptor/rest/filter/LogoutFilterTest.java deleted file mode 100644 index bbddec1..0000000 --- a/src/test/java/ch/sbb/polarion/extension/interceptor/rest/filter/LogoutFilterTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.rest.filter; - -import com.polarion.platform.security.ISecurityService; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import javax.security.auth.Subject; -import javax.ws.rs.container.ContainerRequestContext; -import java.io.IOException; - -import static org.mockito.Mockito.*; - -@ExtendWith(MockitoExtension.class) -class LogoutFilterTest { - - @Mock - private ContainerRequestContext requestContext; - @Mock - private ISecurityService securityService; - - @Test - void successfulLogoutCallIfSubjectExists() throws IOException { - Subject subject = new Subject(); - when(requestContext.getProperty(AuthenticationFilter.USER_SUBJECT)).thenReturn(subject); - LogoutFilter filter = new LogoutFilter(securityService); - filter.filter(requestContext, null); - verify(securityService, times(1)).logout(subject); - } - - @Test - void doNotCallLogoutIfThereIsNoSubject() throws IOException { - when(requestContext.getProperty(AuthenticationFilter.USER_SUBJECT)).thenReturn(null); - LogoutFilter filter = new LogoutFilter(securityService); - filter.filter(requestContext, null); - verify(securityService, times(0)).logout(any()); - } -} diff --git a/src/test/java/ch/sbb/polarion/extension/interceptor/util/RequestContextUtilTest.java b/src/test/java/ch/sbb/polarion/extension/interceptor/util/RequestContextUtilTest.java deleted file mode 100644 index 5a7f098..0000000 --- a/src/test/java/ch/sbb/polarion/extension/interceptor/util/RequestContextUtilTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.util; - -import org.junit.jupiter.api.Test; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import javax.security.auth.Subject; -import javax.servlet.http.HttpServletRequest; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class RequestContextUtilTest { - - @Test - public void shouldReturnUserSubject() { - // Arrange - ServletRequestAttributes requestAttributes = mock(ServletRequestAttributes.class); - HttpServletRequest request = mock(HttpServletRequest.class); - Subject subject = mock(Subject.class); - when(requestAttributes.getRequest()).thenReturn(request); - when(request.getAttribute("user_subject")).thenReturn(subject); - RequestContextHolder.setRequestAttributes(requestAttributes); - - // Act - Subject resultSubject = RequestContextUtil.getUserSubject(); - - // Assert - assertThat(resultSubject).isEqualTo(subject); - } - - @Test - public void shouldThrowIllegalStateExceptionByNullAttributes() { - assertThatThrownBy(RequestContextUtil::getUserSubject) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("request attributes"); - } -} \ No newline at end of file diff --git a/src/test/java/ch/sbb/polarion/extension/interceptor/util/ScopeUtilsTest.java b/src/test/java/ch/sbb/polarion/extension/interceptor/util/ScopeUtilsTest.java deleted file mode 100644 index 47813e0..0000000 --- a/src/test/java/ch/sbb/polarion/extension/interceptor/util/ScopeUtilsTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package ch.sbb.polarion.extension.interceptor.util; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class ScopeUtilsTest { - - private static Stream testValuesForGetProjectByScope() { - return Stream.of( - Arguments.of("", null), - Arguments.of("project/elibrary/", "elibrary"), - Arguments.of("projects/test/", null), - Arguments.of("invalid", null) - ); - } - - @ParameterizedTest - @MethodSource("testValuesForGetProjectByScope") - void getProjectByScope(String scope, String expected) { - String projectFromScope = ScopeUtils.getProjectFromScope(scope); - assertEquals(expected, projectFromScope); - } -} \ No newline at end of file