Commit 8930f7aa by Tuomas Riihimäki

Refactor and fix user searching with role.

1 parent 2b19d7ba
...@@ -22,6 +22,7 @@ import java.io.IOException; ...@@ -22,6 +22,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.ejb.Local; import javax.ejb.Local;
...@@ -216,4 +217,6 @@ public interface UserBeanLocal { ...@@ -216,4 +217,6 @@ public interface UserBeanLocal {
* @return Eventusers for all events this user has been associated to. * @return Eventusers for all events this user has been associated to.
*/ */
List<EventUser> findAllEventusers(User user); List<EventUser> findAllEventusers(User user);
Map<Role,List<String>> findUsersRolesWithReason(EventUser user);
} }
...@@ -186,7 +186,7 @@ public class UserBean implements UserBeanLocal { ...@@ -186,7 +186,7 @@ public class UserBean implements UserBeanLocal {
@Override @Override
public boolean setUsersLocale(String locale) { public boolean setUsersLocale(String locale) {
if(permbean.getCurrentUser().isAnonymous()) { if (permbean.getCurrentUser().isAnonymous()) {
return false; return false;
} }
...@@ -234,6 +234,13 @@ public class UserBean implements UserBeanLocal { ...@@ -234,6 +234,13 @@ public class UserBean implements UserBeanLocal {
} }
@Override
@RolesAllowed(UserPermission.S_VIEW_ALL)
public Map<Role, List<String>> findUsersRolesWithReason(EventUser u) {
return localFindUsersRolesWithReason(u);
}
// private EventUser currentEventuser; // private EventUser currentEventuser;
// private ArrayList<Role> currentEventuserRoles; // private ArrayList<Role> currentEventuserRoles;
...@@ -241,6 +248,10 @@ public class UserBean implements UserBeanLocal { ...@@ -241,6 +248,10 @@ public class UserBean implements UserBeanLocal {
// Käytä Viewien puolelta findUsersRoles joka tarkistaa käyttäjän oikeudet // Käytä Viewien puolelta findUsersRoles joka tarkistaa käyttäjän oikeudet
// ensin. // ensin.
public Set<Role> localFindUsersRoles(EventUser u) { public Set<Role> localFindUsersRoles(EventUser u) {
return localFindUsersRolesWithReason(u).keySet();
}
public HashMap<Role, List<String>> localFindUsersRolesWithReason(EventUser u) {
// if (currentEventuser != null && u.equals(currentEventuser)) { // if (currentEventuser != null && u.equals(currentEventuser)) {
// logger.debug("Returnin cached eventuserroles for user {}: {}", // logger.debug("Returnin cached eventuserroles for user {}: {}",
// currentEventuser, currentEventuserRoles); // currentEventuser, currentEventuserRoles);
...@@ -248,26 +259,27 @@ public class UserBean implements UserBeanLocal { ...@@ -248,26 +259,27 @@ public class UserBean implements UserBeanLocal {
// } // }
LanEvent event = u.getEvent(); LanEvent event = u.getEvent();
Set<Role> checkedRoles = new HashSet<Role>(); //Set<Role> checkedRoles = new HashSet<Role>();
HashMap<Role, List<String>> checkedRoles = new HashMap<>();
if (u != null) { if (u != null) {
addRecursive(checkedRoles, rolefacade.findForUser(u)); addRecursive(checkedRoles, rolefacade.findForUser(u), "DIRECT");
addRecursive(checkedRoles, orgRoleFacade.findRolesForUser(u)); addRecursive(checkedRoles, orgRoleFacade.findRolesForUser(u), "ORG_ROLE");
if (permbean.isLoggedIn()) { if (permbean.isLoggedIn()) {
// add roles from events default role. // add roles from events default role.
addRecursive(checkedRoles, event.getDefaultRole()); addRecursive(checkedRoles, event.getDefaultRole(), "EVENT_DEFAULT");
} }
if (!u.isAnonymous()) { if (!u.isAnonymous()) {
// add roles from accountEvents of the user // add roles from accountEvents of the user
addRecursive(checkedRoles, productbean.getRolesFromAccountEvents(u)); addRecursive(checkedRoles, productbean.getRolesFromAccountEvents(u), "ACCOUNTEVENT");
for (GroupMembership member : gmfacade.findMemberships(u)) { for (GroupMembership member : gmfacade.findMemberships(u)) {
if (member != null && member.getPlaceReservation() != null) { if (member != null && member.getPlaceReservation() != null) {
addRecursive(checkedRoles, member.getPlaceReservation().getProvidesRole()); addRecursive(checkedRoles, member.getPlaceReservation().getProvidesRole(), "PLACE");
if (member.getPlaceReservation().getProduct() != null) { if (member.getPlaceReservation().getProduct() != null) {
addRecursive(checkedRoles, member.getPlaceReservation().getProduct().getProvides()); addRecursive(checkedRoles, member.getPlaceReservation().getProduct().getProvides(), "PLACE_PRODUCT");
} }
} }
} }
...@@ -283,20 +295,28 @@ public class UserBean implements UserBeanLocal { ...@@ -283,20 +295,28 @@ public class UserBean implements UserBeanLocal {
return checkedRoles; return checkedRoles;
} }
private void addRecursive(Set<Role> checkedRoles, Collection<Role> roles) { public void addRecursive(Map<Role, List<String>> checkedRoles, Collection<Role> roles, String source) {
for (Role r : roles) { for (Role r : roles) {
addRecursive(checkedRoles, r); addRecursive(checkedRoles, r, source);
} }
} }
private void addRecursive(Set<Role> checkedRoles, Role role) { public void addRecursive(Map<Role, List<String>> checkedRoles, Role role, String source) {
if (role == null || checkedRoles.contains(role)) { if (role == null) {
return; return;
} }
checkedRoles.add(role);
List<String> reasons = checkedRoles.get(role);
if (reasons == null) {
reasons = new ArrayList<>();
checkedRoles.put(role, reasons);
for (Role r : role.getParents()) { for (Role r : role.getParents()) {
addRecursive(checkedRoles, r); addRecursive(checkedRoles, r, source);
} }
}
reasons.add(source);
} }
...@@ -963,11 +983,11 @@ public class UserBean implements UserBeanLocal { ...@@ -963,11 +983,11 @@ public class UserBean implements UserBeanLocal {
@Override @Override
public boolean isUserInRole(EventUser user, Integer roleId) { public boolean isUserInRole(EventUser user, Integer roleId) {
Set<Role> roles = localFindUsersRoles(user); HashMap<Role, List<String>> roles = localFindUsersRolesWithReason(user);
logger.info("CHecking user {} roleid {} from roles {}, roles size{}", new Object[]{user, roleId, roles, roles.size()}); logger.info("CHecking user {} roleid {} from roles {}, roles size{}", new Object[]{user, roleId, roles, roles.size()});
addRecursive(roles, eventBean.getCurrentEvent().getDefaultRole()); addRecursive(roles, eventBean.getCurrentEvent().getDefaultRole(), "DEFAULT");
for (Role r : roles) { for (Role r : roles.keySet()) {
if (roleId.equals(r.getId())) { if (roleId.equals(r.getId())) {
logger.info("User {} found in role {}", user, roleId); logger.info("User {} found in role {}", user, roleId);
return true; return true;
...@@ -1188,7 +1208,6 @@ public class UserBean implements UserBeanLocal { ...@@ -1188,7 +1208,6 @@ public class UserBean implements UserBeanLocal {
return eventUserFacade.findForUser(user); return eventUserFacade.findForUser(user);
} }
@Override @Override
@RolesAllowed(EventPermission.S_MANAGE_EVENT) @RolesAllowed(EventPermission.S_MANAGE_EVENT)
public EventUser getUserByAuthcode(String authcode) { public EventUser getUserByAuthcode(String authcode) {
......
...@@ -56,12 +56,14 @@ public class AccountEventFacade extends IntegerPkGenericFacade<AccountEvent> { ...@@ -56,12 +56,14 @@ public class AccountEventFacade extends IntegerPkGenericFacade<AccountEvent> {
CriteriaQuery<Role> cq = cb.createQuery(Role.class); CriteriaQuery<Role> cq = cb.createQuery(Role.class);
Root<AccountEvent> root = cq.from(AccountEvent.class); Root<AccountEvent> root = cq.from(AccountEvent.class);
Path<Role> role = root.get(AccountEvent_.product).get(Product_.provides); Path<Product> prodPath = root.get(AccountEvent_.product);
Path<Role> role = prodPath.get(Product_.provides);
cq.select(role); cq.select(role);
cq.where( cq.where(
cb.equal(role.get(Role_.event), event), cb.equal(role.get(Role_.event), event),
cb.equal(root.get(AccountEvent_.user), u) cb.equal(root.get(AccountEvent_.user), u)
,cb.isEmpty(prodPath.get(Product_.places))
); );
// TypedQuery<Role> q = // TypedQuery<Role> q =
......
...@@ -18,45 +18,32 @@ ...@@ -18,45 +18,32 @@
*/ */
package fi.codecrew.moya.facade.callbacks; package fi.codecrew.moya.facade.callbacks;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import javax.persistence.criteria.*;
import fi.codecrew.moya.model.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import fi.codecrew.moya.model.AccountEvent_;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.EventUser_;
import fi.codecrew.moya.model.GroupMembership_;
import fi.codecrew.moya.model.Place_;
import fi.codecrew.moya.model.Product_;
import fi.codecrew.moya.model.Role;
import fi.codecrew.moya.model.Role_;
import fi.codecrew.moya.utilities.jpa.FacadeCallback; import fi.codecrew.moya.utilities.jpa.FacadeCallback;
public class EventUserRolefilter implements FacadeCallback<EventUser> { public class EventUserRolefilter implements FacadeCallback<EventUser> {
private final List<Role> roles; private final List<Role> roles;
private static final Logger logger = LoggerFactory.getLogger(EventUserRolefilter.class); private static final Logger logger = LoggerFactory.getLogger(EventUserRolefilter.class);
private final LanEvent event;
public EventUserRolefilter(List<Role> filters) { public EventUserRolefilter(List<Role> filters) {
roles = filters; roles = Collections.unmodifiableList(filters);
event = roles.get(0).getEvent();
} }
private static final Set<Integer> getAllChildren(Collection<Role> roles, Set<Integer> checkedRoles) { private static final Set<Integer> getAllChildren(Collection<Role> roles, Set<Integer> checkedRoles) {
if (checkedRoles == null) {
for (Role role : roles) checkedRoles = new HashSet<>();
{ }
for (Role role : roles) {
if (role == null || checkedRoles.contains(role.getId())) { if (role == null || checkedRoles.contains(role.getId())) {
continue; continue;
} }
...@@ -66,40 +53,112 @@ public class EventUserRolefilter implements FacadeCallback<EventUser> { ...@@ -66,40 +53,112 @@ public class EventUserRolefilter implements FacadeCallback<EventUser> {
return checkedRoles; return checkedRoles;
} }
private static final Set<Integer> getAllParents(Collection<Role> roles, Set<Integer> checkedRoles) {
if (checkedRoles == null) {
checkedRoles = new HashSet<>();
}
for (Role role : roles) {
if (role == null || checkedRoles.contains(role.getId())) {
continue;
}
checkedRoles.add(role.getId());
getAllParents(role.getParents(), checkedRoles);
}
return checkedRoles;
}
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<EventUser> root, List<Predicate> predicates, boolean isFullQuery) { public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<EventUser> root, List<Predicate> predicates, boolean isFullQuery) {
if (roles != null && !roles.isEmpty()) if (roles == null || roles.isEmpty()) {
{ return;
HashSet<Integer> roleids = new HashSet<Integer>(); }
getAllChildren(roles, roleids); Set<Integer> roleWChildrenIds = getAllChildren(roles, null);
logger.debug("Requiring roles {}", roleids);
Set<Integer> roleWParentsIds = getAllParents(roles, null);
logger.warn("roles with children: {}, roles with parent {}", roleWChildrenIds, roleWParentsIds);
Path<Integer> rootId = root.get(EventUser_.id); Path<Integer> rootId = root.get(EventUser_.id);
ArrayList<Predicate> orPreds = new ArrayList<Predicate>(); ArrayList<Predicate> orPreds = new ArrayList<Predicate>();
/**
* Find all users that have a role "forced" directly to the user
* If role has parents, user belongs also to them, so also parents are included
*/
{ {
Subquery<Integer> subq = cq.subquery(Integer.class); Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class); Root<Role> subroot = subq.from(Role.class);
subq.select(subroot.join(Role_.users).get(EventUser_.id)); subq.select(subroot.join(Role_.users).get(EventUser_.id));
subq.where(subroot.get(Role_.id).in(roleids));
// Root<Role> rolePath = subq.correlate(roleRoot);
subq.where(subroot.get(Role_.id).in(roleWChildrenIds));
orPreds.add(rootId.in(subq)); orPreds.add(rootId.in(subq));
} }
/**
* Find all products that provide a given role, or a parent of the role via accountevents
* NOTE! Products that have places, do not provide roles to users
*/
{ {
Subquery<Integer> subq = cq.subquery(Integer.class); Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class); Root<Role> subroot = subq.from(Role.class);
subq.select(subroot.join(Role_.productsProvide).join(Product_.accountEvents).get(AccountEvent_.user).get(EventUser_.id)); ListJoin<Role, Product> prodsPath = subroot.join(Role_.productsProvide);
subq.where(subroot.get(Role_.id).in(roleids)); subq.select(prodsPath.join(Product_.accountEvents).get(AccountEvent_.user).get(EventUser_.id));
subq.where(
subroot.get(Role_.id).in(roleWChildrenIds),
cb.isEmpty(prodsPath.get(Product_.places))
);
orPreds.add(rootId.in(subq)); orPreds.add(rootId.in(subq));
} }
/**
* Roles provided by products via places user has been given to.
*/
{ {
Subquery<Integer> subq = cq.subquery(Integer.class); Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class); Root<Role> subroot = subq.from(Role.class);
subq.select(subroot.join(Role_.productsProvide).join(Product_.places).get(Place_.placeReserver).get(GroupMembership_.user).get(EventUser_.id)); subq.select(subroot.join(Role_.productsProvide).join(Product_.places).get(Place_.placeReserver).get(GroupMembership_.user).get(EventUser_.id));
subq.where(subroot.get(Role_.id).in(roleids)); subq.where(subroot.get(Role_.id).in(roleWChildrenIds));
orPreds.add(rootId.in(subq));
}
/** Roles provided by places user has been given to.
*/
{
Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class);
subq.select(subroot.join(Role_.placesProvide).get(Place_.placeReserver).get(GroupMembership_.user).get(EventUser_.id));
subq.where(subroot.get(Role_.id).in(roleWChildrenIds));
orPreds.add(rootId.in(subq)); orPreds.add(rootId.in(subq));
} }
predicates.add(cb.or(orPreds.toArray(new Predicate[orPreds.size()]))); /** Find all roles provided by organisation roles
*
*/
{
Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class);
subroot.get(Role_.orgRoles);
ListJoin<OrgRole, User> orgRoleUser = subroot.join(Role_.orgRoles).join(OrgRole_.users);
ListJoin<User, EventUser> euJoin = orgRoleUser.join(User_.eventusers);
subq.select(euJoin.get(EventUser_.id));
subq.where(
cb.equal(euJoin.get(EventUser_.event), event),
subroot.get(Role_.id).in(roleWChildrenIds));
orPreds.add(rootId.in(subq));
} }
predicates.add(cb.or(orPreds.toArray(new Predicate[orPreds.size()])));
} }
} }
...@@ -138,6 +138,18 @@ public class User extends GenericEntity implements IUser { ...@@ -138,6 +138,18 @@ public class User extends GenericEntity implements IUser {
@OrderBy() @OrderBy()
private List<LicenseCode> licenseCodes; private List<LicenseCode> licenseCodes;
@OneToMany(mappedBy="user", fetch = FetchType.LAZY)
private List<EventUser> eventusers;
private List<EventUser> getEventusers(){
throw new RuntimeException("We never want to fetch this. Only here for metamodel");
}
private void setEventusers(List<EventUser> eventusers){
throw new RuntimeException("We never want to fetch this. Only here for metamodel");
}
@Transient @Transient
private static final Logger logger = LoggerFactory.getLogger(User.class); private static final Logger logger = LoggerFactory.getLogger(User.class);
......
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui">
<h:body>
<ui:composition template="#{sessionHandler.template}">
<f:metadata>
<f:event type="preRenderView"
listener="#{applicationApiView.initApplicationListView}" />
</f:metadata>
<ui:define name="content">
<button></button>
<div style="display:none;" id="createApp">
</div>
<h1>#{i18n['apiapp.edit.applist']}</h1>
<p:dataTable value="#{applicationApiView.applist}" var="app">
<p:column headerText="#{i18n['apiapp.name']}">
<h:outputText value="#{app.name}" />
</p:column>
<p:column headerText="#{i18n['apiapp.description']}">
<h:outputText value="#{app.description}" />
</p:column>
<p:column>
<h:outputText value="#{app.created}">
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}"
timeZone="#{sessionHandler.timezone}" />
</h:outputText>
</p:column>
<p:column headerText="#{i18n['apiapp.enabled']}">
<h:outputText value="#{app.enabled}" />
</p:column>
</p:dataTable>
</ui:define>
</ui:composition>
</h:body>
</html>
\ No newline at end of file
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
<h:body> <h:body>
<ui:composition template="#{sessionHandler.template}"> <ui:composition template="#{sessionHandler.template}">
<f:metadata> <f:metadata>
<f:viewParam name="userid" value="#{userView.userid}" /> <f:viewParam name="userid" value="#{userView.userid}"/>
<f:event type="preRenderView" listener="#{userView.initView}" /> <f:event type="preRenderView" listener="#{userView.initView}"/>
<f:event type="preRenderView" listener="#{userView.setCaptureForwardUrl('')}" /> <f:event type="preRenderView" listener="#{userView.setCaptureForwardUrl('')}"/>
</f:metadata> </f:metadata>
<ui:define name="title"> <ui:define name="title">
...@@ -16,27 +16,41 @@ ...@@ -16,27 +16,41 @@
<!-- <users:usertabs tabId="edit" /> --> <!-- <users:usertabs tabId="edit" /> -->
</ui:define> </ui:define>
<ui:define name="edittab"> <ui:define name="edittab">
<users:usertabs tabId="edit" /> <users:usertabs tabId="edit"/>
</ui:define> </ui:define>
<ui:define name="content"> <ui:define name="content">
<users:edit commitaction="#{userCartView.saveUser()}" commitvalue="#{i18n['user.save']}" /> <users:edit commitaction="#{userCartView.saveUser()}" commitvalue="#{i18n['user.save']}"/>
<div style="display: flex;">
<h:form id="roleform" rendered="#{roleView.canReadRoles}"> <h:form id="roleform" rendered="#{roleView.canReadRoles}">
<h2> <h2>
<h:outputText value="#{i18n['user.roles']}:" /> <h:outputText value="#{i18n['user.roles']}:"/>
</h2> </h2>
<h:selectManyCheckbox converter="#{roleConverter}" disabled="#{!roleView.canWriteRoles}" layout="pageDirection" id="roles" value="#{userView.usersRoles}"> <h:selectManyCheckbox converter="#{roleConverter}" disabled="#{!roleView.canWriteRoles}" layout="pageDirection" id="roles" value="#{userView.usersRoles}">
<f:selectItems var="roleitem" itemLabel="#{roleitem.name}" value="#{roleDataView.roles}" /> <f:selectItems var="roleitem" itemLabel="#{roleitem.name}" value="#{roleDataView.roles}"/>
</h:selectManyCheckbox> </h:selectManyCheckbox>
<div> <div>
<h:message rendered="#{roleView.canReadRoles}" for="roles" /> <p:message rendered="#{roleView.canReadRoles}" for="roles"/>
</div> </div>
<h:commandButton action="#{userView.saveRoles}" value="#{i18n['user.saveRoles']}" /> <p:commandButton ajax="false" action="#{userView.saveRoles}" value="#{i18n['user.saveRoles']}"/>
</h:form> </h:form>
<div style="margin-left: 4em;">
<h2>All users roles</h2>
<p:dataTable style="max-width: 600px;" var="r" value="#{userView.allUsersRoles}">
<p:column style="width: 30%;"><f:facet name="header"><h:outputText value="#{i18n['role.name']}"/></f:facet><h:outputText value="#{r.key.name}"/></p:column>
<p:column>
<f:facet name="header">
<h:outputText value="#{i18n['role.source']}"/>
</f:facet>
<ul><ui:repeat var="src" value="#{r.value}">
<li>#{i18n['role.source.'+=src]}</li>
</ui:repeat></ul>
</p:column>
</p:dataTable>
</div>
</div>
</ui:define> </ui:define>
</ui:composition> </ui:composition>
</h:body> </h:body>
......
...@@ -21,9 +21,7 @@ package fi.codecrew.moya.web.cdiview.user; ...@@ -21,9 +21,7 @@ package fi.codecrew.moya.web.cdiview.user;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.enterprise.context.Conversation; import javax.enterprise.context.Conversation;
...@@ -231,6 +229,11 @@ public class UserView extends GenericCDIView { ...@@ -231,6 +229,11 @@ public class UserView extends GenericCDIView {
return null; return null;
} }
public ArrayList<Map.Entry<Role, List<String>>> getAllUsersRoles(){
return new ArrayList<>(userbean.findUsersRolesWithReason(user).entrySet());
}
public List<Role> getUserSelectableRoles() { public List<Role> getUserSelectableRoles() {
if (userSelectableRoles == null && user != null) { if (userSelectableRoles == null && user != null) {
userSelectableRoles = rolebean.getRoles(getSelectedUser()); userSelectableRoles = rolebean.getRoles(getSelectedUser());
......
...@@ -1679,3 +1679,11 @@ user.allergies =Allergies / die ...@@ -1679,3 +1679,11 @@ user.allergies =Allergies / die
allergies.save =Save allergies allergies.save =Save allergies
user.eventproperties = user.eventproperties =
submenu.permissionDenied = submenu.permissionDenied =
role.source =
role.source.DIRECT =
role.source.ORG_ROLE =
role.source.PLACE =
role.source.ACCOUNTEVENT =
role.source.PLACE_PRODUCT =
role.source.EVENT_DEFAULT =
user.allroles =
\ No newline at end of file
...@@ -1916,3 +1916,11 @@ user.allergies =Allergies ...@@ -1916,3 +1916,11 @@ user.allergies =Allergies
allergies.save =Save allergies allergies.save =Save allergies
user.eventproperties = Event specific properties user.eventproperties = Event specific properties
submenu.permissionDenied = Access denied submenu.permissionDenied = Access denied
role.source = Role source
role.source.DIRECT = Forced for user
role.source.ORG_ROLE = Organisation role
role.source.PLACE = Place
role.source.ACCOUNTEVENT = Accountevent (Bought product)
role.source.PLACE_PRODUCT = Product via place
role.source.EVENT_DEFAULT = Event default role
user.allroles = All users roles
\ No newline at end of file
...@@ -598,7 +598,7 @@ incomingflow.giveplace = Merkitse annetuksi ...@@ -598,7 +598,7 @@ incomingflow.giveplace = Merkitse annetuksi
incomingflow.groupmemberships = Konepaikat sek\u00E4 liput incomingflow.groupmemberships = Konepaikat sek\u00E4 liput
incomingflow.invalidbarcode.message = Piipatulla koodilla ei l\u00F6ytynyt mit\u00E4\u00E4n, voit lis\u00E4t\u00E4 koodin k\u00E4ytt\u00E4j\u00E4\u00E4n incomingflow.invalidbarcode.message = Piipatulla koodilla ei l\u00F6ytynyt mit\u00E4\u00E4n, voit lis\u00E4t\u00E4 koodin k\u00E4ytt\u00E4j\u00E4\u00E4n
incomingflow.invalidbarcode.title = Virheellinen koodi incomingflow.invalidbarcode.title = Virheellinen koodi
incomingflow.markEverythingGiven=Anna kaikki antamattomat liput incomingflow.markEverythingGiven =Anna kaikki antamattomat liput
incomingflow.multisearch = Monihaku incomingflow.multisearch = Monihaku
incomingflow.placesummary = Paikkayhteenveto incomingflow.placesummary = Paikkayhteenveto
incomingflow.printedCard = Kortti incomingflow.printedCard = Kortti
...@@ -917,6 +917,7 @@ page.game.list.header = Insomnia Game ...@@ -917,6 +917,7 @@ page.game.list.header = Insomnia Game
page.game.start.header = Insomnia Game page.game.start.header = Insomnia Game
page.index.header = Etusivu page.index.header = Etusivu
page.index.pagegroup = etusivu page.index.pagegroup = etusivu
page.permissionDenied.header = P\u00E4\u00E4sy kielletty
page.place.edit.header = Muokkaa paikkaa page.place.edit.header = Muokkaa paikkaa
page.place.insertToken.header = Sy\u00F6t\u00E4 paikkakoodi page.place.insertToken.header = Sy\u00F6t\u00E4 paikkakoodi
page.poll.answer.header = Kysely page.poll.answer.header = Kysely
...@@ -925,7 +926,11 @@ page.poll.start.header = Kysely ...@@ -925,7 +926,11 @@ page.poll.start.header = Kysely
page.product.create.pagegroup = yll\u00E4pito page.product.create.pagegroup = yll\u00E4pito
page.product.createBill.header = Osta tuotteita page.product.createBill.header = Osta tuotteita
page.product.createBill.pagegroup = kauppa page.product.createBill.pagegroup = kauppa
page.product.edit.pagegroup = admin
page.product.list.pagegroup = admin
page.product.validateBillProducts.header = Tilaus luotu page.product.validateBillProducts.header = Tilaus luotu
page.role.create.pagegroup = admin
page.role.edit.pagegroup = admin
page.svm.error.header = Verkkomaksu ep\u00E4onnistui page.svm.error.header = Verkkomaksu ep\u00E4onnistui
page.svm.failure.header = Verkkomaksuvirhe page.svm.failure.header = Verkkomaksuvirhe
page.svm.notification.header = Maksutapahtuman rekister\u00F6inti page.svm.notification.header = Maksutapahtuman rekister\u00F6inti
...@@ -1860,46 +1865,54 @@ voting.create.voteEnd = \u00C4\u00E4nestys kiinni ...@@ -1860,46 +1865,54 @@ voting.create.voteEnd = \u00C4\u00E4nestys kiinni
voting.create.voteStart = \u00C4\u00E4nestys auki voting.create.voteStart = \u00C4\u00E4nestys auki
yes = Kyll\u00E4 yes = Kyll\u00E4
page.product.shopClosed.header=Kauppa on kiinni! page.product.shopClosed.header =Kauppa on kiinni!
page.product.shopClosed.notOpenYet=Tapahtuman lipunmyynti ei ole viel\u00E4 alkanut, Kokeile uudelleen my\u00F6hemmin. page.product.shopClosed.notOpenYet =Tapahtuman lipunmyynti ei ole viel\u00E4 alkanut, Kokeile uudelleen my\u00F6hemmin.
page.product.shopClosed.alreadyClosed=Kauppa on suljettu, tervetuloa uudelleen tuleviin tapahtumiin. page.product.shopClosed.alreadyClosed =Kauppa on suljettu, tervetuloa uudelleen tuleviin tapahtumiin.
queuemgmt.inDatabase=Arvo tietokannassa queuemgmt.inDatabase =Arvo tietokannassa
queuemgmt.biggestFirst=Isoin ryhm\u00E4 ensin queuemgmt.biggestFirst =Isoin ryhm\u00E4 ensin
queuemgmt.biggestIsFirst=Isompi ryhm\u00E4 nousee automaattisesti jonossa edemm\u00E4ksi. queuemgmt.biggestIsFirst =Isompi ryhm\u00E4 nousee automaattisesti jonossa edemm\u00E4ksi.
reservequeue.reservingTimeIsUpAlert=Sinulle varattu varausauka on kulunut loppuun! Palaa takaisin 'varaa paikkasi' -sivulle jatkaaksesi. reservequeue.reservingTimeIsUpAlert =Sinulle varattu varausauka on kulunut loppuun! Palaa takaisin 'varaa paikkasi' -sivulle jatkaaksesi.
mapView.reserveTimeLeft=Aikaa varata paikkasi mapView.reserveTimeLeft =Aikaa varata paikkasi
queuemgmt.queueEnabled=Varausjono ON k\u00E4yt\u00F6ss\u00E4 queuemgmt.queueEnabled =Varausjono ON k\u00E4yt\u00F6ss\u00E4
queuemgmt.queueDisabled=K\u00E4ytt\u00E4j\u00E4jono EI OLE k\u00E4yt\u00F6ss\u00E4 (ota k\u00E4yttoon tapahtuman tiedot -sivulta) queuemgmt.queueDisabled =K\u00E4ytt\u00E4j\u00E4jono EI OLE k\u00E4yt\u00F6ss\u00E4 (ota k\u00E4yttoon tapahtuman tiedot -sivulta)
product.dependency.add=Lis\u00E4\u00E4 tuoteriippuvuus product.dependency.add =Lis\u00E4\u00E4 tuoteriippuvuus
product.dependency.create=Luo uusi product.dependency.create =Luo uusi
product.dependency.supporter=Tuote josta on riippuvuus product.dependency.supporter =Tuote josta on riippuvuus
product.dependency.type=Riippuvuuden tyyppi product.dependency.type =Riippuvuuden tyyppi
product.dependency.priority=Prioriteetti product.dependency.priority =Prioriteetti
product.dependency.delete=Poista product.dependency.delete =Poista
product.dependency.multiplier=Kerroin product.dependency.multiplier =Kerroin
product.dependency.MAX_SUPPORTED_COUNT=Tuotteita voi ostaa enint\u00E4\u00E4n saman m\u00E4\u00E4r\u00E4n product.dependency.MAX_SUPPORTED_COUNT =Tuotteita voi ostaa enint\u00E4\u00E4n saman m\u00E4\u00E4r\u00E4n
placemove.alreadyTaken=Paikkojen siirto peruuntui koska paikka {0} oli jo varattu. placemove.alreadyTaken =Paikkojen siirto peruuntui koska paikka {0} oli jo varattu.
placegroupview.moveUsersPlaces=Siirr\u00E4 k\u00E4ytt\u00E4j\u00E4n paikkoja placegroupview.moveUsersPlaces =Siirr\u00E4 k\u00E4ytt\u00E4j\u00E4n paikkoja
submenu.neomap.moveplaces=Vaihda paikkoja submenu.neomap.moveplaces =Vaihda paikkoja
mapEdit.removeSelectedPlaces=Poista paikat mapEdit.removeSelectedPlaces =Poista paikat
bortalApplication.map.MOVE_PLACES = Paikkojen itsepalvelusiirto bortalApplication.map.MOVE_PLACES = Paikkojen itsepalvelusiirto
bill.list.header = Tilaukset bill.list.header = Tilaukset
placemove.noMovablePlaces = Ei siirrett\u00E4vi\u00E4 paikkoja placemove.noMovablePlaces = Ei siirrett\u00E4vi\u00E4 paikkoja
deliver=Toimita deliver =Toimita
placegroupview.noProductsToDeliver=Ei toimitettavia tuotteita placegroupview.noProductsToDeliver =Ei toimitettavia tuotteita
placegroupview.productName=Tuotteen nimi placegroupview.productName =Tuotteen nimi
incomingflow.giveAccountEvent=Merkitse annetuksi incomingflow.giveAccountEvent =Merkitse annetuksi
incomingflow.ungiveAccountEvent=Ei olekkaan annettu incomingflow.ungiveAccountEvent =Ei olekkaan annettu
incomingflow.deliverableProducts=Toimitettavat tuotteet incomingflow.deliverableProducts =Toimitettavat tuotteet
placegroupview.accountEventDescription=Kuvaus placegroupview.accountEventDescription =Kuvaus
incomingflow.ungivenProducts=K\u00E4ytt\u00E4j\u00E4ll\u00E4 on toimittamattomia tuotteita incomingflow.ungivenProducts =K\u00E4ytt\u00E4j\u00E4ll\u00E4 on toimittamattomia tuotteita
placegroupview.count=Kpl placegroupview.count =Kpl
user.allergies=Allergiat / ruokavaliot user.allergies =Allergiat / ruokavaliot
allergies.save=Tallenna allergiat allergies.save =Tallenna allergiat
user.eventproperties = Tapahtumakohtaiset tiedot user.eventproperties = Tapahtumakohtaiset tiedot
submenu.permissionDenied = Pääsy kielletty submenu.permissionDenied = P\u00E4\u00E4sy kielletty
\ No newline at end of file role.source = Roolin lhde
role.source.DIRECT = Pakotettu k\u00E4ytt\u00E4j\u00E4lle
role.source.ORG_ROLE = Organisaatiorooli
role.source.PLACE = Paikka
role.source.ACCOUNTEVENT = Tilitapahtuma (Ostettu tuote)
role.source.PLACE_PRODUCT = Tuote paikan kautta
role.source.EVENT_DEFAULT = Tapahtuman oletusrooli
user.allroles = Kaikki k\u00E4yttäj\u00E4n roolit
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!