merge with brach issue-42

This commit is contained in:
Sebastian Sdorra
2012-04-04 19:24:05 +02:00
18 changed files with 564 additions and 68 deletions

View File

@@ -33,6 +33,10 @@
package sonia.scm; package sonia.scm;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.config.ScmConfiguration;
/** /**
* Configuration object for a SCM-Manager * Configuration object for a SCM-Manager
* client (WebInterface, RestClient, ...). * client (WebInterface, RestClient, ...).
@@ -48,6 +52,20 @@ public class ScmClientConfig
*/ */
public ScmClientConfig() {} public ScmClientConfig() {}
/**
* Constructs {@link ScmClientConfig} object
*
*
* @param configuration SCM-Manager main configuration
* @since 1.14
*/
public ScmClientConfig(ScmConfiguration configuration)
{
this.dateFormat = configuration.getDateFormat();
this.disableGroupingGrid = configuration.isDisableGroupingGrid();
this.enableRepositoryArchive = configuration.isEnableRepositoryArchive();
}
/** /**
* Constructs {@link ScmClientConfig} object * Constructs {@link ScmClientConfig} object
* *
@@ -100,6 +118,18 @@ public class ScmClientConfig
return disableGroupingGrid; return disableGroupingGrid;
} }
/**
* Returns true if the repository archive is disabled.
*
*
* @return true if the repository archive is disabled
* @since 1.14
*/
public boolean isEnableRepositoryArchive()
{
return enableRepositoryArchive;
}
//~--- set methods ---------------------------------------------------------- //~--- set methods ----------------------------------------------------------
/** /**
@@ -127,11 +157,26 @@ public class ScmClientConfig
this.disableGroupingGrid = disableGroupingGrid; this.disableGroupingGrid = disableGroupingGrid;
} }
/**
* Enable or disable the repository archive. Default is disabled.
*
*
* @param enableRepositoryArchive true to disable the repository archive
* @since 1.14
*/
public void setEnableRepositoryArchive(boolean enableRepositoryArchive)
{
this.enableRepositoryArchive = enableRepositoryArchive;
}
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/** Field description */ /** Field description */
private String dateFormat; private String dateFormat;
/** Field description */
private boolean enableRepositoryArchive = true;
/** Field description */ /** Field description */
private boolean disableGroupingGrid = true; private boolean disableGroupingGrid = true;
} }

View File

@@ -165,6 +165,7 @@ public class ScmConfiguration
this.forceBaseUrl = other.forceBaseUrl; this.forceBaseUrl = other.forceBaseUrl;
this.baseUrl = other.baseUrl; this.baseUrl = other.baseUrl;
this.disableGroupingGrid = other.disableGroupingGrid; this.disableGroupingGrid = other.disableGroupingGrid;
this.enableRepositoryArchive = other.enableRepositoryArchive;
// deprecated fields // deprecated fields
this.sslPort = other.sslPort; this.sslPort = other.sslPort;
@@ -381,6 +382,18 @@ public class ScmConfiguration
return enableProxy; return enableProxy;
} }
/**
* Returns true if the repository archive is enabled.
*
*
* @return true if the repository archive is enabled
* @since 1.14
*/
public boolean isEnableRepositoryArchive()
{
return enableRepositoryArchive;
}
/** /**
* Returns true if ssl is enabled. * Returns true if ssl is enabled.
* *
@@ -499,6 +512,18 @@ public class ScmConfiguration
this.enableProxy = enableProxy; this.enableProxy = enableProxy;
} }
/**
* Enable or disable the repository archive. Default is disabled.
*
*
* @param enableRepositoryArchive true to disable the repository archive
* @since 1.14
*/
public void setEnableRepositoryArchive(boolean enableRepositoryArchive)
{
this.enableRepositoryArchive = enableRepositoryArchive;
}
/** /**
* Method description * Method description
* *
@@ -682,6 +707,9 @@ public class ScmConfiguration
private Set<ConfigChangedListener> listeners = private Set<ConfigChangedListener> listeners =
new HashSet<ConfigChangedListener>(); new HashSet<ConfigChangedListener>();
/** Field description */
private boolean enableRepositoryArchive = false;
/** Field description */ /** Field description */
private boolean disableGroupingGrid = false; private boolean disableGroupingGrid = false;

View File

