mirror of
				https://github.com/scm-manager/scm-manager.git
				synced 2025-10-31 10:35:56 +01:00 
			
		
		
		
	Disable repository types (#1908)
Disable repository types via global config for Git, Mercurial and Subversion. It is only possible to disable a type, if no repositories of this type exist. Also prevent repository creation if no type is allowed at all to catch nasty errors. Co-authored-by: Konstantin Schaper <konstantin.schaper@cloudogu.com>
This commit is contained in:
		| @@ -37,6 +37,7 @@ import sonia.scm.repository.Compatibility; | ||||
| public class SvnConfigDto extends HalRepresentation implements UpdateSvnConfigDto { | ||||
|  | ||||
|   private boolean disabled; | ||||
|   private boolean allowDisable; | ||||
|  | ||||
|   private boolean enabledGZip; | ||||
|   private Compatibility compatibility; | ||||
|   | ||||
| @@ -29,6 +29,7 @@ import org.mapstruct.AfterMapping; | ||||
| import org.mapstruct.Mapper; | ||||
| import org.mapstruct.MappingTarget; | ||||
| import sonia.scm.config.ConfigurationPermissions; | ||||
| import sonia.scm.repository.RepositoryManager; | ||||
| import sonia.scm.repository.SvnConfig; | ||||
|  | ||||
| import javax.inject.Inject; | ||||
| @@ -43,6 +44,8 @@ public abstract class SvnConfigToSvnConfigDtoMapper extends BaseMapper<SvnConfig | ||||
|  | ||||
|   @Inject | ||||
|   private ScmPathInfoStore scmPathInfoStore; | ||||
|   @Inject | ||||
|   private RepositoryManager repositoryManager; | ||||
|  | ||||
|   @AfterMapping | ||||
|   void appendLinks(SvnConfig config, @MappingTarget SvnConfigDto target) { | ||||
| @@ -51,6 +54,7 @@ public abstract class SvnConfigToSvnConfigDtoMapper extends BaseMapper<SvnConfig | ||||
|       linksBuilder.single(link("update", update())); | ||||
|     } | ||||
|     target.add(linksBuilder.build()); | ||||
|     target.setAllowDisable(repositoryManager.getAll().stream().noneMatch(r -> r.getType().equals("svn"))); | ||||
|   } | ||||
|  | ||||
|   private String self() { | ||||
|   | ||||
| @@ -21,87 +21,65 @@ | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| import React from "react"; | ||||
| import { withTranslation, WithTranslation } from "react-i18next"; | ||||
| import React, { FC, useEffect, useState } from "react"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import { Links } from "@scm-manager/ui-types"; | ||||
| import { Checkbox, Select } from "@scm-manager/ui-components"; | ||||
|  | ||||
| type Configuration = { | ||||
|   disabled: boolean; | ||||
|   allowDisable: boolean; | ||||
|   compatibility: string; | ||||
|   enabledGZip: boolean; | ||||
|   _links: Links; | ||||
| }; | ||||
|  | ||||
| type Props = WithTranslation & { | ||||
| type Props = { | ||||
|   initialConfiguration: Configuration; | ||||
|   readOnly: boolean; | ||||
|  | ||||
|   onConfigurationChange: (p1: Configuration, p2: boolean) => void; | ||||
| }; | ||||
|  | ||||
| type State = Configuration; | ||||
| const SvnConfigurationForm: FC<Props> = ({ initialConfiguration, readOnly, onConfigurationChange }) => { | ||||
|   const [t] = useTranslation("plugins"); | ||||
|   const [configuration, setConfiguration] = useState(initialConfiguration); | ||||
|  | ||||
| class SvnConfigurationForm extends React.Component<Props, State> { | ||||
|   constructor(props: Props) { | ||||
|     super(props); | ||||
|     this.state = { | ||||
|       ...props.initialConfiguration, | ||||
|     }; | ||||
|   } | ||||
|   useEffect(() => setConfiguration(initialConfiguration), [initialConfiguration]); | ||||
|   useEffect(() => onConfigurationChange(configuration, true), [configuration]); | ||||
|  | ||||
|   handleChange = (value: any, name?: string) => { | ||||
|     if (!name) { | ||||
|       throw new Error("required name not set"); | ||||
|     } | ||||
|     this.setState( | ||||
|       // @ts-ignore | ||||
|       { | ||||
|         [name]: value, | ||||
|       }, | ||||
|       () => this.props.onConfigurationChange(this.state, true) | ||||
|     ); | ||||
|   }; | ||||
|   const options = ["NONE", "PRE14", "PRE15", "PRE16", "PRE17", "WITH17"].map((option: string) => ({ | ||||
|     value: option, | ||||
|     label: t("scm-svn-plugin.config.compatibility-values." + option.toLowerCase()) | ||||
|   })); | ||||
|  | ||||
|   compatibilityOptions = (values: string[]) => { | ||||
|     const options = []; | ||||
|     for (const value of values) { | ||||
|       options.push(this.compatibilityOption(value)); | ||||
|     } | ||||
|     return options; | ||||
|   }; | ||||
|   return ( | ||||
|     <> | ||||
|       <Select | ||||
|         name="compatibility" | ||||
|         label={t("scm-svn-plugin.config.compatibility")} | ||||
|         helpText={t("scm-svn-plugin.config.compatibilityHelpText")} | ||||
|         value={configuration.compatibility} | ||||
|         options={options} | ||||
|         onChange={option => setConfiguration({ ...configuration, compatibility: option })} | ||||
|       /> | ||||
|       <Checkbox | ||||
|         name="enabledGZip" | ||||
|         label={t("scm-svn-plugin.config.enabledGZip")} | ||||
|         helpText={t("scm-svn-plugin.config.enabledGZipHelpText")} | ||||
|         checked={configuration.enabledGZip} | ||||
|         onChange={value => setConfiguration({ ...configuration, enabledGZip: value })} | ||||
|         disabled={readOnly} | ||||
|       /> | ||||
|       <Checkbox | ||||
|         name="disabled" | ||||
|         label={t("scm-svn-plugin.config.disabled")} | ||||
|         helpText={t("scm-svn-plugin.config.disabledHelpText")} | ||||
|         checked={configuration.disabled} | ||||
|         onChange={value => setConfiguration({ ...configuration, disabled: value })} | ||||
|         disabled={readOnly || !configuration.allowDisable} | ||||
|       /> | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
|   compatibilityOption = (value: string) => { | ||||
|     return { | ||||
|       value, | ||||
|       label: this.props.t("scm-svn-plugin.config.compatibility-values." + value.toLowerCase()), | ||||
|     }; | ||||
|   }; | ||||
|  | ||||
|   render() { | ||||
|     const { readOnly, t } = this.props; | ||||
|     const compatibilityOptions = this.compatibilityOptions(["NONE", "PRE14", "PRE15", "PRE16", "PRE17", "WITH17"]); | ||||
|  | ||||
|     return ( | ||||
|       <> | ||||
|         <Select | ||||
|           name="compatibility" | ||||
|           label={t("scm-svn-plugin.config.compatibility")} | ||||
|           helpText={t("scm-svn-plugin.config.compatibilityHelpText")} | ||||
|           value={this.state.compatibility} | ||||
|           options={compatibilityOptions} | ||||
|           onChange={this.handleChange} | ||||
|         /> | ||||
|         <Checkbox | ||||
|           name="enabledGZip" | ||||
|           label={t("scm-svn-plugin.config.enabledGZip")} | ||||
|           helpText={t("scm-svn-plugin.config.enabledGZipHelpText")} | ||||
|           checked={this.state.enabledGZip} | ||||
|           onChange={this.handleChange} | ||||
|           disabled={readOnly} | ||||
|         /> | ||||
|       </> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| export default withTranslation("plugins")(SvnConfigurationForm); | ||||
| export default SvnConfigurationForm; | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
|       "enabledGZip": "GZip Compression aktivieren", | ||||
|       "enabledGZipHelpText": "Aktiviert GZip Kompression für SVN Responses", | ||||
|       "disabled": "Deaktiviert", | ||||
|       "disabledHelpText": "Aktiviert oder deaktiviert das SVN Plugin", | ||||
|       "disabledHelpText": "Aktiviert oder deaktiviert das SVN Plugin. Nur erlaubt, wenn keine Subversion Repositories existieren.", | ||||
|       "required": "Dieser Konfigurationswert wird benötigt" | ||||
|     } | ||||
|   }, | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
|       "enabledGZip": "Enable GZip Compression", | ||||
|       "enabledGZipHelpText": "Enable GZip compression for SVN responses.", | ||||
|       "disabled": "Disabled", | ||||
|       "disabledHelpText": "Enable or disable the SVN plugin", | ||||
|       "disabledHelpText": "Enable or disable the SVN plugin. Only allowed if no Subversion repositories exist.", | ||||
|       "required": "This configuration value is required" | ||||
|     } | ||||
|   }, | ||||
|   | ||||
| @@ -38,6 +38,7 @@ import org.mockito.Answers; | ||||
| import org.mockito.InjectMocks; | ||||
| import org.mockito.Mock; | ||||
| import org.mockito.junit.MockitoJUnitRunner; | ||||
| import sonia.scm.repository.RepositoryManager; | ||||
| import sonia.scm.repository.SvnConfig; | ||||
| import sonia.scm.repository.SvnRepositoryHandler; | ||||
| import sonia.scm.web.RestDispatcher; | ||||
| @@ -68,6 +69,9 @@ public class SvnConfigResourceTest { | ||||
|  | ||||
|   private final URI baseUri = URI.create("/"); | ||||
|  | ||||
|   @Mock | ||||
|   private RepositoryManager repositoryManager; | ||||
|  | ||||
|   @InjectMocks | ||||
|   private SvnConfigDtoToSvnConfigMapperImpl dtoToConfigMapper; | ||||
|  | ||||
|   | ||||
| @@ -37,9 +37,12 @@ import org.mockito.InjectMocks; | ||||
| import org.mockito.Mock; | ||||
| import org.mockito.junit.MockitoJUnitRunner; | ||||
| import sonia.scm.repository.Compatibility; | ||||
| import sonia.scm.repository.RepositoryManager; | ||||
| import sonia.scm.repository.RepositoryTestData; | ||||
| import sonia.scm.repository.SvnConfig; | ||||
|  | ||||
| import java.net.URI; | ||||
| import java.util.Collections; | ||||
|  | ||||
| import static org.junit.Assert.assertEquals; | ||||
| import static org.junit.Assert.assertFalse; | ||||
| @@ -50,11 +53,14 @@ import static org.mockito.Mockito.when; | ||||
| @RunWith(MockitoJUnitRunner.class) | ||||
| public class SvnConfigToSvnConfigDtoMapperTest { | ||||
|  | ||||
|   private URI baseUri = URI.create("http://example.com/base/"); | ||||
|   private final URI baseUri = URI.create("http://example.com/base/"); | ||||
|  | ||||
|   @Mock(answer = Answers.RETURNS_DEEP_STUBS) | ||||
|   private ScmPathInfoStore scmPathInfoStore; | ||||
|  | ||||
|   @Mock | ||||
|   private RepositoryManager manager; | ||||
|  | ||||
|   @InjectMocks | ||||
|   private SvnConfigToSvnConfigDtoMapperImpl mapper; | ||||
|  | ||||
| @@ -80,10 +86,12 @@ public class SvnConfigToSvnConfigDtoMapperTest { | ||||
|   public void shouldMapFields() { | ||||
|     SvnConfig config = createConfiguration(); | ||||
|  | ||||
|     when(manager.getAll()).thenReturn(Collections.singleton(RepositoryTestData.create42Puzzle("svn"))); | ||||
|     when(subject.isPermitted("configuration:write:svn")).thenReturn(true); | ||||
|     SvnConfigDto dto = mapper.map(config); | ||||
|  | ||||
|     assertTrue(dto.isDisabled()); | ||||
|     assertFalse(dto.isAllowDisable()); | ||||
|  | ||||
|     assertEquals(Compatibility.PRE15, dto.getCompatibility()); | ||||
|     assertTrue(dto.isEnabledGZip()); | ||||
| @@ -92,6 +100,17 @@ public class SvnConfigToSvnConfigDtoMapperTest { | ||||
|     assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("update").get().getHref()); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void shouldAllowDisableIfNoSubversionRepositoriesExist() { | ||||
|     SvnConfig config = createConfiguration(); | ||||
|  | ||||
|     when(manager.getAll()).thenReturn(Collections.singleton(RepositoryTestData.create42Puzzle("git"))); | ||||
|     when(subject.isPermitted("configuration:write:svn")).thenReturn(true); | ||||
|     SvnConfigDto dto = mapper.map(config); | ||||
|  | ||||
|     assertTrue(dto.isAllowDisable()); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void shouldMapFieldsWithoutUpdate() { | ||||
|     SvnConfig config = createConfiguration(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user