added frist draft of account ui

This commit is contained in:
2018-11-10 14:02:29 +01:00
parent b95ffdb417
commit c254d27e84
37 changed files with 2724 additions and 0 deletions

View File

@ -0,0 +1,91 @@
/*
* Copyright 2017 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web;
import de.muehlencord.shared.account.business.account.boundary.AccountControl;
import de.muehlencord.shared.account.business.account.entity.Account;
import java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.ManagedBean;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@ManagedBean
@SessionScoped
public class AccountProducer implements Serializable {
private static final long serialVersionUID = -3806204732038165311L;
private final Map<String, Object> objectMap = new ConcurrentHashMap<>();
@EJB
AccountControl accountController;
private Account account = null;
@Produces
public Account getAccount() {
String accountName;
if (account == null) {
Subject subject = SecurityUtils.getSubject();
if (subject == null) {
return null;
}
if ((subject.isAuthenticated() == false) && (subject.isRemembered() == false)) {
accountName = "web";
} else {
accountName = subject.getPrincipal().toString();
}
account = accountController.getAccountEntity(accountName, true);
}
return account;
}
public <T> T getValue(String key, Class<T> clazz) {
if (objectMap.containsKey(key)) {
Object obj = objectMap.get(key);
if (obj == null) {
return null;
}
try {
return clazz.cast(obj);
} catch (ClassCastException ex) {
return null;
}
} else {
return null;
}
}
public void setValue(String key, Object obj) {
objectMap.put(key, obj);
}
@Produces
public Locale getLocale() {
return Locale.ENGLISH; // TODO depend lcoale on account or on incoming request
}
}

View File

@ -0,0 +1,59 @@
package de.muehlencord.shared.account.web;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author joern.muehlencord
*/
@Named(value = "applicationController")
@ApplicationScoped
public class ApplicationController {
private final static Logger LOGGER = LoggerFactory.getLogger(ApplicationController.class.getName());
private String version;
private String buildDate;
@PostConstruct
public void init() {
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("buildInfo.properties");
if (in == null) {
return;
}
Properties props = new Properties();
try {
props.load(in);
version = props.getProperty("build.version");
buildDate = props.getProperty("build.timestamp");
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("buildInfo.properties read successfully");
}
} catch (IOException ex) {
LOGGER.error("Cannot find buildInfo.properties. ", ex);
version = "??";
buildDate = "??";
}
}
/* *** getter / setter *** */
public String getVersion() {
return version;
}
public String getBuildDate() {
return buildDate;
}
}

View File

@ -0,0 +1,53 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package de.muehlencord.shared.account.web;
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
import de.muehlencord.shared.account.business.accountcounfig.entity.AccountConfigurationKey;
import de.muehlencord.shared.account.business.accountcounfig.entity.AccountConfigurationValue;
import de.muehlencord.shared.account.business.config.entity.ConfigException;
import javax.ejb.EJB;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.InjectionPoint;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Dependent
public class ConfigurationProducer {
@EJB
ConfigService configService;
@Produces
@AccountConfigurationValue(key = AccountConfigurationKey.Producer)
public String produceConfigurationValue(InjectionPoint injectionPoint) {
Annotated annotated = injectionPoint.getAnnotated();
AccountConfigurationValue annotation = annotated.getAnnotation(AccountConfigurationValue.class);
if (annotation != null) {
AccountConfigurationKey key = annotation.key();
if (key != null) {
try {
switch (key) {
case BaseUrl:
return configService.getConfigValue("base.url");
case PasswordResetUrl:
return configService.getConfigValue("base.url") + "/login.xhtml";
default:
throw new IllegalStateException("Invalid key " + key + " for injection point: " + injectionPoint);
}
} catch (ConfigException ex) {
throw new IllegalStateException("Invalid key " + key + " for injection point: " + injectionPoint + ". Exception: " + ex.getMessage());
}
}
}
throw new IllegalStateException("No key for injection point: " + injectionPoint);
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2017 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web;
import javax.enterprise.context.ContextNotActiveException;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public class FacesContextProducer {
@Produces
@RequestScoped
public FacesContext getFacesContext() {
FacesContext ctx = FacesContext.getCurrentInstance();
if (ctx == null) {
throw new ContextNotActiveException("FacesContext is not active");
}
return ctx;
}
}

View File

@ -0,0 +1,42 @@
package de.muehlencord.shared.account.web;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.SynchronizationType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@ApplicationScoped
public class PersistenceContextFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(PersistenceContextFactory.class);
@PersistenceUnit
EntityManagerFactory emf;
@Produces
@RequestScoped
public EntityManager getEntityManager() {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("getting entityManager");
}
return emf.createEntityManager(SynchronizationType.UNSYNCHRONIZED);
}
public void closeEntityManager (@Disposes EntityManager em) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("closing entityManager");
}
em.close();
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2017 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web;
import java.io.Serializable;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@RequestScoped
public class ResourceBundleProducer implements Serializable {
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceBundleProducer.class);
private static final long serialVersionUID = 3764096270387408239L;
@Inject
private Locale locale;
@Inject
private FacesContext facesContext;
@Produces
public ResourceBundle getResourceBundle() {
ResourceBundle rb = ResourceBundle.getBundle("de.muehlencord.shared.account.web.presentation.messages", facesContext.getViewRoot().getLocale());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("ResourceBundle = "+rb);
}
return rb;
}
}

View File

@ -0,0 +1,48 @@
package de.muehlencord.shared.account.web;
import javax.annotation.Priority;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import static javax.transaction.Transactional.TxType.REQUIRED;
import javax.validation.constraints.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Transactional(value = REQUIRED)
@Interceptor
@Priority(value=TransactionJoinInterceptor.PRIORITY)
public class TransactionJoinInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionJoinInterceptor.class);
// attach behind the interceptor of the container
public static final int PRIORITY = Interceptor.Priority.PLATFORM_BEFORE+250;
private final EntityManager em;
@Inject
public TransactionJoinInterceptor(@NotNull EntityManager em) {
this.em = em;
}
@AroundInvoke
public Object joinTransaction(InvocationContext context) throws Exception {
if (em.isJoinedToTransaction()) {
LOGGER.info("transaction already joined");
} else {
LOGGER.info("joining transaction");
em.joinTransaction();
}
return context.proceed();
}
}

View File