@@ -37,6 +37,10 @@ package sonia.scm.repository;
import com.google.inject.Provider; import com.google.inject.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.security.ScmSecurityException; import sonia.scm.security.ScmSecurityException;
import sonia.scm.user.User; import sonia.scm.user.User;
import sonia.scm.util.AssertUtil; import sonia.scm.util.AssertUtil;
@@ -54,6 +58,14 @@ import java.util.List;
public class PermissionUtil public class PermissionUtil
{ {
/**
* the logger for PermissionUtil
*/
private static final Logger logger =
LoggerFactory.getLogger(PermissionUtil.class);
//~--- methods --------------------------------------------------------------
/** /**
* Method description * Method description
* *
@@ -151,6 +163,40 @@ public class PermissionUtil
return result; return result;
} }
/**
* Returns true if the repository is writable.
*
*
* @param configuration SCM-Manager main configuration
* @param repository repository to check
* @param securityContext current user security context
*
* @return true if the repository is writable
* @since 1.14
*/
public static boolean isWritable(ScmConfiguration configuration,
Repository repository,
WebSecurityContext securityContext)
{
boolean permitted = false;
if (configuration.isEnableRepositoryArchive() && repository.isArchived())
{
if (logger.isWarnEnabled())
{
logger.warn("{} is archived and is not writeable",
repository.getName());
}
}
else
{
permitted = PermissionUtil.hasPermission(repository, securityContext,
PermissionType.WRITE);
}
return permitted;
}
/** /**
* Method description * Method description
* *

View File

@@ -345,6 +345,18 @@ public class Repository extends BasicPropertiesAware implements ModelObject
return url; return url;
} }
/**
* Returns true if the repository is archived.
*
*
* @return true if the repository is archived
* @since 1.14
*/
public boolean isArchived()
{
return archived;
}
/** /**
* Returns true if the {@link Repository} is public readable. * Returns true if the {@link Repository} is public readable.
* *
@@ -377,6 +389,18 @@ public class Repository extends BasicPropertiesAware implements ModelObject
//~--- set methods ---------------------------------------------------------- //~--- set methods ----------------------------------------------------------
/**
* Archive or un archive this repository.
*
*
* @param archived true to enable archive
* @since 1.14
*/
public void setArchived(boolean archived)
{
this.archived = archived;
}
/** /**
* Sets the contact of the {@link Repository}. The contact address should be * Sets the contact of the {@link Repository}. The contact address should be
* a email address of a person who is responsible for the {@link Repository}. * a email address of a person who is responsible for the {@link Repository}.
@@ -516,6 +540,9 @@ public class Repository extends BasicPropertiesAware implements ModelObject
@XmlElement(name = "public") @XmlElement(name = "public")
private boolean publicReadable = false; private boolean publicReadable = false;
/** Field description */
private boolean archived = false;
/** Field description */ /** Field description */
private String type; private String type;

View File

@@ -41,6 +41,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.SCMContext; import sonia.scm.SCMContext;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.PermissionType; import sonia.scm.repository.PermissionType;
import sonia.scm.repository.PermissionUtil; import sonia.scm.repository.PermissionUtil;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
@@ -76,10 +77,14 @@ public abstract class PermissionFilter extends HttpFilter
* Constructs ... * Constructs ...
* *
* *
*
* @param configuration
* @param securityContextProvider * @param securityContextProvider
*/ */
public PermissionFilter(Provider<WebSecurityContext> securityContextProvider) public PermissionFilter(ScmConfiguration configuration,
Provider<WebSecurityContext> securityContextProvider)
{ {
this.configuration = configuration;
this.securityContextProvider = securityContextProvider; this.securityContextProvider = securityContextProvider;
} }
@@ -139,10 +144,7 @@ public abstract class PermissionFilter extends HttpFilter
{ {
boolean writeRequest = isWriteRequest(request); boolean writeRequest = isWriteRequest(request);
if (PermissionUtil.hasPermission(repository, securityContext, if (hasPermission(repository, securityContext, writeRequest))
writeRequest
? PermissionType.WRITE
: PermissionType.READ))
{ {
chain.doFilter(request, response); chain.doFilter(request, response);
} }
@@ -213,8 +215,43 @@ public abstract class PermissionFilter extends HttpFilter
} }
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param repository
* @param securityContext
* @param writeRequest
*
* @return
*/
private boolean hasPermission(Repository repository,
WebSecurityContext securityContext,
boolean writeRequest)
{
boolean permitted = false;
if (writeRequest)
{
permitted = PermissionUtil.isWritable(configuration, repository,
securityContext);
}
else
{
permitted = PermissionUtil.hasPermission(repository, securityContext,
PermissionType.READ);
}
return permitted;
}
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/** Field description */ /** Field description */
protected Provider<WebSecurityContext> securityContextProvider; protected Provider<WebSecurityContext> securityContextProvider;
/** Field description */
private ScmConfiguration configuration;
} }

