mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-07-06 10:57:55 +02:00
merge
This commit is contained in:
19
scm-core/src/main/java/sonia/scm/DisplayManager.java
Normal file
19
scm-core/src/main/java/sonia/scm/DisplayManager.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package sonia.scm;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface DisplayManager<T extends ReducedModelObject> {
|
||||
|
||||
int DEFAULT_LIMIT = 5;
|
||||
|
||||
/**
|
||||
* Returns a {@link Collection} of filtered objects
|
||||
*
|
||||
* @param filter the searched string
|
||||
* @return filtered object from the store
|
||||
*/
|
||||
Collection<T> autocomplete(String filter);
|
||||
|
||||
Optional<T> get(String id);
|
||||
}
|
||||
@@ -47,8 +47,6 @@ public interface Manager<T extends ModelObject>
|
||||
extends HandlerBase<T>, LastModifiedAware
|
||||
{
|
||||
|
||||
int DEFAULT_LIMIT = 5;
|
||||
|
||||
|
||||
/**
|
||||
* Reloads a object from store and overwrites all changes.
|
||||
|
||||
@@ -39,8 +39,10 @@ package sonia.scm;
|
||||
* @author Sebastian Sdorra
|
||||
*
|
||||
* @param <T> type of objects to transform
|
||||
* @param <R> result type of the transformation
|
||||
*/
|
||||
public interface TransformFilter<T>
|
||||
@FunctionalInterface
|
||||
public interface TransformFilter<T, R>
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -52,5 +54,5 @@ public interface TransformFilter<T>
|
||||
*
|
||||
* @return tranformed object
|
||||
*/
|
||||
public T accept(T item);
|
||||
R accept(T item);
|
||||
}
|
||||
|
||||
26
scm-core/src/main/java/sonia/scm/group/DisplayGroup.java
Normal file
26
scm-core/src/main/java/sonia/scm/group/DisplayGroup.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package sonia.scm.group;
|
||||
|
||||
import sonia.scm.ReducedModelObject;
|
||||
|
||||
public class DisplayGroup implements ReducedModelObject {
|
||||
|
||||
private final String id;
|
||||
private final String displayName;
|
||||
|
||||
public static DisplayGroup from(Group group) {
|
||||
return new DisplayGroup(group.getId(), group.getDescription());
|
||||
}
|
||||
|
||||
private DisplayGroup(String id, String displayName) {
|
||||
this.id = id;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package sonia.scm.group;
|
||||
|
||||
import sonia.scm.DisplayManager;
|
||||
|
||||
public interface GroupDisplayManager extends DisplayManager<DisplayGroup> {
|
||||
}
|
||||
@@ -61,14 +61,4 @@ public interface GroupManager
|
||||
* @return all groups assigned to the given member
|
||||
*/
|
||||
public Collection<Group> getGroupsForMember(String member);
|
||||
|
||||
|
||||
/**
|
||||
* Returns a {@link java.util.Collection} of filtered objects
|
||||
*
|
||||
* @param filter the searched string
|
||||
* @return filtered object from the store
|
||||
*/
|
||||
Collection<Group> autocomplete(String filter);
|
||||
|
||||
}
|
||||
|
||||
@@ -109,11 +109,6 @@ public class GroupManagerDecorator
|
||||
return decorated.getGroupsForMember(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Group> autocomplete(String filter) {
|
||||
return decorated.autocomplete(filter);
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
|
||||
@@ -159,17 +159,17 @@ public final class SearchUtil
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static <T> Collection<T> search(SearchRequest searchRequest,
|
||||
Collection<T> collection, TransformFilter<T> filter)
|
||||
public static <T, R> Collection<R> search(SearchRequest searchRequest,
|
||||
Collection<T> collection, TransformFilter<T, R> filter)
|
||||
{
|
||||
List<T> items = new ArrayList<T>();
|
||||
List<R> items = new ArrayList<>();
|
||||
int index = 0;
|
||||
int counter = 0;
|
||||
Iterator<T> it = collection.iterator();
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
T item = filter.accept(it.next());
|
||||
R item = filter.accept(it.next());
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,7 @@ package sonia.scm.template;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The {@link TemplateEngine} searches for {@link Template}s and prepares the
|
||||
@@ -59,11 +60,42 @@ public interface TemplateEngine
|
||||
*
|
||||
* @param templatePath path of the template
|
||||
*
|
||||
* @return template associated withe the given path or null
|
||||
* @return template associated with the given path or null
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public Template getTemplate(String templatePath) throws IOException;
|
||||
Template getTemplate(String templatePath) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the template associated with the given path and the given language
|
||||
* or the default version. To do this, the template path will be extended
|
||||
* with the language. For example `my-template.type` will be extended to
|
||||
* `my-template_en.type`, if the language is {@link Locale#ENGLISH}. If no
|
||||
* dedicated template can be found, the template without the extension will
|
||||
* be used.
|
||||
* <p>The template engine
|
||||
* will search the template in the folder of the web application and in
|
||||
* the classpath. This method will return null,
|
||||
* if no template could be found for the given path.
|
||||
*
|
||||
*
|
||||
* @param templatePath path of the template
|
||||
* @param locale the preferred language
|
||||
*
|
||||
* @return template associated with the given path, extended by the language
|
||||
* if found, or null
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
default Template getTemplate(String templatePath, Locale locale) throws IOException {
|
||||
String templatePathWithLanguage = extendWithLanguage(templatePath, locale);
|
||||
Template templateForLanguage = getTemplate(templatePathWithLanguage);
|
||||
if (templateForLanguage == null) {
|
||||
return getTemplate(templatePath);
|
||||
} else {
|
||||
return templateForLanguage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a template of the given reader. Note some template implementations
|
||||
@@ -79,7 +111,7 @@ public interface TemplateEngine
|
||||
*
|
||||
* @since 1.22
|
||||
*/
|
||||
public Template getTemplate(String templateIdentifier, Reader reader)
|
||||
Template getTemplate(String templateIdentifier, Reader reader)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
@@ -87,5 +119,12 @@ public interface TemplateEngine
|
||||
*
|
||||
* @return type of template engine
|
||||
*/
|
||||
public TemplateType getType();
|
||||
TemplateType getType();
|
||||
|
||||
static String extendWithLanguage(String templatePath, Locale locale) {
|
||||
int lastIndexOfDot = templatePath.lastIndexOf('.');
|
||||
String filename = templatePath.substring(0, lastIndexOfDot);
|
||||
String extension = templatePath.substring(lastIndexOfDot);
|
||||
return filename + "_" + locale.getLanguage() + extension;
|
||||
}
|
||||
}
|
||||
|
||||
32
scm-core/src/main/java/sonia/scm/user/DisplayUser.java
Normal file
32
scm-core/src/main/java/sonia/scm/user/DisplayUser.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package sonia.scm.user;
|
||||
|
||||
import sonia.scm.ReducedModelObject;
|
||||
|
||||
public class DisplayUser implements ReducedModelObject {
|
||||
|
||||
private final String id;
|
||||
private final String displayName;
|
||||
private final String mail;
|
||||
|
||||
public static DisplayUser from(User user) {
|
||||
return new DisplayUser(user.getId(), user.getDisplayName(), user.getMail());
|
||||
}
|
||||
|
||||
private DisplayUser(String id, String displayName, String mail) {
|
||||
this.id = id;
|
||||
this.displayName = displayName;
|
||||
this.mail = mail;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getMail() {
|
||||
return mail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package sonia.scm.user;
|
||||
|
||||
import sonia.scm.DisplayManager;
|
||||
|
||||
public interface UserDisplayManager extends DisplayManager<DisplayUser> {
|
||||
}
|
||||
@@ -75,14 +75,6 @@ public interface UserManager
|
||||
return getDefaultType().equals(user.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link java.util.Collection} of filtered objects
|
||||
*
|
||||
* @param filter the searched string
|
||||
* @return filtered object from the store
|
||||
*/
|
||||
Collection<User> autocomplete(String filter);
|
||||
|
||||
/**
|
||||
* Changes the password of the logged in user.
|
||||
* @param oldPassword The current encrypted password of the user.
|
||||
|
||||
@@ -121,11 +121,6 @@ public class UserManagerDecorator extends ManagerDecorator<User>
|
||||
return decorated.getDefaultType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<User> autocomplete(String filter) {
|
||||
return decorated.autocomplete(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changePasswordForLoggedInUser(String oldPassword, String newPassword) {
|
||||
decorated.changePasswordForLoggedInUser(oldPassword, newPassword);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { AsyncCreatable } from "react-select";
|
||||
import { AsyncCreatable, Async } from "react-select";
|
||||
import type { AutocompleteObject, SelectValue } from "@scm-manager/ui-types";
|
||||
import LabelWithHelpIcon from "./forms/LabelWithHelpIcon";
|
||||
|
||||
@@ -13,7 +13,8 @@ type Props = {
|
||||
value?: SelectValue,
|
||||
placeholder: string,
|
||||
loadingMessage: string,
|
||||
noOptionsMessage: string
|
||||
noOptionsMessage: string,
|
||||
creatable?: boolean
|
||||
};
|
||||
|
||||
|
||||
@@ -42,27 +43,40 @@ class Autocomplete extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { label, helpText, value, placeholder, loadingMessage, noOptionsMessage, loadSuggestions } = this.props;
|
||||
const { label, helpText, value, placeholder, loadingMessage, noOptionsMessage, loadSuggestions, creatable } = this.props;
|
||||
return (
|
||||
<div className="field">
|
||||
<LabelWithHelpIcon label={label} helpText={helpText} />
|
||||
<div className="control">
|
||||
<AsyncCreatable
|
||||
cacheOptions
|
||||
loadOptions={loadSuggestions}
|
||||
onChange={this.handleInputChange}
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
loadingMessage={() => loadingMessage}
|
||||
noOptionsMessage={() => noOptionsMessage}
|
||||
isValidNewOption={this.isValidNewOption}
|
||||
onCreateOption={value => {
|
||||
this.handleInputChange({
|
||||
label: value,
|
||||
value: { id: value, displayName: value }
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{creatable?
|
||||
<AsyncCreatable
|
||||
cacheOptions
|
||||
loadOptions={loadSuggestions}
|
||||
onChange={this.handleInputChange}
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
loadingMessage={() => loadingMessage}
|
||||
noOptionsMessage={() => noOptionsMessage}
|
||||
isValidNewOption={this.isValidNewOption}
|
||||
onCreateOption={value => {
|
||||
this.handleInputChange({
|
||||
label: value,
|
||||
value: { id: value, displayName: value }
|
||||
});
|
||||
}}
|
||||
/>
|
||||
:
|
||||
<Async
|
||||
cacheOptions
|
||||
loadOptions={loadSuggestions}
|
||||
onChange={this.handleInputChange}
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
loadingMessage={() => loadingMessage}
|
||||
noOptionsMessage={() => noOptionsMessage}
|
||||
/>
|
||||
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import classNames from "classnames";
|
||||
|
||||
type Props = {
|
||||
options: string[],
|
||||
optionValues?: string[],
|
||||
optionSelected: string => void,
|
||||
preselectedOption?: string,
|
||||
className: any,
|
||||
@@ -13,7 +14,7 @@ type Props = {
|
||||
|
||||
class DropDown extends React.Component<Props> {
|
||||
render() {
|
||||
const { options, preselectedOption, className, disabled } = this.props;
|
||||
const { options, optionValues, preselectedOption, className, disabled } = this.props;
|
||||
return (
|
||||
<div className={classNames(className, "select")}>
|
||||
<select
|
||||
@@ -22,9 +23,9 @@ class DropDown extends React.Component<Props> {
|
||||
disabled={disabled}
|
||||
>
|
||||
<option key="" />
|
||||
{options.map(option => {
|
||||
{options.map((option, index) => {
|
||||
return (
|
||||
<option key={option} value={option}>
|
||||
<option key={option} value={optionValues && optionValues[index] ? optionValues[index] : option}>
|
||||
{option}
|
||||
</option>
|
||||
);
|
||||
|
||||
@@ -19,15 +19,6 @@ class BaseUrlSettings extends React.Component<Props> {
|
||||
<div>
|
||||
<Subtitle subtitle={t("base-url-settings.name")} />
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<Checkbox
|
||||
checked={forceBaseUrl}
|
||||
label={t("base-url-settings.force-base-url")}
|
||||
onChange={this.handleForceBaseUrlChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.forceBaseUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("base-url-settings.base-url")}
|
||||
@@ -37,6 +28,15 @@ class BaseUrlSettings extends React.Component<Props> {
|
||||
helpText={t("help.baseUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<Checkbox
|
||||
checked={forceBaseUrl}
|
||||
label={t("base-url-settings.force-base-url")}
|
||||
onChange={this.handleForceBaseUrlChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.forceBaseUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package sonia.scm;
|
||||
|
||||
import sonia.scm.search.SearchRequest;
|
||||
import sonia.scm.search.SearchUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static sonia.scm.group.DisplayGroup.from;
|
||||
|
||||
public abstract class GenericDisplayManager<D, T extends ReducedModelObject> implements DisplayManager<T> {
|
||||
|
||||
private final GenericDAO<D> dao;
|
||||
private final Function<D, T> transform;
|
||||
|
||||
protected GenericDisplayManager(GenericDAO<D> dao, Function<D, T> transform) {
|
||||
this.dao = dao;
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> autocomplete(String filter) {
|
||||
checkPermission();
|
||||
SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT);
|
||||
return SearchUtil.search(
|
||||
searchRequest,
|
||||
dao.getAll(),
|
||||
object -> matches(searchRequest, object)? transform.apply(object): null
|
||||
);
|
||||
}
|
||||
|
||||
protected abstract void checkPermission();
|
||||
|
||||
protected abstract boolean matches(SearchRequest searchRequest, D object);
|
||||
|
||||
@Override
|
||||
public Optional<T> get(String id) {
|
||||
return ofNullable(dao.get(id)).map(transform);
|
||||
}
|
||||
}
|
||||
@@ -46,8 +46,10 @@ import sonia.scm.cache.CacheManager;
|
||||
import sonia.scm.cache.GuavaCacheManager;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.group.DefaultGroupDisplayManager;
|
||||
import sonia.scm.group.DefaultGroupManager;
|
||||
import sonia.scm.group.GroupDAO;
|
||||
import sonia.scm.group.GroupDisplayManager;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.group.GroupManagerProvider;
|
||||
import sonia.scm.group.xml.XmlGroupDAO;
|
||||
@@ -102,8 +104,10 @@ import sonia.scm.template.MustacheTemplateEngine;
|
||||
import sonia.scm.template.TemplateEngine;
|
||||
import sonia.scm.template.TemplateEngineFactory;
|
||||
import sonia.scm.template.TemplateServlet;
|
||||
import sonia.scm.user.DefaultUserDisplayManager;
|
||||
import sonia.scm.user.DefaultUserManager;
|
||||
import sonia.scm.user.UserDAO;
|
||||
import sonia.scm.user.UserDisplayManager;
|
||||
import sonia.scm.user.UserManager;
|
||||
import sonia.scm.user.UserManagerProvider;
|
||||
import sonia.scm.user.xml.XmlUserDAO;
|
||||
@@ -268,8 +272,11 @@ public class ScmServletModule extends ServletModule
|
||||
RepositoryManagerProvider.class);
|
||||
bindDecorated(UserManager.class, DefaultUserManager.class,
|
||||
UserManagerProvider.class);
|
||||
bind(UserDisplayManager.class, DefaultUserDisplayManager.class);
|
||||
bindDecorated(GroupManager.class, DefaultGroupManager.class,
|
||||
GroupManagerProvider.class);
|
||||
bind(GroupDisplayManager.class, DefaultGroupDisplayManager.class);
|
||||
|
||||
bind(CGIExecutorFactory.class, DefaultCGIExecutorFactory.class);
|
||||
|
||||
// bind sslcontext provider
|
||||
|
||||
@@ -4,8 +4,8 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import sonia.scm.ReducedModelObject;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.user.UserManager;
|
||||
import sonia.scm.group.GroupDisplayManager;
|
||||
import sonia.scm.user.UserDisplayManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -30,14 +30,14 @@ public class AutoCompleteResource {
|
||||
|
||||
private ReducedObjectModelToDtoMapper mapper;
|
||||
|
||||
private UserManager userManager;
|
||||
private GroupManager groupManager;
|
||||
private UserDisplayManager userDisplayManager;
|
||||
private GroupDisplayManager groupDisplayManager;
|
||||
|
||||
@Inject
|
||||
public AutoCompleteResource(ReducedObjectModelToDtoMapper mapper, UserManager userManager, GroupManager groupManager) {
|
||||
public AutoCompleteResource(ReducedObjectModelToDtoMapper mapper, UserDisplayManager userDisplayManager, GroupDisplayManager groupDisplayManager) {
|
||||
this.mapper = mapper;
|
||||
this.userManager = userManager;
|
||||
this.groupManager = groupManager;
|
||||
this.userDisplayManager = userDisplayManager;
|
||||
this.groupDisplayManager = groupDisplayManager;
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -51,7 +51,7 @@ public class AutoCompleteResource {
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public List<ReducedObjectModelDto> searchUser(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) {
|
||||
return map(userManager.autocomplete(filter));
|
||||
return map(userDisplayManager.autocomplete(filter));
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -65,7 +65,7 @@ public class AutoCompleteResource {
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public List<ReducedObjectModelDto> searchGroup(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) {
|
||||
return map(groupManager.autocomplete(filter));
|
||||
return map(groupDisplayManager.autocomplete(filter));
|
||||
}
|
||||
|
||||
private <T extends ReducedModelObject> List<ReducedObjectModelDto> map(Collection<T> autocomplete) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import org.apache.shiro.authc.credential.PasswordService;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserManager;
|
||||
import sonia.scm.user.UserPermissions;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -2,6 +2,8 @@ package sonia.scm.boot;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.shiro.authc.credential.PasswordService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.security.PermissionAssigner;
|
||||
import sonia.scm.security.PermissionDescriptor;
|
||||
@@ -18,6 +20,8 @@ import java.util.Collections;
|
||||
@Extension
|
||||
public class SetupContextListener implements ServletContextListener {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SetupContextListener.class);
|
||||
|
||||
private final AdministrationContext administrationContext;
|
||||
|
||||
@Inject
|
||||
@@ -27,7 +31,11 @@ public class SetupContextListener implements ServletContextListener {
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
administrationContext.runAsAdmin(SetupAction.class);
|
||||
if (Boolean.getBoolean("sonia.scm.skipAdminCreation")) {
|
||||
LOG.info("found skipAdminCreation flag; skipping creation of scmadmin");
|
||||
} else {
|
||||
administrationContext.runAsAdmin(SetupAction.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package sonia.scm.group;
|
||||
|
||||
import sonia.scm.GenericDisplayManager;
|
||||
import sonia.scm.search.SearchRequest;
|
||||
import sonia.scm.search.SearchUtil;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class DefaultGroupDisplayManager extends GenericDisplayManager<Group, DisplayGroup> implements GroupDisplayManager {
|
||||
|
||||
@Inject
|
||||
public DefaultGroupDisplayManager(GroupDAO groupDAO) {
|
||||
super(groupDAO, DisplayGroup::from);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkPermission() {
|
||||
GroupPermissions.autocomplete().check();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matches(SearchRequest searchRequest, Group group) {
|
||||
return SearchUtil.matchesOne(searchRequest, group.getName(), group.getDescription());
|
||||
}
|
||||
}
|
||||
@@ -195,7 +195,7 @@ public class DefaultGroupManager extends AbstractGroupManager
|
||||
|
||||
final PermissionActionCheck<Group> check = GroupPermissions.read();
|
||||
return SearchUtil.search(searchRequest, groupDAO.getAll(),
|
||||
new TransformFilter<Group>()
|
||||
new TransformFilter<Group, Group>()
|
||||
{
|
||||
@Override
|
||||
public Group accept(Group group)
|
||||
@@ -241,13 +241,6 @@ public class DefaultGroupManager extends AbstractGroupManager
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Group> autocomplete(String filter) {
|
||||
GroupPermissions.autocomplete().check();
|
||||
SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT);
|
||||
return SearchUtil.search(searchRequest, groupDAO.getAll(), group -> matches(searchRequest,group)?group:null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package sonia.scm.user;
|
||||
|
||||
import sonia.scm.GenericDisplayManager;
|
||||
import sonia.scm.search.SearchRequest;
|
||||
import sonia.scm.search.SearchUtil;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class DefaultUserDisplayManager extends GenericDisplayManager<User, DisplayUser> implements UserDisplayManager {
|
||||
|
||||
@Inject
|
||||
public DefaultUserDisplayManager(UserDAO userDAO) {
|
||||
super(userDAO, DisplayUser::from);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkPermission() {
|
||||
UserPermissions.autocomplete().check();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matches(SearchRequest searchRequest, User user) {
|
||||
return SearchUtil.matchesOne(searchRequest, user.getName(), user.getDisplayName(), user.getMail());
|
||||
}
|
||||
}
|
||||
@@ -212,13 +212,6 @@ public class DefaultUserManager extends AbstractUserManager
|
||||
fresh.copyProperties(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<User> autocomplete(String filter) {
|
||||
UserPermissions.autocomplete().check();
|
||||
SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT);
|
||||
return SearchUtil.search(searchRequest, userDAO.getAll(), user -> matches(searchRequest,user)?user:null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
@@ -236,7 +229,7 @@ public class DefaultUserManager extends AbstractUserManager
|
||||
}
|
||||
|
||||
final PermissionActionCheck<User> check = UserPermissions.read();
|
||||
return SearchUtil.search(searchRequest, userDAO.getAll(), new TransformFilter<User>() {
|
||||
return SearchUtil.search(searchRequest, userDAO.getAll(), new TransformFilter<User, User>() {
|
||||
@Override
|
||||
public User accept(User user)
|
||||
{
|
||||
@@ -415,35 +408,6 @@ public class DefaultUserManager extends AbstractUserManager
|
||||
this.modify(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param unmarshaller
|
||||
* @param path
|
||||
*/
|
||||
private void createDefaultAccount(Unmarshaller unmarshaller, String path)
|
||||
{
|
||||
InputStream input = DefaultUserManager.class.getResourceAsStream(path);
|
||||
|
||||
try
|
||||
{
|
||||
User user = (User) unmarshaller.unmarshal(input);
|
||||
|
||||
user.setType(userDAO.getType());
|
||||
user.setCreationDate(System.currentTimeMillis());
|
||||
userDAO.add(user);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.error("could not create account", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close(input);
|
||||
}
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
private final UserDAO userDAO;
|
||||
|
||||
@@ -14,16 +14,14 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.Manager;
|
||||
import sonia.scm.group.DefaultGroupManager;
|
||||
import sonia.scm.DisplayManager;
|
||||
import sonia.scm.group.DefaultGroupDisplayManager;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.group.xml.XmlGroupDAO;
|
||||
import sonia.scm.store.ConfigurationStore;
|
||||
import sonia.scm.store.ConfigurationStoreFactory;
|
||||
import sonia.scm.user.DefaultUserManager;
|
||||
import sonia.scm.user.DefaultUserDisplayManager;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserManager;
|
||||
import sonia.scm.user.xml.XmlUserDAO;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
import sonia.scm.xml.XmlDatabase;
|
||||
@@ -51,7 +49,7 @@ public class AutoCompleteResourceTest {
|
||||
public final ShiroRule shiroRule = new ShiroRule();
|
||||
|
||||
public static final String URL = "/" + AutoCompleteResource.PATH;
|
||||
private final Integer defaultLimit = Manager.DEFAULT_LIMIT;
|
||||
private final Integer defaultLimit = DisplayManager.DEFAULT_LIMIT;
|
||||
private Dispatcher dispatcher;
|
||||
|
||||
private XmlUserDAO userDao;
|
||||
@@ -73,8 +71,8 @@ public class AutoCompleteResourceTest {
|
||||
XmlGroupDAO groupDAO = new XmlGroupDAO(storeFactory);
|
||||
groupDao = spy(groupDAO);
|
||||
ReducedObjectModelToDtoMapperImpl mapper = new ReducedObjectModelToDtoMapperImpl();
|
||||
UserManager userManager = new DefaultUserManager(this.userDao);
|
||||
GroupManager groupManager = new DefaultGroupManager(groupDao);
|
||||
DefaultUserDisplayManager userManager = new DefaultUserDisplayManager(this.userDao);
|
||||
DefaultGroupDisplayManager groupManager = new DefaultGroupDisplayManager(groupDao);
|
||||
AutoCompleteResource autoCompleteResource = new AutoCompleteResource(mapper, userManager, groupManager);
|
||||
dispatcher = createDispatcher(autoCompleteResource);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import sonia.scm.security.PermissionAssigner;
|
||||
import sonia.scm.security.PermissionDescriptor;
|
||||
import sonia.scm.user.User;
|
||||
@@ -62,6 +64,21 @@ class SetupContextListenerTest {
|
||||
verifyAdminPermissionsAssigned();
|
||||
}
|
||||
|
||||
@Test
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
void shouldSkipAdminAccountCreationIfPropertyIsSet() {
|
||||
System.setProperty("sonia.scm.skipAdminCreation", "true");
|
||||
|
||||
try {
|
||||
setupContextListener.contextInitialized(null);
|
||||
|
||||
verify(userManager, never()).create(any());
|
||||
verify(permissionAssigner, never()).setPermissionsForUser(anyString(), any(Collection.class));
|
||||
} finally {
|
||||
System.setProperty("sonia.scm.skipAdminCreation", "");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDoNothingOnSecondStart() {
|
||||
List<User> users = Lists.newArrayList(UserTestData.createTrillian());
|
||||
|
||||
@@ -97,6 +97,11 @@ public class MustacheTemplateEngineTest extends TemplateEngineTestBase
|
||||
return "sonia/scm/template/001.mustache";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateResourceWithGermanTranslation() {
|
||||
return "sonia/scm/template/loc.mustache";
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -37,6 +37,7 @@ package sonia.scm.template;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
@@ -52,6 +53,7 @@ import java.io.StringWriter;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
@@ -92,6 +94,8 @@ public abstract class TemplateEngineTestBase
|
||||
*/
|
||||
public abstract String getTemplateResource();
|
||||
|
||||
public abstract String getTemplateResourceWithGermanTranslation();
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
@@ -126,7 +130,7 @@ public abstract class TemplateEngineTestBase
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetTemlateNotFound() throws IOException
|
||||
public void testGetTemplateNotFound() throws IOException
|
||||
{
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
TemplateEngine engine = createEngine(context);
|
||||
@@ -151,6 +155,32 @@ public abstract class TemplateEngineTestBase
|
||||
assertNotNull(engine.getTemplate(getTemplateResource()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTemplateFromClasspathWithExistingLocale() throws IOException
|
||||
{
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
TemplateEngine engine = createEngine(context);
|
||||
|
||||
Template template = engine.getTemplate(getTemplateResourceWithGermanTranslation(), Locale.GERMAN);
|
||||
StringWriter writer = new StringWriter();
|
||||
template.execute(writer, new Object());
|
||||
Assertions.assertThat(writer.toString()).contains("German");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTemplateFromClasspathWithNotExistingLocale() throws IOException
|
||||
{
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
TemplateEngine engine = createEngine(context);
|
||||
|
||||
Template template = engine.getTemplate(getTemplateResourceWithGermanTranslation(), Locale.CHINESE);
|
||||
StringWriter writer = new StringWriter();
|
||||
template.execute(writer, new Object());
|
||||
Assertions.assertThat(writer.toString()).contains("English");
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
English
|
||||
@@ -0,0 +1 @@
|
||||
German
|
||||
Reference in New Issue
Block a user