@ -0,0 +1,180 @@
package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.account.boundary.AccountControl;
import de.muehlencord.shared.account.business.account.boundary.ApplicationRoleControl;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.account.entity.AccountStatus;
import de.muehlencord.shared.account.business.account.entity.ApplicationRoleEntity;
import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author jomu
*/
@SessionScoped
@Named
public class AccountView implements Serializable {
private static final long serialVersionUID = -8050582392249849438L;
private static final Logger LOGGER = LoggerFactory.getLogger(AccountView.class);
@EJB
private AccountControl accountService;
@EJB
private ApplicationRoleControl appliationRoleService;
/**
* boolean flag to determine wether disabled accounts should be shown
* accounts are not deleted but disabled and can be activated in case
*/
private boolean showDisabledAccounts = false;
// cached accounts
private List<AccountEntity> accountList = null;
// cached application roles
private List<ApplicationRoleEntity> applicationRoles = null;
// account currently on edit
private AccountEntity currentAccount;
private List<ApplicationRoleEntity> currentAccountRoles = null;
// boolean flag to toggle buttons which require an account to be selected
private boolean accountSelected = false;
public List<AccountEntity> getAccounts() {
if (accountList == null) {
accountList = accountService.getAccounts(showDisabledAccounts);
}
return accountList;
}
public List<ApplicationRoleEntity> getAllApplicationRoles() {
if (applicationRoles == null) {
applicationRoles = appliationRoleService.getAllRoles();
}
return applicationRoles;
}
public void newAccount() {
currentAccount = new AccountEntity();
currentAccount.setUsername(null);
currentAccount.setStatus("NEW"); // TODO add status enum
currentAccountRoles = new ArrayList<>();
}
public void editAccount() {
// function called by webpage
if (currentAccount == null) {
currentAccountRoles = null;
} else {
currentAccount = accountService.getAccountEntity(currentAccount.getUsername(), true);
this.currentAccountRoles = new ArrayList<>();
if (currentAccount.getApplicationRoleList() != null) {
currentAccountRoles.addAll(currentAccount.getApplicationRoleList());
}
}
}
public void cancelEditAccount() {
currentAccount = null;
currentAccountRoles = null;
}
public void saveEditAccount() {
String username = currentAccount.getUsername();
AccountEntity existingEntity = accountService.getAccountEntity(username, true);
// check if it is a new user (createdBy == null) but a user with same name already exists
if ((currentAccount.getCreatedBy() == null) && (existingEntity != null)) {
currentAccount.setUsername(null);
FacesUtil.addErrorMessage("editDialogMessaegs", "Create new account failed", "Account with username " + username + " already exists");
} else {
accountService.saveAccount(currentAccount, currentAccountRoles);
selectAccount();
if (currentAccount.getId() == null) {
// this was a new account
// force accounts to be loaded from database again
accountList = null;
}
}
}
public void deleteAccount() {
try {
accountService.deleteAccount(currentAccount);
accountList.remove(currentAccount);
FacesUtil.addGlobalInfoMessage("Info", "Account " + currentAccount.getUsername() + " deleted");
currentAccount = null;
currentAccountRoles = null;
deselectAccount();
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.error(ex.toString());
}
FacesUtil.addGlobalErrorMessage("Error deleting account", ex.getMessage());
}
}
public void selectAccount() {
this.accountSelected = true;
}
public void deselectAccount() {
this.accountSelected = false;
}
public void showDisabledAccountsChange() {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("show diabled accounts changed to {}", showDisabledAccounts);
}
this.accountList = null;
}
public List<String> getStatusList() {
return AccountStatus.getAllStatusNames();
}
/* **** getter / setter **** */
public AccountEntity getCurrentAccount() {
return currentAccount;
}
public void setCurrentAccount(AccountEntity currentAccount) {
this.currentAccount = currentAccount;
}
public boolean isAccountSelected() {
return accountSelected;
}
public void setAccountSelected(boolean accountSelected) {
this.accountSelected = accountSelected;
}
public boolean isShowDisabledAccounts() {
return showDisabledAccounts;
}
public void setShowDisabledAccounts(boolean showDisabledAccounts) {
this.showDisabledAccounts = showDisabledAccounts;
}
public List<ApplicationRoleEntity> getCurrentAccountRoles() {
return currentAccountRoles;
}
public void setCurrentAccountRoles(List<ApplicationRoleEntity> currentAccountRoles) {
this.currentAccountRoles = currentAccountRoles;
}
}

View File

@ -0,0 +1,99 @@
package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.application.boundary.ApplicationService;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Named(value = "applicationView")
@SessionScoped
public class ApplicationView implements Serializable {
private static final long serialVersionUID = -5515249316880163539L;
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationView.class);
@Inject
ApplicationService applicationService;
private ApplicationEntity currentApplication = null;
private List<ApplicationEntity> applicationList = null;
private ApplicationEntity editApplication = null;
@PostConstruct
public void selectDefaultCurrentApplication() {
// force applications to be loaded from database
getAllApplications();
if ((applicationList != null) && (!applicationList.isEmpty())) {
currentApplication = applicationList.get(0);
}
}
public List<ApplicationEntity> getAllApplications() {
if (applicationList == null) {
applicationList = applicationService.getAllApplications();
}
return applicationList;
}
public void selectApplication() {
if (currentApplication != null) {
LOGGER.info("selected application: {}", currentApplication.getApplicationName());
FacesUtil.addGlobalInfoMessage("Success", "Selected application " + currentApplication.getApplicationName());
}
}
public void newApplication() {
this.editApplication = new ApplicationEntity();
}
public void cancelEditApplication() {
this.editApplication = null;
}
public void saveEditApplication() {
if (editApplication == null) {
FacesUtil.addGlobalErrorMessage("Error", "Need to provide data");
} else if ((editApplication.getApplicationName() == null) || (editApplication.getApplicationName().trim().equals(""))) {
String hint;
if (editApplication.getId() == null) {
hint = "Cannot create application";
} else {
hint = "Cannot save application";
}
FacesUtil.addGlobalErrorMessage(hint, "Application name must not be empty");
} else {
currentApplication = applicationService.createOrUpdate(editApplication);
// force reload of to update view
applicationList = null;
FacesUtil.addGlobalInfoMessage("Info", "Application saved");
}
}
/* *** getter / setter *** */
public ApplicationEntity getCurrentApplication() {
return currentApplication;
}
public void setCurrentApplication(ApplicationEntity currentApplication) {
this.currentApplication = currentApplication;
}
public ApplicationEntity getEditApplication() {
return editApplication;
}
public void setEditApplication(ApplicationEntity editApplication) {
this.editApplication = editApplication;
}
}

View File

@ -0,0 +1,252 @@
/*
* Copyright 2017 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.account.boundary.ApplicationRoleControl;
import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.account.entity.ApplicationPermissionEntity;
import de.muehlencord.shared.account.business.account.entity.ApplicationRoleEntity;
import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.validation.constraints.Size;
import org.primefaces.event.SelectEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@SessionScoped
@Named
public class GroupView implements Serializable {
private static final long serialVersionUID = 1669321020398119007L;
private static final Logger LOGGER = LoggerFactory.getLogger(GroupView.class);
@EJB
ApplicationRoleControl applicationRoleControl;
@Size(max = 80)
private String newRoleName;
@Size(max = 200)
private String newRoleDescription;
// flag to determine whether a role is selected or not
private boolean isPermissionSelected = false;
private List<ApplicationRoleEntity> allRoles = null;
private List<ApplicationPermissionEntity> currentRolePermissions = null;
private List<ApplicationPermissionEntity> missingApplicationsPermissions = null;
private ApplicationRoleEntity currentRole;
private ApplicationPermissionEntity currentPermission;
private ApplicationPermissionEntity newPermission;
public List<ApplicationRoleEntity> getAllRoles() {
if (allRoles == null) {
allRoles = applicationRoleControl.getAllRoles();
}
return allRoles;
}
public void newRole() {
if ((newRoleName == null) || (newRoleName.trim().length() == 0)) {
FacesUtil.addGlobalErrorMessage("Error", "Permission name must not be null");
} else if ((newRoleDescription == null) || (newRoleDescription.trim().length() == 0)) {
FacesUtil.addGlobalErrorMessage("Error", "Permission name must not be null");
} else {
applicationRoleControl.createOrUpdate(newRoleName, newRoleDescription);
allRoles = null; // force reload
newRoleName = null;
newRoleDescription = null;
}
}
public void editRole() {
if (currentRole == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a permission to edit");
} else {
allRoles = null; // force reload
newRoleName = currentRole.getRoleName();
newRoleDescription = currentRole.getRoleDescription();
}
}
public void deleteRole() {
if (currentRole == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a permission to edit");
} else {
try {
applicationRoleControl.delete(currentRole);
allRoles = null; // force reload
currentRole = null;
currentRolePermissions = null;
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.debug(ex.toString());
}
FacesUtil.addGlobalErrorMessage("Error while deleting permission.", ex.toString());
}
}
}
public void onRoleSelect(SelectEvent event) {
currentRolePermissions = null;
currentRolePermissions = getRolePermissions();
missingApplicationsPermissions = null;
missingApplicationsPermissions = getMissingPermissions();
}
public List<ApplicationPermissionEntity> getRolePermissions() {
if (currentRole == null) {
currentRolePermissions = new ArrayList<>();
return currentRolePermissions;
} else {
if (currentRolePermissions == null) {
try {
currentRolePermissions = applicationRoleControl.getRolePermissions(currentRole);
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.debug(ex.toString());
}
FacesUtil.addGlobalErrorMessage("Error while fetching role permissions", "see log for details");
currentRolePermissions = new ArrayList<>();
}
}
return currentRolePermissions;
}
}
public List<ApplicationPermissionEntity> getMissingPermissions() {
if (currentRole == null) {
missingApplicationsPermissions = new ArrayList<>();
return missingApplicationsPermissions;
} else {
if (missingApplicationsPermissions == null) {
missingApplicationsPermissions = applicationRoleControl.getNotAssignedApplicationPermissions(currentRole);
}
return missingApplicationsPermissions;
}
}
public void addRolePermission() {
if (newPermission == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a new permission first");
} else {
try {
applicationRoleControl.addPermission(currentRole, newPermission);
currentRolePermissions = null;
missingApplicationsPermissions = null;
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.debug(ex.toString());
}
FacesUtil.addGlobalErrorMessage("Error while adding permission", ex.getMessage());
}
}
}
public void removeRolePermission() {
if (currentPermission == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a permission first");
} else {
try {
applicationRoleControl.removePermission(currentRole, currentPermission);
currentRolePermissions = null;
missingApplicationsPermissions = null;
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.debug(ex.toString());
}
FacesUtil.addGlobalErrorMessage("Error while adding permission", ex.getMessage());
}
}
}
public void selectPermission() {
this.isPermissionSelected = true;
}
public void deselectPermission() {
this.isPermissionSelected = false;
}
/* *** getter / setter *** */
public ApplicationRoleEntity getCurrentRole() {
return currentRole;
}
public void setCurrentRole(ApplicationRoleEntity currentRole) {
this.currentRole = currentRole;
}
public ApplicationPermissionEntity getCurrentPermission() {
return currentPermission;
}
public void setCurrentPermission(ApplicationPermissionEntity currentPermission) {
this.currentPermission = currentPermission;
}
public String getNewRoleName() {
return newRoleName;
}
public void setNewRoleName(String newRoleName) {
this.newRoleName = newRoleName;
}
public String getNewRoleDescription() {
return newRoleDescription;
}
public void setNewRoleDescription(String newRoleDescription) {
this.newRoleDescription = newRoleDescription;
}
public ApplicationPermissionEntity getNewPermission() {
return newPermission;
}
public void setNewPermission(ApplicationPermissionEntity newPermission) {
this.newPermission = newPermission;
}
public boolean isIsPermissionSelected() {
return isPermissionSelected;
}
public void setIsPermissionSelected(boolean isPermissionSelected) {
this.isPermissionSelected = isPermissionSelected;
}
}