View File

@@ -44,6 +44,7 @@ import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import sonia.scm.config.ScmConfiguration;
/** /**
* *
@@ -61,10 +62,11 @@ public abstract class ProviderPermissionFilter extends PermissionFilter
* @param repositoryProvider * @param repositoryProvider
*/ */
public ProviderPermissionFilter( public ProviderPermissionFilter(
ScmConfiguration configuration,
Provider<WebSecurityContext> securityContextProvider, Provider<WebSecurityContext> securityContextProvider,
RepositoryProvider repositoryProvider) RepositoryProvider repositoryProvider)
{ {
super(securityContextProvider); super(configuration, securityContextProvider);
this.repositoryProvider = repositoryProvider; this.repositoryProvider = repositoryProvider;
} }

View File

@@ -37,6 +37,7 @@ package sonia.scm.web.filter;
import com.google.inject.Provider; import com.google.inject.Provider;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryManager;
import sonia.scm.web.security.WebSecurityContext; import sonia.scm.web.security.WebSecurityContext;
@@ -65,14 +66,17 @@ public abstract class RegexPermissionFilter extends PermissionFilter
* Constructs ... * Constructs ...
* *
* *
*
* @param configuration
* @param securityContextProvider * @param securityContextProvider
* @param repositoryManager * @param repositoryManager
*/ */
public RegexPermissionFilter( public RegexPermissionFilter(
ScmConfiguration configuration,
Provider<WebSecurityContext> securityContextProvider, Provider<WebSecurityContext> securityContextProvider,
RepositoryManager repositoryManager) RepositoryManager repositoryManager)
{ {
super(securityContextProvider); super(configuration, securityContextProvider);
this.repositoryManager = repositoryManager; this.repositoryManager = repositoryManager;
} }

View File

@@ -35,8 +35,10 @@ package sonia.scm.repository;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.security.ScmSecurityException; import sonia.scm.security.ScmSecurityException;
import sonia.scm.user.User; import sonia.scm.user.User;
import sonia.scm.web.security.WebSecurityContext; import sonia.scm.web.security.WebSecurityContext;
@@ -65,17 +67,7 @@ public class PermissionUtilTest
*/ */
public PermissionUtilTest() public PermissionUtilTest()
{ {
repository = new Repository();
admams.getUser().setAdmin(true); admams.getUser().setAdmin(true);
Permission[] permissions = new Permission[] {
new Permission("dent", PermissionType.READ),
new Permission("perfect",
PermissionType.WRITE),
new Permission("marvin",
PermissionType.OWNER) };
repository.setPermissions(Arrays.asList(permissions));
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
@@ -108,6 +100,25 @@ public class PermissionUtilTest
PermissionUtil.assertPermission(repository, admams, PermissionType.OWNER); PermissionUtil.assertPermission(repository, admams, PermissionType.OWNER);
} }
/**
* Method description
*
*/
@Before
public void before()
{
repository = new Repository();
Permission[] permissions = new Permission[] {
new Permission("dent", PermissionType.READ),
new Permission("perfect",
PermissionType.WRITE),
new Permission("marvin",
PermissionType.OWNER) };
repository.setPermissions(Arrays.asList(permissions));
}
/** /**
* Method description * Method description
* *
@@ -161,6 +172,31 @@ public class PermissionUtilTest
PermissionType.OWNER)); PermissionType.OWNER));
} }
/**
* Method description
*
*/
@Test
public void testIsWritable()
{
ScmConfiguration configuration = new ScmConfiguration();
configuration.setEnableRepositoryArchive(true);
assertTrue(PermissionUtil.isWritable(configuration, repository, perfect));
repository.setArchived(true);
assertFalse(PermissionUtil.isWritable(configuration, repository, perfect));
assertFalse(PermissionUtil.isWritable(configuration, repository, admams));
configuration.setEnableRepositoryArchive(false);
assertTrue(PermissionUtil.isWritable(configuration, repository, perfect));
assertTrue(PermissionUtil.isWritable(configuration, repository, admams));
assertFalse(PermissionUtil.isWritable(configuration, repository, dent));
configuration.setEnableRepositoryArchive(true);
repository.setArchived(false);
assertTrue(PermissionUtil.isWritable(configuration, repository, perfect));
assertTrue(PermissionUtil.isWritable(configuration, repository, admams));
assertFalse(PermissionUtil.isWritable(configuration, repository, dent));
}
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/** /**

View File

@@ -46,6 +46,7 @@ import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import sonia.scm.config.ScmConfiguration;
/** /**
* *
@@ -79,10 +80,11 @@ public class GitPermissionFilter extends ProviderPermissionFilter
*/ */
@Inject @Inject
public GitPermissionFilter( public GitPermissionFilter(
ScmConfiguration configuration,
Provider<WebSecurityContext> securityContextProvider, Provider<WebSecurityContext> securityContextProvider,
RepositoryProvider repositoryProvider) RepositoryProvider repositoryProvider)
{ {
super(securityContextProvider, repositoryProvider); super(configuration, securityContextProvider, repositoryProvider);
} }
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------