View File

@ -0,0 +1,46 @@
package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
import de.muehlencord.shared.account.business.config.entity.ConfigException;
import javax.ejb.EJB;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Named(value = "instanceView")
@ApplicationScoped
public class InstanceView {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(InstanceView.class);
@EJB
ConfigService configService;
public boolean isDevelopmentVersion() {
String instanceName = getInstanceName();
return !instanceName.equals("Production");
}
public String getInstanceName() {
String instanceName;
try {
instanceName = configService.getConfigValue("base.instance");
} catch (ConfigException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.error(ex.toString());
}
instanceName = "unknown (" + ex.toString() + ")";
}
if (instanceName == null) {
return "unknown";
} else {
return instanceName;
}
}
}

View File

@ -0,0 +1,167 @@
/*
* Copyright 2017 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.account.boundary.ApplicationPermissionControl;
import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.account.entity.ApplicationPermissionEntity;
import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.validation.constraints.Size;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@SessionScoped
@Named
public class PermissionView implements Serializable {
private static final long serialVersionUID = -1469453490360990772L;
private static final Logger LOGGER = LoggerFactory.getLogger(PermissionView.class);
@EJB
ApplicationPermissionControl applicationPermissionService;
@Size(max = 80)
private String newPermissionName;
@Size(max = 200)
private String newPermissionDescription;
private ApplicationPermissionEntity currentPermission;
// flag if a permission is selected - used to control button state
private boolean permissionSelected;
public List<ApplicationPermissionEntity> getAppPermissions() {
return applicationPermissionService.getApplicationPermissions();
}
public void savePermission() {
if ((newPermissionName == null) || (newPermissionName.trim().length() == 0)) {
FacesUtil.addGlobalErrorMessage("Error", "Permission name must not be null");
} else if ((newPermissionDescription == null) || (newPermissionDescription.trim().length() == 0)) {
FacesUtil.addGlobalErrorMessage("Error", "Permission name must not be null");
} else {
applicationPermissionService.createOrUpdate(newPermissionName, newPermissionDescription);
FacesUtil.addGlobalInfoMessage("Pemissin updated", "Permission "+newPermissionName+" updated");
newPermissionName = null;
newPermissionDescription = null;
deselectPermission();
}
}
public void editPermission() {
if (currentPermission == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a permission to edit");
} else {
newPermissionName = currentPermission.getPermissionName();
newPermissionDescription = currentPermission.getPermissionDescription();
}
}
public void deletePermission() {
if (currentPermission == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a permission to edit");
} else {
try {
applicationPermissionService.delete(currentPermission);
currentPermission = null;
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.debug(ex.toString());
}
FacesUtil.addGlobalErrorMessage("Error while deleting permission.", ex.toString());
}
}
}
public void selectPermission() {
this.permissionSelected = true;
}
public void deselectPermission() {
this.permissionSelected = false;
this.newPermissionName = null;
this.newPermissionDescription = null;
}
public boolean getCanEdit() {
if (!isPermissionSelected()) {
return false;
}
return true;
}
public boolean getCanDelete() {
if (!isPermissionSelected()) {
return false;
}
if (newPermissionName == null) {
return true;
}
return false;
}
/* *** getter / setter *** */
public ApplicationPermissionEntity getCurrentPermission() {
return currentPermission;
}
public void setCurrentPermission(ApplicationPermissionEntity newCurrentPermission) {
if ((currentPermission == null) || (newCurrentPermission == null) || (!currentPermission.equals(newCurrentPermission))) {
this.newPermissionName = null;
this.newPermissionDescription = null;
}
this.currentPermission = newCurrentPermission;
}
public String getNewPermissionName() {
return newPermissionName;
}
public void setNewPermissionName(String newPermissionName) {
this.newPermissionName = newPermissionName;
}
public String getNewPermissionDescription() {
return newPermissionDescription;
}
public void setNewPermissionDescription(String newPermissionDescription) {
this.newPermissionDescription = newPermissionDescription;
}
public boolean isPermissionSelected() {
return permissionSelected;
}
public void setPermissionSelected(boolean permissionSelected) {
this.permissionSelected = permissionSelected;
}
}

View File

@ -0,0 +1,36 @@
package de.muehlencord.shared.account.web.presentation;
import java.io.Serializable;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@FacesValidator("uniqueApplicationValidator")
public class UniqueApplicationValidator implements Validator, Serializable {
private static final long serialVersionUID = 2526409681909574670L;
private static final Logger LOGGER = LoggerFactory.getLogger(UniqueApplicationValidator.class);
@Inject
EntityManager em;
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
String name = (String) value;
LOGGER.info("Name = {}", name) ;
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="com.wincornixdorf.pcd_pu" transaction-type="JTA">
<jta-data-source>java:/jboss/accountTestDs</jta-data-source>
<class>de.muehlencord.shared.account.business.account.entity.AccountEntity</class>
<class>de.muehlencord.shared.account.business.account.entity.AccountHistoryEntity</class>
<class>de.muehlencord.shared.account.business.account.entity.ApplicationPermissionEntity</class>
<class>de.muehlencord.shared.account.business.account.entity.ApplicationRoleEntity</class>
<class>de.muehlencord.shared.account.business.config.entity.ConfigEntity</class>
<class>de.muehlencord.shared.account.business.mail.entity.MailTemplateEntity</class>
<class>de.muehlencord.shared.account.business.application.entity.ApplicationEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<validation-mode>NONE</validation-mode>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL94Dialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
</properties>
</persistence-unit>
</persistence>

View File

@ -0,0 +1,32 @@
admin.loginPage=/login.xhtml
admin.indexPage=/web/account.xhtml
#admin.dateFormat=
#admin.breadcrumbSize=5
admin.renderMessages=true
#admin.renderAjaxStatus=true
## disable filter to redirect to login page - shiro security filter is already doing this
admin.disableFilter=true
#admin.renderBreadCrumb=true
#admin.enableSlideMenu=true
#admin.enableRipple=true
#admin.rippleElements= .ripplelink,button.ui-button,.ui-selectlistbox-item,.ui-multiselectlistbox-item,.ui-selectonemenu-label,.ui-selectcheckboxmenu,\
#.ui-autocomplete-dropdown, .ui-autocomplete-item ... (the list goes on)
admin.skin=skin-purple-light
#admin.autoShowNavbar=true
#admin.ignoredResources=
#admin.loadingImage=ajaxloadingbar.gif
#admin.extensionLessUrls=false
admin.renderControlSidebar=false
#admin.controlSidebar.showOnMobile=false
#admin.controlSidebar.leftMenuTemplate=true
#admin.controlSidebar.fixedLayout=false
#admin.controlSidebar.boxedLayout=false
#admin.controlSidebar.sidebarCollapsed=false
#admin.controlSidebar.expandOnHover=false
#admin.controlSidebar.fixed=false
#admin.controlSidebar.darkSkin=true
#admin.rippleMobileOnly=true
admin.renderMenuSearch=false
## do not autohide
admin.autoHideMessages=false
#admin.messagesHideTimeout=2500

View File

@ -0,0 +1,2 @@
build.version=${project.version}
build.timestamp=${timestamp}

View File

@ -0,0 +1,131 @@
header_login=Login
header_reset_password=Reset password
message_username_password=Please enter your user name and a new password
button_login=Login
button_cancel=Cancel
button_password_lost=Password lost?
label_username=Username
label_password=Password
label_new_password=New Password
button_password_reset=Reset password
header_passwort_lost=Lost password
message_start_password_reset=Please enter your username to start the password recovery procedure
menu_dashboard=Dashboard
menu_events=Events
menu_administration=Administration
menu_overview=Overview
menu_emails=Emails
menu_account=Account
menu_config=Config
menu_logout=Logout
button_new=New
button_delete=Delete
button_edit=Edit
button_reload=Reload
label_name=Name
label_description=Description
label_event_date=Event Date
label_reservation=Reservation
label_reservation_from_to=Reservation from/to
label_actions=Actions
message_confirm=Are you sure?
button_setup=Setup
button_reservations=Reservations
label_event_name=Event Name
label_event_item_desc=Event Item Description
label_timezone=Timezone
label_event_start=Event Start
label_event_end=Event End
label_reservation_autostart=Reservation start
label_reservation_autoend=Reservation end
label_reservation_active=Reservation active
label_reservation_max_items=Max Items
label_booking_deadline=Booking deadline
label_template_validation=Email validation mail template
label_template_confirmation=Event confirmation mail template
label_template_waitlist=Event waitlist mail template
message_event_not_found=Event not found
label_items=Items
label_costs=Costs
label_all=All
label_yes=Yes
label_no=No
label_status=Status
label_firstname=Firstname
label_lastname=Lastname
label_emailaddress=Emailaddress
label_comment=Comment
label_email_confirmed=Email confirmed
label_booking_number=Booking Number
label_booking_executed=booking executed
tt_log_entries=Show log entries
tt_cancel_reservation=Cancel the current reservation
tt_send_email_again=Send email again
tt_move_from_wl=Move from waitlist
tt_fix_reservation=Try to fix the current reservation
tt_edit_reservation=Edit the reservation
button_refresh_free=Refresh free
button_manual_reserve=Reserve
button_export=Export
label_amount=Amount
label_select=Select
label_created_by=Created by
label_ip=IP
label_ip_forwarded=IP (forwarded)
label_value=Value
label_useragent=Useragent
button_ok=Ok
message_comment=Please add a comment
menu_help=Help
label_event=Event
label_active=Active
label_waitlist=Waitlist
label_is_waitlist=Is waitlist
label_order=Order
message_dynamic_numbering=dynamic numbering (put %n as placeholder)
label_start_number=Start Number
label_end_number=End Number
header_item_def=Define items for event
message_no_event_items=No event item defined
button_overview=Overview
label_reservation_auto_start=Automatically switch on/off
label_item_public=Item public?
label_is_publicitem=Is public
label_customer_comment=Customer comment
label_change_comment=Change comment
label_existing_items=current items
label_new_items=new items
label_available_items=available items
label_no_records=No records found.
button_mail=Mail
header_email_distribution=Email distribution
label_template=Template
label_demomode=Demo mode
message_invalid_email=Please provide a valid email address
menu_permissions=Permissions
button_save=Save
menu_groups=Groups
message_email_sent=email sent
message_email_with_error=emails with error
message_no_email=no email address defined
message_email_not_sent=Error while sending emails
label_seating=Seating
label_attachments=Attachments
label_language=Language
label_subject=Subject
label_bytes=Bytes
label_upload=Upload
header_export=Export
label_export_type=Export Type
label_filtered=Filtered
label_include_deleted=Include deleted
label_include_log=Include Logs
label_template_booking_executed=Booking executed template
label_street=Street
label_zipCode=ZIP Code
label_city=City
label_groupName=Groupname
label_phoneNumber=Phone Number
label_template_waitlist_cancelled=Waitlist cancelled mail template
msgs_menu_status=Status
menu_status=Status

View File

@ -0,0 +1,132 @@
header_login=Anmeldung
header_reset_password=Passwort zur\u00fccksetzten
message_username_password=Bitte geben Deinen Benutzernamen und dein Passwort ein
button_login=Anmelden
button_cancel=Abbruch
button_password_lost=Passwort vergessen?
label_username=Benutzername
label_password=Passwort
label_new_password=Neues Passwort
button_password_reset=Passwort zur\u00fccksetzten
header_passwort_lost=Passwort vergessen
message_start_password_reset=Bitte gib deinen Benutzernamen ein um das Zur\u00fccksetzten des Passworts zu starten.
menu_dashboard=Dashbaord
menu_events=Veranstaltungen
menu_administration=Administration
menu_overview=\u00dcbersicht
menu_emails=E-Mails
menu_account=Benutzer
menu_config=Konfiguration
menu_logout=Abmelden
button_new=Neu
button_delete=L\u00f6schen
button_edit=Bearbeiten
button_reload=Aktualisieren
label_name=Name
label_description=Beschreibung
label_event_date=Veranstaltungsdatum
label_reservation=Reservierung
label_reservation_from_to=Reservierung von/bis
label_actions=Aktionen
message_confirm=Bist du sicher?
button_setup=Setup
button_reservations=Reservierungen
label_event_name=Veranstaltungsname
label_event_item_desc=Veranstaltungsobjekte
label_timezone=Zeitzone
label_event_start=Veranstaltungsbeginn
label_event_end=Veranstaltungsende
label_reservation_autostart=Reservierung von
label_reservation_autoend=Reservierung bis
label_reservation_active=Reservierung aktiv
label_reservation_max_items=Maximale Objekte
label_booking_deadline=Buchungsfrist
label_template_validation=Vorlage Emailvalidierung
label_template_confirmation=Vorlage Reservierungsbest\u00e4tigung
label_template_waitlist=Vorlage Wartelist
message_event_not_found=Veranstaltung nicht gefunden
label_items=Objekte
label_costs=Kosten
label_all=Alle
label_yes=Ja
label_no=Nein
label_status=Status
label_firstname=Vorname
label_lastname=Nachname
label_emailaddress=E-Mail-Adresse
label_comment=Kommentar
label_email_confirmed=E-Mail best\u00e4tigt
label_booking_number=Buchungsnummer
label_booking_executed=Buchungs ausgef\u00fchrt
tt_log_entries=Logbucheintr\u00e4ge
tt_cancel_reservation=Storniere die Reservierung
tt_send_email_again=Sende E-Mail erneut
tt_move_from_wl=Schiebe von Warteliste
tt_fix_reservation=Versuche den Fehler zu beheben
tt_edit_reservation=Bearbeite die Reservierung
button_refresh_free=Frei aktualisieren
button_manual_reserve=Reservieren
button_export=Exportieren
label_amount=Anzahl
label_select=W\u00e4hlen
label_created_by=Erzeugt durch
label_ip=IP
label_ip_forwarded=IP (forwarded)
label_value=Wert
label_useragent=Useragent
button_ok=Ok
message_comment=Bitte geben Sie einen Kommentar an
menu_help=Hilfe
label_event=Veranstaltung
label_active=Aktiv
label_waitlist=Warteliste
label_is_waitlist=Ist Warteliste
label_order=Reihenfolge
message_dynamic_numbering=Dynamische Nummerierung (%n als Platzhalter)
label_start_number=Startnummer
label_end_number=Endnummer
header_item_def=Objekte f\u00fcr Veranstaltung
message_no_event_items=Keine Objekte definiert
button_overview=\u00dcbersicht
label_reservation_auto_start=Automatisch ein/ausschalten
label_item_public=\u00d6ffentlich verf\u00fcgar?
label_is_publicitem=\u00d6ffentlich
label_customer_comment=Kundenkommentar
label_change_comment=\u00c4nderungskommentar
label_existing_items=aktuelle Objekte
label_new_items=neue Objekte
label_available_items=verf\u00fcgbare Objekte
label_no_records=Keine Daten gefunden.
button_mail=E-Mail
header_email_distribution=Emailversand
label_template=Vorlage
label_demomode=Demomodus
message_invalid_email=Bitte geben Sie eine g\u00fcltige Emailadresse an
menu_permissions=Berechtigungen
button_save=Speichern
menu_groups=Gruppen
message_email_sent=Email gesendet
message_email_with_error=Emails mit Fehler
message_no_email=keine Emailadresse verf\u00fcgbar
message_email_not_sent=Fehler beim Versenden der Email
label_seating=Saalplan Platz
label_attachments=Attachments
label_language=Sprache
label_subject=Betreff
label_bytes=Bytes
label_upload=Upload
header_export=Exportieren
label_export_type=Export Art
label_filtered=Gefiltert
label_include_deleted=Einschlie\u00dflich gel\u00f6scht
label_include_log=mit Logbuch
label_template_booking_executed=Vorlage Buchung durchgef\u00fchrt
label_street=Stra\u00dfe
label_zipCode=PLZ
label_city=Ort
label_groupName=Gruppenname
label_phoneNumber=Telefonnummer
label_template_waitlist_cancelled=Vorlage Warteliste Abbruch
msgs_menu_status=Status
menu_status=Status

View File

@ -0,0 +1,132 @@
header_login=Login
header_reset_password=Reset password
message_username_password=Please enter your user name and a new password
button_login=Login
button_cancel=Cancel
button_password_lost=Password lost?
label_username=Username
label_password=Password
label_new_password=New Password
button_password_reset=Reset password
header_passwort_lost=Lost password
message_start_password_reset=Please enter your username to start the password recovery procedure
menu_dashboard=Dashboard
menu_events=Events
menu_administration=Administration
menu_overview=Overview
menu_emails=Emails
menu_account=Account
menu_config=Config
menu_logout=Logout
button_new=New
button_delete=Delete
button_edit=Edit
button_reload=Reload
label_name=Name
label_description=Description
label_event_date=Event Date
label_reservation=Reservation
label_reservation_from_to=Reservation from/to
label_actions=Actions
message_confirm=Are you sure?
button_setup=Setup
button_reservations=Reservations
label_event_name=Event Name
label_event_item_desc=Event Item Description
label_timezone=Timezone
label_event_start=Event Start
label_event_end=Event End
label_reservation_autostart=Reservation Start
label_reservation_autoend=Reservation End
label_reservation_active=Reservation active
label_reservation_max_items=Max Items
label_booking_deadline=Booking deadline
label_template_validation=Email validation mail template
label_template_confirmation=Event confirmation mail template
label_template_waitlist=Event waitlist mail template
message_event_not_found=Event not found
label_items=Items
label_costs=Costs
label_all=All
label_yes=Yes
label_no=No
label_status=Status
label_firstname=Firstname
label_lastname=Lastname
label_emailaddress=Emailaddress
label_comment=Comment
label_email_confirmed=Email confirmed
label_booking_number=Booking Number
label_booking_executed=booking executed
tt_log_entries=Show log entries
tt_cancel_reservation=Cancel the current reservation
tt_send_email_again=Send email again
tt_move_from_wl=Move from waitlist
tt_fix_reservation=Try to fix the current reservation
tt_edit_reservation=Edit the reservation
button_refresh_free=Refresh free
button_manual_reserve=Reserve
button_export=Export
label_amount=Amount
label_select=Select
label_created_by=Created by
label_ip=IP
label_ip_forwarded=IP (forwarded)
label_value=Value
label_useragent=Useragent
button_ok=Ok
message_comment=Please add a comment
menu_help=Help
label_event=Event
label_active=Active
label_waitlist=Waitlist
label_is_waitlist=Is waitlist
label_order=Reservation Order
message_dynamic_numbering=dynamic numbering (put %n as placeholder)
label_start_number=Start Number
label_end_number=End Number
header_item_def=Define items for event
message_no_event_items=No event item defined
button_overview=Overview
label_reservation_auto_start=Automatically switch on/off
label_item_public=Item public?
label_is_publicitem=Is public
label_customer_comment=Customer comment
label_change_comment=Change comment
label_existing_items=current items
label_new_items=new items
label_available_items=available items
label_no_records=No records found.
button_mail=Mail
header_email_distribution=Email distribution
label_template=Template
label_demomode=Demo mode
message_invalid_email=Please provide a valid email address
menu_permissions=Permissions
button_save=Save
menu_groups=Groups
message_email_sent=email sent
message_email_with_error=emails with error
message_no_email=no email address defined
message_email_not_sent=Error while sending emails
label_seating=Seating
label_attachments=Anh\u00e4nge
label_language=Language
label_subject=Subject
label_bytes=Bytes
label_upload=Hochladen
header_export=Export
label_export_type=Export Type
label_filtered=Filtered
label_include_deleted=Include deleted
label_include_log=Include Logs
label_template_booking_executed=Booking executed template
label_street=Street
label_zipCode=ZIP Code
label_city=City
label_groupName=Groupname
label_phoneNumber=Phone Number
label_template_waitlist_cancelled=Waitlist cancelled mail template
msgs_menu_status=Status
menu_status=Status

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1"
bean-discovery-mode="all">
</beans>

View File

@ -0,0 +1,26 @@
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<application>
<el-resolver>org.primefaces.application.exceptionhandler.PrimeExceptionHandlerELResolver</el-resolver>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>en</supported-locale>
<supported-locale>de</supported-locale>
</locale-config>
<!-- register own messages for general i18n support -->
<resource-bundle>
<base-name>de.muehlencord.shared.account.web.presentation.messages</base-name>
<var>msgs</var>
</resource-bundle>
</application>
<factory>
<exception-handler-factory>org.omnifaces.exceptionhandler.FullAjaxExceptionHandlerFactory</exception-handler-factory>
</factory>
</faces-config>

View File

@ -0,0 +1,57 @@
[main]
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
# DataSource Setup
datasource = org.apache.shiro.jndi.JndiObjectFactory
datasource.resourceName = java:/jboss/accountTestDs
# TODO - change to accountDs
datasource.resourceRef = true
# HashService
hashService = org.apache.shiro.crypto.hash.DefaultHashService
hashService.hashIterations = 500000
hashService.hashAlgorithmName = SHA-512
hashService.generatePublicSalt = true
# Password service
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordService.hashService = $hashService
# Required password matcher
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
passwordMatcher.passwordService = $passwordService
# JDBC Realm setup
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.permissionsLookupEnabled=false
jdbcRealm.authenticationQuery = select account_password from account where username = ? and status not in ('LOCKED','DELETED')
jdbcRealm.userRolesQuery = select r.role_name from application_role r, account_role ar, account a WHERE a.username = ? AND a.id = ar.account AND ar.account_role = r.id
jdbcRealm.credentialsMatcher = $passwordMatcher
jdbcRealm.dataSource = $datasource
# Activate realms
authcStrategy = org.apache.shiro.authc.pam.AllSuccessfulStrategy
securityManager.realms = $jdbcRealm
securityManager.authenticator.authenticationStrategy = $authcStrategy
# Setup authentication filter
authc = de.muehlencord.shirofaces.filter.FacesAjaxAwarePassThruAuthenticationFilter
authc.loginUrl = /login.xhtml
authc.successUrl = /web/account.xhtml
roles.unauthorizedUrl = /error/accessDenied.xhtml
#
# filter setup
#
[urls]
/public/**=anon
/resources/**=anon
/fonts/**=anon
/javax.faces.resource/**=anon
/=anon
/index.html=anon
/login.xhtml=authc
/logout.xhtml=logout
/web/**=authc

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<display-name>reservation-system-backed</display-name>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>${jsf.projectStage}</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
<param-value>1048576</param-value>
</context-param>
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>admin</param-value>
</context-param>
<context-param>
<param-name>primefaces.FONT_AWESOME</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>primefaces.MOVE_SCRIPTS_TO_BOTTOM</param-name>
<param-value>true</param-value>
</context-param>
<servlet>
<servlet-name>FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>FacesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>web/account.xhtml</welcome-file>
</welcome-file-list>
<!-- Shiro Web Environment -->
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
<display-name>ShiroFilter</display-name>
<filter-name>shiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<!-- Faces Exception Filter -->
<filter>
<display-name>FacesExceptionFilter</display-name>
<filter-name>facesExceptionFilter</filter-name>
<filter-class>org.omnifaces.filter.FacesExceptionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>facesExceptionFilter</filter-name>
<servlet-name>FacesServlet</servlet-name>
</filter-mapping>
<!-- Content Security Policy headers -->
<filter>
<filter-name>contentSecurityFilter</filter-name>
<filter-class>de.muehlencord.sf.filter.ContentSecurityPolicyFilter</filter-class>
<init-param>
<param-name>report-only</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>default-src</param-name>
<param-value>'none'</param-value>
</init-param>
<init-param>
<param-name>img-src</param-name>
<param-value>'self'</param-value>
</init-param>
<init-param>
<param-name>script-src</param-name>
<param-value>'self' 'unsafe-inline' 'unsafe-eval'</param-value>
</init-param>
<init-param>
<param-name>style-src</param-name>
<param-value>'self' 'unsafe-inline'</param-value>
</init-param>
<init-param>
<param-name>connect-src</param-name>
<param-value>'self'</param-value>
</init-param>
<init-param>
<param-name>font-src</param-name>
<param-value>'self'</param-value>
</init-param>
<init-param>
<param-name>object-src</param-name>
<param-value>'none'</param-value>
</init-param>
<init-param>
<param-name>media-src</param-name>
<param-value>'none'</param-value>
</init-param>
<init-param>
<param-name>child-src</param-name>
<param-value>'none'</param-value>
</init-param>
</filter>
<!-- Security related headers -->
<filter>
<display-name>OwaspStandardFilter</display-name>
<filter-name>owaspStandardFilter</filter-name>
<filter-class>de.muehlencord.sf.filter.OwaspStandardFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>owaspStandardFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

View File

@ -0,0 +1,99 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Login Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="shortcut icon" href="#{resource['images/favicon/favicon.ico']}" />
<h:outputStylesheet name="css/admin.css" />
<style type="text/css">
/* below css hides growls in small screens and makes messages visible */
@media (max-width: 768px) {
body div.ui-growl {
display: none;
}
body div.ui-messages {
display: block;
}
}
/* below css hides messages in medium/big devices and makes growl visible in such devices */
@media (min-width: 769px) {
body div.ui-growl {
display: block;
}
body div.ui-messages {
display: none;
}
}
body.login-page {
background-color: transparent;
}
html {
background: url(#{resource[ 'images:login-bg.png' ]}) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
</style>
</h:head>
<h:body styleClass="hold-transition login-page">
<p:growl sticky="true">
<p:autoUpdate />
</p:growl>
<div id="loader" class="load-bar" style="display: none">
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
</div>
<div class="login-box">
<div class="login-logo">
<p:link href="/web/account.xhtml"><b>Account&nbsp;</b>Management</p:link>
<h:outputLabel rendered="#{instanceView.developmentVersion}" value="#{instanceView.instanceName}" />
</div>
<!-- /.login-logo -->
<div class="box login-box-body">
<h:form>
<p:focus context="panel" for="username" />
<p class="login-box-msg">Sign in to start your session</p>
<p:messages closable="true" />
<div id="panel" class="form-group has-feedback">
<p:inputText id="username" value="#{loginView.username}" styleClass="form-control" placeholder="Username"
required="true" autocomplete="off"
requiredMessage="Username is required."/>
<i class="fa fa-user form-control-feedback"></i>
</div>
<div class="form-group has-feedback">
<p:inputText value="#{loginView.password}" type="password" styleClass="form-control"
placeholder="Password" required="true" autocomplete="off" size="40"
requiredMessage="Password is required."/>
<i class="fa fa-lock form-control-feedback" style="font-size: 18px" ></i>
</div>
<div class="row">
<p:spacer height="10"/>
<div class="col-xs-12">
<p:commandButton styleClass="btn btn-success btn-block" onclick="showBar()"
action="#{loginView.authenticate}" oncomplete="if(args.validationFailed) { hideBar()}"
value="Sign In" process="@form" update="@form" icon="fa fa-sign-in" iconPos="left"/>
<p>&nbsp;</p>
<p:commandButton styleClass="btn btn-primary btn-block" action="#{menuView.publicHome}"
value="Home" immediate="true" icon="fa fa-home" iconPos="left" ajax="false"/>
</div>
</div>
</h:form>
</div>
<!-- /.login-box-body -->
</div>
</h:body>
</html>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/resources/template/template.xhtml">
<ui:define name="title">
Logout
</ui:define>
<ui:define name="body">
<h2>You are logged out. </h2>
</ui:define>
</ui:composition>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:p="http://primefaces.org/ui">
<composite:interface />
<composite:implementation>
<p:confirmDialog global="true" showEffect="fade" hideEffect="fade" styleClass="box-solid box-danger">
<p:commandButton value="Yes" type="button" styleClass="btn-material btn-primary ui-confirmdialog-yes"
icon="fa fa-check"/>
<p:commandButton value="No" type="button" styleClass="btn-material btn-danger ui-confirmdialog-no"
icon="fa fa-close"/>
</p:confirmDialog>
</composite:implementation>
</html>

View File

@ -0,0 +1,18 @@
/*
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
*/
/*
Created on : 24.10.2018, 19:31:57
Author : Joern Muehlencord <joern at muehlencord.de>
*/
.watermark {
position: absolute;
opacity: 0.25;
font-size: 3em;
width: 100%;
text-align: center;
z-index: 1000;
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Account Management</title>
</head>
<body>
<ui:composition>
&copy; Joern Muehlencord - Account Management - version ${applicationController.version} - build date ${applicationController.buildDate}
</ui:composition>
</body>
</html>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:shiro="http://shiro.apache.org/tags">
<shiro:authenticated>
<ul class="sidebar-menu tree" data-widget="tree">
<li>
<p:link outcome="/web/index.xhtml">
<i class="fa fa-tablet"></i>
<span>Application</span>
</p:link>
</li>
<li>
<p:link outcome="/web/permissions.xhtml">
<i class="fa fa-list-ul"></i>
<span>Permissions</span>
</p:link>
</li>
<li>
<p:link outcome="/web/roles.xhtml">
<i class="fa fa-circle"></i>
<span>Roles</span>
</p:link>
</li>
<li>
<p:link outcome="/web/account.xhtml">
<i class="fa fa-user"></i>
<span>Accounts</span>
</p:link>
</li>
<li>
<p:commandLink target="/logout.xhtml" actionListener="#{loginView.logout}">
<i class="fa fa-sign-out"></i>
<span>Logout</span>
</p:commandLink>
</li>
</ul>
</shiro:authenticated>
</ui:composition>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2018 joern@muehlencord.de
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/admin.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<ui:define name="head">
<title>Product Catalog Designer</title>
<link rel="shortcut icon" href="#{resource['images/favicon/favicon.ico']}" />
<h:outputStylesheet name="css/admin.css" />
</ui:define>
<ui:define name="logo-lg">
Account Management
</ui:define>
<ui:define name="logo-mini">
AM
</ui:define>
<ui:define name="menu">
<ui:include src="/resources/template/leftmenu.xhtml"/>
</ui:define>
<ui:define name="footer">
<ui:include src="/resources/template/footer.xhtml"/>
</ui:define>
<ui:define name="content-end">
<h:outputLabel styleClass="watermark" rendered="#{instanceView.developmentVersion}" value="#{instanceView.instanceName}" />
</ui:define>
</ui:composition>

View File

@ -0,0 +1,251 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/resources/template/template.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:co="http://java.sun.com/jsf/composite/composite"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:composite="http://xmlns.jcp.org/jsf/composite/composite">
<ui:define name="title">
Account Overview
</ui:define>
<ui:define name="description">
List all accounts
</ui:define>
<ui:define name="body">
<h:form id="accountForm">
<p:dataTable id="accountTable" value="#{accountView.accounts}" var="account" rowKey="#{account.username}" selectionMode="single" selection="#{accountView.currentAccount}"
styleClass="box-primary">
<p:ajax event="rowSelect" update="deleteButton,editButton" listener="#{accountView.selectAccount}" />
<p:ajax event="rowUnselect" update="deleteButton,editButton" listener="#{accountView.deselectAccount}" />
<p:column headerText="Username">
<h:outputText value="#{account.username}" />
</p:column>
<p:column headerText="Lastname">
<h:outputText value="#{account.lastname}" />
</p:column>
<p:column headerText="Firstname">
<h:outputText value="#{account.firstname}" />
</p:column>
<p:column headerText="Email">
<h:outputText value="#{account.emailaddress}" />
</p:column>
<p:column headerText="Last login">
<h:outputText value="#{account.lastLogin}" />
</p:column>
<p:column headerText="Status">
<h:outputText value="#{account.status}" />
</p:column>
<p:column headerText="CreatedOn">
<h:outputText value="#{account.createdOn}" >
<f:convertDateTime type="both" dateStyle="full" timeStyle="short" timeZone="Europe/Berlin"/>
</h:outputText>
</p:column>
<p:column headerText="CreatedBy">
<h:outputText value="#{account.createdBy}" />
</p:column>
<p:column headerText="LastUpdatedOn">
<h:outputText value="#{account.lastUpdatedOn}">
<f:convertDateTime type="both" dateStyle="full" timeStyle="short" timeZone="Europe/Berlin"/>
</h:outputText>
</p:column>
<p:column headerText="LastUpdatedBy">
<h:outputText value="#{account.lastUpdatedBy}" />
</p:column>
<f:facet name="footer" >
<div class="col-sm-12 col-md-3" style="margin-top:10px">
<p:spacer height="10px" />
<div class="ui-inputgroup" >
<h:outputLabel for="includeDisabledCheckbox" value="Include disabled accounts?" />
<p:inputSwitch id="includeDisabledCheckbox" value="#{accountView.showDisabledAccounts}" styleClass="btn-teal btn-block" >
<p:ajax listener="#{accountView.showDisabledAccountsChange}" update="accountTable" />
</p:inputSwitch>
</div>
</div>
<div class="col-sm-12 col-md-3">
<p:spacer height="10px" />
<p:commandButton value="New" id="newButton" icon="fa fa-plus"
update="editDialog" oncomplete="PF('editDialogVar').show();"
actionListener="#{accountView.newAccount}" styleClass="btn-primary btn-block" />
</div>
<div class="col-sm-12 col-md-3">
<p:spacer height="10px" />
<p:commandButton value="Edit" id="editButton" icon="fa fa-pencil"
update="editDialog" oncomplete="PF('editDialogVar').show();"
actionListener="#{accountView.editAccount}" disabled="#{!accountView.accountSelected}" styleClass="btn-teal btn-block" />
</div>
<div class="col-sm-12 col-md-3">
<p:spacer height="10px" />
<p:commandButton value="Delete" id="deleteButton" icon="fa fa-fw fa-trash-o"
update=":accountForm:accountTable" action="#{accountView.deleteAccount}" disabled="#{!accountView.accountSelected}" styleClass="btn-danger btn-block">
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" />
</p:commandButton>
</div>
</f:facet>
</p:dataTable>
<composite:confirmationDialog />
</h:form>
<p:dialog id="editDialog" widgetVar="editDialogVar" header="Edit account" width="600"
modal="true" appendTo="@(body)" showEffect="fade" hideEffect="fade" styleClass="box-solid box-primary" >
<h:form id="editDialogForm">
<p:messages id="editDialogMessages" showDetail="true" showIcon="true" showSummary="true">
<p:autoUpdate />
</p:messages>
<div class="ui-g ui-fluid">
<div class="col-sm-12 col-md-3">
<p:outputLabel for="username" value="Username" />
</div>
<div class="col-sm-12 col-md-6">
<c:if test="#{accountView.currentAccount.createdBy != null}">
<h:outputText id="username" value="#{accountView.currentAccount.username}" />
</c:if>
<c:if test="#{accountView.currentAccount.createdBy == null}">
<p:inputText id="username" value="#{accountView.currentAccount.username}" />
</c:if>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="username"><p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="lastname" value="Lastname" />
</div>
<div class="col-sm-12 col-md-6">
<p:inputText id="lastname" value="#{accountView.currentAccount.lastname}" size="40" maxlength="100"/>
</div>
<div class="col-sm-12 col-md-3 ">
<p:message for="lastname"> <p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="firstname" value="Firstname" />
</div>
<div class="col-sm-12 col-md-6">
<p:inputText id="firstname" value="#{accountView.currentAccount.firstname}" size="40" maxlength="100" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="firstname"> <p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="emailaddress" value="emailaddress" />
</div>
<div class="col-sm-12 col-md-6">
<p:inputText id="emailaddress" value="#{accountView.currentAccount.emailaddress}" size="40" maxlength="200">
<f:validator validatorId="de.muehlencord.shared.jeeutil.validator.EmailValidator" />
</p:inputText>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="emailaddress"> <p:autoUpdate /></p:message>
</div>
<c:if test="#{accountView.currentAccount.username != null}">
<div class="col-sm-12 col-md-3">
<p:outputLabel for="status" value="Status" />
</div>
<div class="col-sm-12 col-md-6">
<p:selectOneMenu id="status" value="#{accountView.currentAccount.status}" >
<f:selectItems value="#{accountView.statusList}" />
</p:selectOneMenu>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="status" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="lastlogin" value="Lastlogin" />
</div>
<div class="col-sm-12 col-md-3">
<h:outputText id="lastlogin" value="#{accountView.currentAccount.lastLogin}" />
</div>
<div class="col-sm-12 col-md-6">
<p:message for="lastlogin" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="createdon" value="Created on" />
</div>
<div class="col-sm-12 col-md-6">
<h:outputText id="createdon" value="#{accountView.currentAccount.createdOn}" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="createdon" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="createdby" value="Created by" />
</div>
<div class="col-sm-12 col-md-6">
<h:outputText id="createdby" value="#{accountView.currentAccount.createdBy}" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="createdby" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="lastupdatedon" value="Last updated on" />
</div>
<div class="col-sm-12 col-md-6">
<h:outputText id="lastupdatedon" value="#{accountView.currentAccount.lastUpdatedOn}" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="lastupdatedon" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="lastupdatedby" value="Last updated by" />
</div>
<div class="col-sm-12 col-md-6">
<h:outputText id="lastupdatedby" value="#{accountView.currentAccount.lastUpdatedBy}" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="lastupdatedby" />
</div>
</c:if>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="roles" value="Roles" />
</div>
<div class="col-sm-12 col-md-6">
<p:selectManyMenu id="roles" var="role" label="#{role.roleName}" value="#{accountView.currentAccountRoles}" converter="omnifaces.SelectItemsConverter" required="true" >
<f:selectItems value="#{accountView.allApplicationRoles}" var="roleItem" itemLabel="#{roleItem.roleName}" itemValue="#{role}" />
<p:column>
<h:outputText value="#{role.roleName}"/>
</p:column>
</p:selectManyMenu>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="roles" />
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Save" action="#{accountView.saveEditAccount}" styleClass="btn-primary btn-block"
oncomplete="if (args &amp;&amp; !args.validationFailed) PF('editDialogVar').hide();" update=":accountForm:accountTable" />
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Cancel" action="#{accountView.cancelEditAccount}" immediate="true" styleClass="btn-teal btn-block"
oncomplete="PF('editDialogVar').hide();" />
</div>
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/resources/template/template.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:co="http://java.sun.com/jsf/composite/composite"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:composite="http://xmlns.jcp.org/jsf/composite/composite">
<ui:define name="title">
Applications
</ui:define>
<ui:define name="body" >
<h:form id="applicationForm">
<p:panel styleClass="box-solid">
<div class="ui-g ui-fluid">
<div class="col-sm-12 col-md-6">
<p:selectOneMenu id="applicationSelect" value="#{applicationView.currentApplication}" converter="omnifaces.SelectItemsConverter" required="true">
<f:selectItems value="#{applicationView.allApplications}" var="app" itemLabel="#{app.applicationName}" itemValue="#{app}" />
</p:selectOneMenu>
</div>
<div class="col-sm-12 col-md-3">
<p:commandButton value="Select" styleClass="btn-primary btn-solid}" actionListener="#{applicationView.selectApplication}" />
</div>
<div class="col-sm-12 col-md-3">
<p:commandButton value="New" id="newButton" icon="fa fa-plus"
update="editDialog" oncomplete="PF('editDialogVar').show();"
actionListener="#{applicationView.newApplication}" styleClass="btn-teal btn-block" />
</div>
</div>
</p:panel>
</h:form>
<p:dialog id="editDialog" widgetVar="editDialogVar" header="Edit account" width="600"
modal="true" appendTo="@(body)" showEffect="fade" hideEffect="fade" styleClass="box-solid box-primary" >
<h:form id="editDialogForm">
<p:messages id="editDialogMessages" showDetail="true" showIcon="true" showSummary="true">
<p:autoUpdate />
</p:messages>
<div class="ui-g ui-fluid">
<div class="col-sm-12 col-md-3">
<p:outputLabel for="applicationName" value="Application name" />
</div>
<div class="col-sm-12 col-md-6">
<p:inputText id="applicationName" value="#{applicationView.editApplication.applicationName}">
<f:validator validatorId="uniqueApplicationValidator"/>
<f:attribute name="applicationName" value="#{applicationView.editApplication.applicationName}" />
</p:inputText>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="applicationName"><p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Save" action="#{applicationView.saveEditApplication}" styleClass="btn-primary btn-block"
oncomplete="if (args &amp;&amp; !args.validationFailed) PF('editDialogVar').hide();" update=":applicationForm" />
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Cancel" action="#{applicationView.cancelEditApplication}" immediate="true" styleClass="btn-teal btn-block"
oncomplete="PF('editDialogVar').hide();" />
</div>
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/resources/template/template.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:co="http://java.sun.com/jsf/composite/composite"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:composite="http://xmlns.jcp.org/jsf/composite/composite">
<ui:define name="title">
Permissions
</ui:define>
<ui:define name="description">
Edit permissions
</ui:define>
<ui:define name="body">
<h:form id="permissionForm">
<p:panel styleClass="card no-border">
<div class="ui-g ui-fluid">
<div class="ui-g-12 ui-md-3">
<div class="ui-inputgroup">
<span class="ui-inputgroup-addon"><i style="font-size: 20px" class="fa fa-edit"></i></span>
<p:inputText id="newName" value="#{permissionView.newPermissionName}" maxlength="80" size="30" placeholder="#{msgs.label_name}" />
</div>
</div>
<div class="ui-g-12 ui-md-3">
<div class="ui-inputgroup">
<span class="ui-inputgroup-addon"><i style="font-size: 20px" class="fa fa-edit"></i></span>
<p:inputText id="newDescription" value="#{permissionView.newPermissionDescription}" maxlength="200" size="30" placeholder="#{msgs.label_description}" />
</div>
</div>
<div class="ui-g-12 ui-md-2">
<p:commandButton icon="fa fa-fw fa-save" value="#{msgs.button_save}" action="#{permissionView.savePermission}"
update="permissionForm" styleClass="btn-primary btn-block" />
</div>
<div class="ui-g-12 ui-md-2">
<p:commandButton id="editPermissionButton" icon="fa fa-fw fa-pencil" value="#{msgs.button_edit}" action="#{permissionView.editPermission}"
update="permissionForm" styleClass="btn-teal btn-block" disabled="#{!permissionView.canEdit}" />
</div>
<div class="ui-g-12 ui-md-2">
<p:commandButton id="deletePermissionButton" icon="fa fa-fw fa-trash-o" value="#{msgs.button_delete}" action="#{permissionView.deletePermission}"
update="permissionForm" styleClass="btn-danger btn-block" disabled="#{!permissionView.canDelete}">
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-fw fa-exclamation-triangle" />
</p:commandButton>
</div>
</div>
<p:dataTable id="permissionTable" value="#{permissionView.appPermissions}" var="permission" rowKey="#{permission.id}"
selectionMode="single" selection="#{permissionView.currentPermission}" styleClass="box-primary">
<p:ajax event="rowSelect" update=":permissionForm" listener="#{permissionView.selectPermission}" />
<p:ajax event="rowUnselect" update=":permissionForm" listener="#{permissionView.deselectPermission}" />
<p:column headerText="Permission name">
<h:outputText value="#{permission.permissionName}" />
</p:column>
<p:column headerText="Permission description">
<h:outputText value="#{permission.permissionDescription}" />
</p:column>
</p:dataTable>
<composite:confirmationDialog />
</p:panel>
</h:form>
</ui:define>
</ui:composition>

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/resources/template/template.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:co="http://java.sun.com/jsf/composite/composite"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:composite="http://xmlns.jcp.org/jsf/composite/composite">
<ui:define name="title">
Group Overview
</ui:define>
<ui:define name="description">
List all groups
</ui:define>
<ui:define name="body">
<h:form id="groupForm">
<p:panel styleClass="card no-border">
<div class="ui-g ui-fluid">
<div class="ui-g-12 ui-md-3">
<div class="ui-inputgroup">
<span class="ui-inputgroup-addon"><i style="font-size: 20px" class="fa fa-user"></i></span>
<p:inputText id="newName" value="#{groupView.newRoleName}" placeholder="#{msgs.label_name}" maxlength="80" size="30" />
</div>
</div>
<div class="ui-g-12 ui-md-3">
<div class="ui-inputgroup">
<span class="ui-inputgroup-addon"><i style="font-size: 20px" class="fa fa-user"></i></span>
<p:inputText id="newDescription" value="#{groupView.newRoleDescription}" placeholder="#{msgs.label_description}" maxlength="200" size="40" />
</div>
</div>
<div class="ui-g-12 ui-md-2">
<p:commandButton icon="fa fa-fw fa-plus" value="#{msgs.button_save}" action="#{groupView.newRole}" update="groupForm" styleClass="btn-primary btn-block"/>
</div>
<div class="ui-g-12 ui-md-2">
<p:commandButton icon="fa fa-fw fa-pencil" value="#{msgs.button_edit}" action="#{groupView.editRole}" update="groupForm" styleClass="btn-teal btn-block"/>
</div>
<div class="ui-g-12 ui-md-2">
<p:commandButton icon="fa fa-fw fa-trash-o" value="#{msgs.button_delete}" action="#{groupView.deleteRole}" update="groupForm" styleClass="btn-danger btn-block">
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-fw fa-exclamation-triangle" />
</p:commandButton>
</div>
</div>
</p:panel>
<p:dataTable id="groupTable" value="#{groupView.allRoles}" var="role" rowKey="#{role.id}" styleClass="box-solid box-primary"
selectionMode="single" selection="#{groupView.currentRole}">
<p:ajax event="rowSelect" update=":groupForm:permissionTable" listener="#{groupView.onRoleSelect}" />
<p:column headerText="Role name">
<h:outputText value="#{role.roleName}" />
</p:column>
<p:column headerText="Role description">
<h:outputText value="#{role.roleDescription}" />
</p:column>
</p:dataTable>
<p:dataTable id="permissionTable" value="#{groupView.rolePermissions}" var="permission" rowKey="#{permission.id}" styleClass="box-teal"
selectionMode="single" selection="#{groupView.currentPermission}">
<p:ajax event="rowSelect" update="deletePermissionButton" listener="#{groupView.selectPermission}" />
<p:ajax event="rowUnselect" update="deletePermissionButton" listener="#{groupView.deselectPermission}" />
<p:column headerText="Permission name">
<h:outputText value="#{permission.permissionName}" />
</p:column>
<p:column headerText="Permission description">
<h:outputText value="#{permission.permissionDescription}" />
</p:column>
<f:facet name="footer" >
<p:selectOneMenu value="#{groupView.newPermission}" converter="omnifaces.SelectItemsConverter" >
<f:selectItems id="permissionListItems" value="#{groupView.missingPermissions}" var="missingPermission" itemLabel="#{missingPermission.permissionName}" itemValue="#{missingPermission}" />
</p:selectOneMenu>
<div class="ui-g-12 ui-md-2">
<p:commandButton id="addPermissionButton" icon="fa fa-plus" value="#{msgs.button_new}" action="#{groupView.addRolePermission}"
update=":groupForm:permissionTable" styleClass="btn-primary btn-block"/>
</div>
<div class="ui-g-12 ui-md-2">
<p:commandButton id="deletePermissionButton" icon="fa fa-trash-o" value="Delete" update=":groupForm:groupTable,:groupForm:permissionTable"
action="#{groupView.removeRolePermission}" styleClass="btn-danger btn-block"
disabled="#{!groupView.isPermissionSelected}" >
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-fw fa-exclamation-triangle" />
</p:commandButton>
</div>
</f:facet>
</p:dataTable>
<composite:confirmationDialog />
</h:form>
</ui:define>
</ui:composition>