View File

@@ -46,6 +46,7 @@ import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import sonia.scm.config.ScmConfiguration;
/** /**
* *
@@ -64,10 +65,11 @@ public class HgPermissionFilter extends ProviderPermissionFilter
*/ */
@Inject @Inject
public HgPermissionFilter( public HgPermissionFilter(
ScmConfiguration configuration,
Provider<WebSecurityContext> securityContextProvider, Provider<WebSecurityContext> securityContextProvider,
RepositoryProvider repositoryProvider) RepositoryProvider repositoryProvider)
{ {
super(securityContextProvider, repositoryProvider); super(configuration, securityContextProvider, repositoryProvider);
} }
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------

View File

@@ -39,6 +39,7 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryProvider;
import sonia.scm.web.filter.ProviderPermissionFilter; import sonia.scm.web.filter.ProviderPermissionFilter;
import sonia.scm.web.security.WebSecurityContext; import sonia.scm.web.security.WebSecurityContext;
@@ -72,15 +73,18 @@ public class SvnPermissionFilter extends ProviderPermissionFilter
* *
* *
* *
*
* @param configuration
* @param securityContextProvider * @param securityContextProvider
* @param repository * @param repository
*/ */
@Inject @Inject
public SvnPermissionFilter( public SvnPermissionFilter(
ScmConfiguration configuration,
Provider<WebSecurityContext> securityContextProvider, Provider<WebSecurityContext> securityContextProvider,
RepositoryProvider repository) RepositoryProvider repository)
{ {
super(securityContextProvider, repository); super(configuration, securityContextProvider, repository);
} }
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------

View File

@@ -251,8 +251,7 @@ public class AuthenticationResource
return new ScmState(contextProvider, securityContext, return new ScmState(contextProvider, securityContext,
repositoryManger.getConfiguredTypes(), repositoryManger.getConfiguredTypes(),
userManager.getDefaultType(), userManager.getDefaultType(),
new ScmClientConfig(configuration.getDateFormat(), new ScmClientConfig(configuration));
configuration.isDisableGroupingGrid()));
} }
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------

View File

@@ -46,6 +46,25 @@ import sonia.scm.ConfigurationException;
import sonia.scm.HandlerEvent; import sonia.scm.HandlerEvent;
import sonia.scm.SCMContextProvider; import sonia.scm.SCMContextProvider;
import sonia.scm.Type; import sonia.scm.Type;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.AbstractRepositoryManager;
import sonia.scm.repository.BlameViewer;
import sonia.scm.repository.ChangesetViewer;
import sonia.scm.repository.DiffViewer;
import sonia.scm.repository.PermissionType;
import sonia.scm.repository.PermissionUtil;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryAllreadyExistExeption;
import sonia.scm.repository.RepositoryBrowser;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RepositoryHandler;
import sonia.scm.repository.RepositoryHandlerNotFoundException;
import sonia.scm.repository.RepositoryHook;
import sonia.scm.repository.RepositoryHookEvent;
import sonia.scm.repository.RepositoryListener;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.security.ScmSecurityException; import sonia.scm.security.ScmSecurityException;
import sonia.scm.util.AssertUtil; import sonia.scm.util.AssertUtil;
import sonia.scm.util.CollectionAppender; import sonia.scm.util.CollectionAppender;
@@ -92,6 +111,8 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
* *
* *
* *
*
* @param configuration
* @param contextProvider * @param contextProvider
* @param securityContextProvider * @param securityContextProvider
* @param repositoryDAO * @param repositoryDAO
@@ -101,12 +122,13 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
*/ */
@Inject @Inject
public DefaultRepositoryManager( public DefaultRepositoryManager(
SCMContextProvider contextProvider, ScmConfiguration configuration, SCMContextProvider contextProvider,
Provider<WebSecurityContext> securityContextProvider, Provider<WebSecurityContext> securityContextProvider,
RepositoryDAO repositoryDAO, Set<RepositoryHandler> handlerSet, RepositoryDAO repositoryDAO, Set<RepositoryHandler> handlerSet,
Provider<Set<RepositoryListener>> repositoryListenersProvider, Provider<Set<RepositoryListener>> repositoryListenersProvider,
Provider<Set<RepositoryHook>> repositoryHooksProvider) Provider<Set<RepositoryHook>> repositoryHooksProvider)
{ {
this.configuration = configuration;
this.securityContextProvider = securityContextProvider; this.securityContextProvider = securityContextProvider;
this.repositoryDAO = repositoryDAO; this.repositoryDAO = repositoryDAO;
this.repositoryListenersProvider = repositoryListenersProvider; this.repositoryListenersProvider = repositoryListenersProvider;
@@ -213,6 +235,12 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
assertIsOwner(repository); assertIsOwner(repository);
if (configuration.isEnableRepositoryArchive() &&!repository.isArchived())
{
throw new RepositoryException(
"Repository could not deleted, because it is not archived.");
}
if (repositoryDAO.contains(repository)) if (repositoryDAO.contains(repository))
{ {
getHandler(repository).delete(repository); getHandler(repository).delete(repository);
@@ -932,6 +960,9 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/** Field description */
private ScmConfiguration configuration;
/** Field description */ /** Field description */
private Map<String, RepositoryHandler> handlerMap; private Map<String, RepositoryHandler> handlerMap;

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 B

View File

@@ -57,6 +57,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{
baseUrlText: 'Base Url', baseUrlText: 'Base Url',
forceBaseUrlText: 'Force Base Url', forceBaseUrlText: 'Force Base Url',
disableGroupingGridText: 'Disable repository Groups', disableGroupingGridText: 'Disable repository Groups',
enableRepositoryArchiveText: 'Enable repository archive',
// help // help
@@ -81,7 +82,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{
baseUrlHelpText: 'The url of the application (with context path) i.e. http://localhost:8080/scm', baseUrlHelpText: 'The url of the application (with context path) i.e. http://localhost:8080/scm',
forceBaseUrlHelpText: 'Redirects to the base url if the request comes from a other url', forceBaseUrlHelpText: 'Redirects to the base url if the request comes from a other url',
disableGroupingGridHelpText: 'Disable repository Groups. A complete page reload is required after a change of this value.', disableGroupingGridHelpText: 'Disable repository Groups. A complete page reload is required after a change of this value.',
enableRepositoryArchiveHelpText: 'Enable repository archives. A complete page reload is required after a change of this value.',
initComponent: function(){ initComponent: function(){
@@ -108,6 +109,12 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{
name: 'disableGroupingGrid', name: 'disableGroupingGrid',
inputValue: 'true', inputValue: 'true',
helpText: this.disableGroupingGridHelpText helpText: this.disableGroupingGridHelpText
},{
xtype: 'checkbox',
fieldLabel: this.enableRepositoryArchiveText,
name: 'enableRepositoryArchive',
inputValue: 'true',
helpText: this.enableRepositoryArchiveHelpText
},{ },{
xtype: 'textfield', xtype: 'textfield',
fieldLabel: this.dateFormatText, fieldLabel: this.dateFormatText,

View File

@@ -36,11 +36,23 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
colDescriptionText: 'Description', colDescriptionText: 'Description',
colCreationDateText: 'Creation date', colCreationDateText: 'Creation date',
colUrlText: 'Url', colUrlText: 'Url',
colArchiveText: 'Archive',
emptyText: 'No repository is configured', emptyText: 'No repository is configured',
formTitleText: 'Repository Form', formTitleText: 'Repository Form',
unknownType: 'Unknown', unknownType: 'Unknown',
archiveIcon: 'resources/images/archive.png',
filterRequest: null,
/**
* @deprecated use filterRequest
*/
searchValue: null, searchValue: null,
/**
* @deprecated use filterRequest
*/
typeFilter: null, typeFilter: null,
// TODO find better text // TODO find better text
@@ -82,6 +94,8 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
name:'permissions' name:'permissions'
},{ },{
name: 'properties' name: 'properties'
},{
name: 'archived'
}] }]
}), }),
sortInfo: { sortInfo: {
@@ -139,6 +153,14 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
dataIndex: 'url', dataIndex: 'url',
renderer: this.renderUrl, renderer: this.renderUrl,
width: 250 width: 250
},{
id: 'Archive',
header: this.colArchiveText,
dataIndex: 'archived',
width: 40,
hidden: ! state.clientConfig.enableRepositoryArchive,
renderer: this.renderArchive,
scope: this
},{ },{
id: 'group', id: 'group',
dataIndex: 'group', dataIndex: 'group',
@@ -159,6 +181,13 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
console.debug( msg ); console.debug( msg );
} }
if ( state.clientConfig.enableRepositoryArchive ){
if ( !this.filterRequest ){
this.filterRequest = {};
}
this.filterRequest.archived = false;
}
var config = { var config = {
autoExpandColumn: 'description', autoExpandColumn: 'description',
store: repositoryStore, store: repositoryStore,
@@ -180,6 +209,8 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
}) })
}; };
this.addEvents('repositorySelected');
Ext.apply(this, Ext.apply(this.initialConfig, config)); Ext.apply(this, Ext.apply(this.initialConfig, config));
Sonia.repository.Grid.superclass.initComponent.apply(this, arguments); Sonia.repository.Grid.superclass.initComponent.apply(this, arguments);
@@ -188,6 +219,10 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
} }
}, },
renderArchive: function(v){
return v ? '<img src=' + this.archiveIcon + ' alt=' + v + '>' : '';
},
convertToGroup: function(v, data){ convertToGroup: function(v, data){
var name = data.name; var name = data.name;
var i = name.lastIndexOf('/'); var i = name.lastIndexOf('/');
@@ -220,6 +255,9 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
this.filterStore(); this.filterStore();
} }
this.ready = true; this.ready = true;
if (this.filterRequest){
this.filterByRequest();
}
}, },
onFallBelowMinHeight: function(height, minHeight){ onFallBelowMinHeight: function(height, minHeight){
@@ -233,23 +271,63 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
this.ownerCt.doLayout(); this.ownerCt.doLayout();
}, },
getFilterRequest: function(){
if ( ! this.filterRequest ){
this.filterRequest = {};
}
return this.filterRequest;
},
/**
* @deprecated use filterByRequest
*/
search: function(value){ search: function(value){
this.searchValue = value; this.searchValue = value;
this.filterStore(); this.filterStore();
}, },
/**
* @deprecated use filterByRequest
*/
filter: function(type){ filter: function(type){
this.typeFilter = type; this.typeFilter = type;
this.filterStore(); this.filterStore();
}, },
clearStoreFilter: function(){ clearStoreFilter: function(){
this.filterRequest = null;
this.searchValue = null; this.searchValue = null;
this.typeFilter = null; this.typeFilter = null;
this.getStore().clearFilter(); this.getStore().clearFilter();
}, },
filterByRequest: function(){
if (debug){
console.debug('filter repository store by request:');
console.debug(this.filterRequest);
}
var store = this.getStore();
if ( ! this.filterRequest ){
store.clearFilter();
} else {
var query = this.filterRequest.query;
if ( query ){
query = query.toLowerCase();
}
var archived = ! state.clientConfig.enableRepositoryArchive || this.filterRequest.archived;
store.filterBy(function(rec){
var desc = rec.get('description');
return (! query || rec.get('name').toLowerCase().indexOf(query) >= 0 ||
(desc && desc.toLowerCase().indexOf(query) >= 0)) &&
(! this.filterRequest.type || rec.get('type') == this.filterRequest.type) &&
(archived || ! rec.get('archived'));
}, this);
}
},
/**
* @deprecated use filterByRequest
*/
filterStore: function(){ filterStore: function(){
var store = this.getStore(); var store = this.getStore();
if ( ! this.searchValue && ! this.typeFilter ){ if ( ! this.searchValue && ! this.typeFilter ){
@@ -268,6 +346,9 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
} }
}, },
/**
* TODO move to panel
*/
selectItem: function(item){ selectItem: function(item){
if ( debug ){ if ( debug ){
console.debug( item.name + ' selected' ); console.debug( item.name + ' selected' );
@@ -277,13 +358,16 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
this.parentPanel.updateHistory(item); this.parentPanel.updateHistory(item);
} }
var owner = Sonia.repository.isOwner(item);
this.fireEvent('repositorySelected', item, owner);
var infoPanel = main.getInfoPanel(item.type); var infoPanel = main.getInfoPanel(item.type);
infoPanel.item = item; infoPanel.item = item;
var panels = [infoPanel]; var panels = [infoPanel];
if ( Sonia.repository.isOwner(item) ){ if ( owner ){
Ext.getCmp('repoRmButton').setDisabled(false);
panels.push({ panels.push({
item: item, item: item,
xtype: 'repositorySettingsForm', xtype: 'repositorySettingsForm',

View File

@@ -34,11 +34,21 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, {
titleText: 'Repository Form', titleText: 'Repository Form',
emptyText: 'Add or select an Repository', emptyText: 'Add or select an Repository',
// TODO i18n
archiveText: 'Archive',
unarchiveText: 'Unarchive',
archiveTitleText: 'Archive Repository',
archiveMsgText: 'Archive Repository "{0}"?',
errorArchiveMsgText: 'Repository archival failed',
removeTitleText: 'Remove Repository', removeTitleText: 'Remove Repository',
removeMsgText: 'Remove Repository "{0}"?', removeMsgText: 'Remove Repository "{0}"?',
errorTitleText: 'Error', errorTitleText: 'Error',
errorMsgText: 'Repository deletion failed', errorMsgText: 'Repository deletion failed',
archiveIcon: 'resources/images/archive.png',
repositoryGrid: null, repositoryGrid: null,
initComponent: function(){ initComponent: function(){
@@ -70,6 +80,20 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, {
handler: this.showAddForm handler: this.showAddForm
}); });
} }
// repository archive
if (state.clientConfig.enableRepositoryArchive){
toolbar.push({
xtype: 'tbbutton',
id: 'repoArchiveButton',
disabled: true,
text: this.archiveText,
icon: this.archiveIcon,
scope: this,
handler: this.toggleArchive
});
}
toolbar.push({ toolbar.push({
xtype: 'tbbutton', xtype: 'tbbutton',
id: 'repoRmButton', id: 'repoRmButton',
@@ -127,13 +151,37 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, {
} }
}); });
// repository archive
if (state.clientConfig.enableRepositoryArchive){
toolbar.push(' ',{
id: 'displayArchived',
xtype: 'checkbox',
listeners: {
check: {
fn: this.filterByArchived,
scope: this
}
}
},{
xtype: 'label',
text: 'Archive',
cls: 'ytb-text'
})
}
var config = { var config = {
tbar: toolbar, tbar: toolbar,
items: [{ items: [{
id: 'repositoryGrid', id: 'repositoryGrid',
xtype: 'repositoryGrid', xtype: 'repositoryGrid',
region: 'center', region: 'center',
parentPanel: this parentPanel: this,
listeners: {
repositorySelected: {
fn: this.onRepositorySelection,
scope: this
}
}
},{ },{
id: 'repositoryEditPanel', id: 'repositoryEditPanel',
xtype: 'tabpanel', xtype: 'tabpanel',
@@ -170,57 +218,144 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, {
Sonia.History.add(token); Sonia.History.add(token);
}, },
filterByArchived: function(checkbox, checked){
var grid = this.getGrid();
grid.getFilterRequest().archived = checked;
grid.filterByRequest();
},
filterByType: function(combo, rec){ filterByType: function(combo, rec){
this.getGrid().filter(rec.get('name')); var grid = this.getGrid();
grid.getFilterRequest().type = rec.get('name');
grid.filterByRequest();
}, },
search: function(field){ search: function(field){
this.getGrid().search(field.getValue()); var grid = this.getGrid();
grid.getFilterRequest().query = field.getValue();
grid.filterByRequest();
}, },
removeRepository: function(){ getSelectedRepository: function(){
var repository = null;
var grid = this.getGrid(); var grid = this.getGrid();
var selected = grid.getSelectionModel().getSelected(); var selected = grid.getSelectionModel().getSelected();
if ( selected ){ if ( selected ){
var item = selected.data; repository = selected.data;
var url = restUrl + 'repositories/' + item.id + '.json'; } else if (debug) {
console.debug( 'no repository selected' );
}
return repository;
},
executeRemoteCall: function(title, message, method, url, data, failureCallback){
Ext.MessageBox.show({ Ext.MessageBox.show({
title: this.removeTitleText, title: title,
msg: String.format(this.removeMsgText, item.name), msg: message,
buttons: Ext.MessageBox.OKCANCEL, buttons: Ext.MessageBox.OKCANCEL,
icon: Ext.MessageBox.QUESTION, icon: Ext.MessageBox.QUESTION,
fn: function(result){ fn: function(result){
if ( result == 'ok' ){ if ( result == 'ok' ){
if ( debug ){ if ( debug ){
console.debug( 'remove repository ' + item.name ); console.debug('call repository repository action '+ method + ' on ' + url );
}
var el = this.el;
var tid = setTimeout( function(){el.mask('Loading ...');}, 100);
if (data && data.group){
delete data.group;
} }
Ext.Ajax.request({ Ext.Ajax.request({
url: url, url: url,
method: 'DELETE', method: method,
jsonData: data,
scope: this, scope: this,
success: function(){ success: function(){
this.reload(); this.reload();
this.resetPanel(); this.resetPanel();
clearTimeout(tid);
el.unmask();
}, },
failure: function(result){ failure: function(result){
main.handleRestFailure( clearTimeout(tid);
result, el.unmask();
failureCallback.call(this, result);
}
});
} // canceled
},
scope: this
});
},
toggleArchive: function(){
var item = this.getSelectedRepository();
if ( item ){
console.debug(item);
item.archived = ! item.archived;
if (debug){
console.debug('toggle repository ' + item.name + ' archive to ' + item.archived);
}
var url = restUrl + 'repositories/' + item.id + '.json';
this.executeRemoteCall(this.archiveTitleText,
String.format(this.archiveMsgText, item.name),
'PUT', url, item, function(result){
main.handleFailure(
result.status,
this.errorTitleText,
this.errorArchiveMsgText
);
}
);
}
},
removeRepository: function(){
var item = this.getSelectedRepository();
if ( item ){
if ( debug ){
console.debug( 'remove repository ' + item.name );
}
var url = restUrl + 'repositories/' + item.id + '.json';
this.executeRemoteCall(this.archiveTitleText,
String.format(this.archiveMsgText, item.name),
'DELETE', url, null, function(result){
main.handleFailure(
result.status,
this.errorTitleText, this.errorTitleText,
this.errorMsgText this.errorMsgText
); );
} }
}); );
} }
}, },
scope: this
});
} else if ( debug ){ onRepositorySelection: function(item, owner){
console.debug( 'no repository selected' ); if ( owner ){
if (state.clientConfig.enableRepositoryArchive){
var archiveBt = Ext.getCmp('repoArchiveButton');
if ( item.archived ){
archiveBt.setText(this.unarchiveText);
Ext.getCmp('repoRmButton').setDisabled(false);
} else {
archiveBt.setText(this.archiveText);
Ext.getCmp('repoRmButton').setDisabled(true);
}
archiveBt.setDisabled(false);
} else {
Ext.getCmp('repoRmButton').setDisabled(false);
}
} else {
Ext.getCmp('repoRmButton').setDisabled(false);
if (state.clientConfig.enableRepositoryArchive){
Ext.getCmp('repoArchiveButton').setDisabled(false);
}
} }
}, },
@@ -271,6 +406,10 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, {
reload: function(){ reload: function(){
this.getGrid().reload(); this.getGrid().reload();
var repo = this.getSelectedRepository();
if ( repo ){
this.onRepositorySelection(repo, Sonia.repository.isOwner(repo));
}
} }
}); });

View File

@@ -41,6 +41,7 @@ import org.junit.Test;
import sonia.scm.Type; import sonia.scm.Type;
import sonia.scm.repository.xml.XmlRepositoryDAO; import sonia.scm.repository.xml.XmlRepositoryDAO;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.store.JAXBStoreFactory; import sonia.scm.store.JAXBStoreFactory;
import sonia.scm.store.StoreFactory; import sonia.scm.store.StoreFactory;
import sonia.scm.util.MockUtil; import sonia.scm.util.MockUtil;
@@ -134,7 +135,9 @@ public class DefaultRepositoryManagerTest extends RepositoryManagerTestBase
XmlRepositoryDAO repositoryDAO = new XmlRepositoryDAO(factory); XmlRepositoryDAO repositoryDAO = new XmlRepositoryDAO(factory);
return new DefaultRepositoryManager(contextProvider, ScmConfiguration configuration = new ScmConfiguration();
return new DefaultRepositoryManager(configuration, contextProvider,
MockUtil.getAdminSecurityContextProvider(), repositoryDAO, MockUtil.getAdminSecurityContextProvider(), repositoryDAO,
handlerSet, listenerProvider, hookProvider); handlerSet, listenerProvider, hookProvider);
} }