Commit c553b55d by Tuomas Riihimäki

Queue management view

1 parent f256b97d
......@@ -28,7 +28,8 @@ public interface QueueBeanLocal {
void setMinimumSlotsInQueue(int minimumSlotsInQueue);
Date getReservationTimeout(EventMap map, EventUser user);
Date getReservationTimeout(EventMap map);
void setReservingSize(int reservingSize);
......@@ -50,4 +51,9 @@ public interface QueueBeanLocal {
}
void forceAddToReserving(EventMap map, EventUser u, Date time);
void forceRemove(EventMap e, EventUser u);
}
......@@ -93,14 +93,16 @@ public interface UserBeanLocal {
/**
*
* @param invitemail Target mail
* @param url Url to send
* @param membership target group membership, if null we generate new one
* @param invitemail
* Target mail
* @param url
* Url to send
* @param membership
* target group membership, if null we generate new one
* @return
*/
boolean invite(String invitemail, String url, GroupMembership membership);
void cancelInvite(GroupMembership ship);
EventUser mergeEventUserChanges(EventUser shoppingUser);
......@@ -131,7 +133,7 @@ public interface UserBeanLocal {
boolean initPasswordResetForEmail(String email, String url);
PrintedCard rejectPrintedCard(PrintedCard card, MailMessage mail);
boolean initPasswordResetForUsername(String username, String url);
void addGameID(TournamentGame game, String gameid);
......@@ -161,14 +163,17 @@ public interface UserBeanLocal {
*/
BigDecimal transferAccountSaldoFromPreviousEvent(List<User> dstEventuser, LanEvent source);
EventUser getUser(String authcode);
EventUser getUserByAuthcode(String authcode);
String getAuthCode(EventUser user);
/**
* Find username by email or username, this is kind of login-helper.
*
* @param filter
* @return
*/
String findUsernameByEmailUsername(String filter);
EventUser findEventuserByLogin(String username);
}
......@@ -112,7 +112,7 @@ public class NetworkAssociationBean implements NetworkAssociationBeanLocal {
@Override
@RolesAllowed(NetworkAssociationPermission.S_CAN_ADMINISTER_ASSOCIATIONS)
public NetworkAssociation tryAssociate(String usercode, String ip, String mac, String code, Boolean codeRequired) throws Exception {
EventUser authUser = userBean.getUser(usercode);
EventUser authUser = userBean.getUserByAuthcode(usercode);
if(authUser == null)
throw new Exception("INVALID_USERCODE");
......
......@@ -172,6 +172,26 @@ public class QueueBean implements QueueBeanLocal {
}
public void forceAdd(EventUser u, Date time) {
MapReservationQueueEntry entry = queEntries.get(u);
synchronized (queue)
{
if (entry == null) {
entry = new MapReservationQueueEntry();
entry.setCreated(new Date());
entry.setUser(u);
queEntries.put(u, entry);
}
entry.setReservationTimeout(time);
entry.setSeenTime(new Date());
reserving.remove(u);
queue.remove(u);
reserving.add(u);
}
}
public Integer getPosition(EventUser user) {
Integer ret = null;
......@@ -210,6 +230,7 @@ public class QueueBean implements QueueBeanLocal {
public Set<EventUser> getReserving() {
return reserving;
}
}
@EJB
......@@ -217,13 +238,19 @@ public class QueueBean implements QueueBeanLocal {
private AtomicLong nextReservingTimeoutCheck = new AtomicLong();
@EJB
private PlaceSlotFacade slotfacade;
@EJB
private PermissionBeanLocal permbean;
@Lock(LockType.READ)
@Override
public boolean isReserving(EventMap map, EventUser user) {
// If queue is not enabled, user can always reserve
if (!isQueueEnabled())
return true;
if (!permbean.isCurrentUser(user) && !permbean.hasPermission(MapPermission.MANAGE_OTHERS))
throw new RuntimeException("Use " + permbean.getCurrentUser() + "tried to enter to queue in behalf of another user: " + user);
if (map == null || user == null)
{
logger.warn("Can not check map {}, user {}", map, user);
......@@ -282,20 +309,32 @@ public class QueueBean implements QueueBeanLocal {
@Lock(LockType.READ)
@Override
public Date getReservationTimeout(EventMap map, EventUser user)
public Date getReservationTimeout(EventMap map)
{
Date d = null;
MapReservationQueueEntry ret = getMapque(map).getEntry(user);
MapReservationQueueEntry ret = getMapque(map).getEntry(permbean.getCurrentUser());
if (ret != null)
d = ret.getReservationTimeout();
return d;
}
public Date getReservingTimeout(EventMap map)
{
MapReservationQueueEntry ret = getMapque(map).getEntry(permbean.getCurrentUser());
Date time = null;
if (ret != null)
time = ret.getReservationTimeout();
return time;
}
@Lock(LockType.READ)
@Override
public Integer getQueuePosition(EventMap map, EventUser user)
{
return getMapque(map).getPosition(user);
if (!permbean.isCurrentUser(user) && !permbean.hasPermission(MapPermission.MANAGE_OTHERS))
throw new RuntimeException("Use " + permbean.getCurrentUser() + "tried to get queuepos in behalf of another user: " + user);
return getMapque(map).getPosition(permbean.getCurrentUser());
}
@Lock(LockType.READ)
......@@ -307,16 +346,36 @@ public class QueueBean implements QueueBeanLocal {
@Lock(LockType.READ)
@Override
public MapReservationQueueEntry remove(EventMap map, EventUser user) {
if (!permbean.isCurrentUser(user) && !permbean.hasPermission(MapPermission.MANAGE_OTHERS))
throw new RuntimeException("Use " + permbean.getCurrentUser() + "tried to enter to queue in behalf of another user: " + user);
MapQueue queue = getMapque(map);
return queue.remove(user);
}
@Override
@Lock(LockType.READ)
@RolesAllowed(MapPermission.S_MANAGE_MAPS)
public void forceAddToReserving(EventMap map, EventUser u, Date time) {
MapQueue q = getMapque(map);
q.forceAdd(u, time);
}
@Override
@Lock(LockType.READ)
public MapReservationQueueEntry enterQueue(EventMap map, EventUser user) {
if (!isQueueEnabled()) {
return null;
}
if (!permbean.isCurrentUser(user) && !permbean.hasPermission(MapPermission.MANAGE_OTHERS))
throw new RuntimeException("Use " + permbean.getCurrentUser() + "tried to enter to queue in behalf of another user: " + user);
if (user == null || user.isAnonymous()) {
return null;
}
MapQueue queue = getMapque(map);
MapReservationQueueEntry ret = null;
......@@ -357,24 +416,36 @@ public class QueueBean implements QueueBeanLocal {
}
@Override
@Lock(LockType.READ)
public int getDefaultTimeoutMin() {
return defaultTimeoutMin;
}
@Override
@Lock(LockType.READ)
public void setDefaultTimeoutMin(int defaultTimeoutMin) {
this.defaultTimeoutMin = defaultTimeoutMin;
}
@Override
@Lock(LockType.READ)
public int getReservingSize() {
return reservingSize;
}
@Override
@Lock(LockType.READ)
@RolesAllowed(MapPermission.S_MANAGE_MAPS)
public void setReservingSize(int reservingSize) {
this.reservingSize = reservingSize;
}
@Override
@Lock(LockType.READ)
@RolesAllowed(MapPermission.S_MANAGE_MAPS)
public void forceRemove(EventMap e, EventUser u) {
MapQueue q = getMapque(e);
q.remove(u);
}
}
......@@ -49,6 +49,7 @@ import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import fi.codecrew.moya.enums.apps.MapPermission;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -420,7 +421,6 @@ public class UserBean implements UserBeanLocal {
// return userFacade.searchForName(name);
// }
@Override
@RolesAllowed(UserPermission.S_CREATE_NEW)
public void createNewUser(EventUser user, String password) {
......@@ -428,7 +428,7 @@ public class UserBean implements UserBeanLocal {
user.getUser().resetPassword(password);
user.setEvent(eventBean.getCurrentEvent());
if(user.getLogin() == null || user.getLogin().trim().isEmpty()) {
if (user.getLogin() == null || user.getLogin().trim().isEmpty()) {
user.setLogin(user.getEmail());
}
......@@ -559,12 +559,11 @@ public class UserBean implements UserBeanLocal {
EventUser creator = permbean.getCurrentUser();
LanEvent ev = eventBean.getCurrentEvent();
String token = gmfacade.createInviteToken();
PlaceGroup pg;
if(inviteGm != null) {
if(!permbean.hasPermission(MapPermission.MANAGE_OTHERS)) {
if (inviteGm != null) {
if (!permbean.hasPermission(MapPermission.MANAGE_OTHERS)) {
if (inviteGm.getUser() != null && !permbean.isCurrentUser(inviteGm.getUser())) {
throw new EJBAccessException("No permission to reinvite to that place");
}
......@@ -579,7 +578,7 @@ public class UserBean implements UserBeanLocal {
gmfacade.merge(inviteGm);
pg = inviteGm.getPlaceGroup();
} else {
if(!permbean.hasPermission(UserPermission.INVITE_USERS)) {
if (!permbean.hasPermission(UserPermission.INVITE_USERS)) {
throw new EJBAccessException("No permission to invite other people");
}
......@@ -592,8 +591,6 @@ public class UserBean implements UserBeanLocal {
pgfacade.create(pg);
}
MailMessage msg = new MailMessage();
msg.setSubject(eventBean.getPropertyString(LanEventPropertyKey.INVITEMAIL_SUBJECT));
String formatUrl = MessageFormat.format(url, token);
......@@ -612,7 +609,6 @@ public class UserBean implements UserBeanLocal {
ship.setInviteName(null);
}
@Override
@PermitAll
public GroupMembership findToken(String token) {
......@@ -630,7 +626,7 @@ public class UserBean implements UserBeanLocal {
// it's nice to check password also
EventUser eu = validateUser(username, password, true);
if(eu == null)
if (eu == null)
return null;
loggerbean.sendMessage(MoyaEventType.INVITE_ACCEPTED, eu, "Ivite accepted by current user", gm, gm.getUser());
......@@ -660,7 +656,7 @@ public class UserBean implements UserBeanLocal {
}
user.setEvent(eventBean.getCurrentEvent());
if(user.getLogin() == null || user.getLogin().trim().isEmpty()) {
if (user.getLogin() == null || user.getLogin().trim().isEmpty()) {
user.setLogin(user.getEmail());
}
......@@ -851,7 +847,7 @@ public class UserBean implements UserBeanLocal {
@Override
public EventUser validateUser(String username, String password)
{
return validateUser(username, password,false);
return validateUser(username, password, false);
}
@Override
......@@ -1091,18 +1087,17 @@ public class UserBean implements UserBeanLocal {
List<User> users = userFacade.findByEmail(filter);
if(users.size() == 1 && user != null) {
if(user.equals(users.get(0)))
if (users.size() == 1 && user != null) {
if (user.equals(users.get(0)))
return user.getLogin();
return null;
}
if(user != null)
if (user != null)
return user.getLogin();
if(users.size() == 1) {
if (users.size() == 1) {
return users.get(0).getLogin();
}
......@@ -1110,9 +1105,14 @@ public class UserBean implements UserBeanLocal {
}
@RolesAllowed(UserPermission.S_VIEW_ALL)
public EventUser findEventuserByLogin(String username) {
return eventUserFacade.findByLogin(username);
}
@Override
@RolesAllowed(EventPermission.S_MANAGE_EVENT)
public EventUser getUser(String authcode) {
public EventUser getUserByAuthcode(String authcode) {
logger.info("getUser({})", authcode);
EventUser user = null;
......@@ -1155,4 +1155,5 @@ public class UserBean implements UserBeanLocal {
return user;
}
}
\ No newline at end of file
<!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:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:map="http://java.sun.com/jsf/composite/cditools/map"
xmlns:tools="http://java.sun.com/jsf/composite/cditools"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:map="http://java.sun.com/jsf/composite/cditools/map"
xmlns:tools="http://java.sun.com/jsf/composite/cditools" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:p="http://primefaces.org/ui">
<h:body>
......@@ -16,18 +10,41 @@
<f:viewParam name="mapId" value="#{queueManageView.mapId}" />
<f:event type="preRenderView" listener="#{queueManageView.initView}" />
</f:metadata>
<ui:define name="content">
<h2>Queue properties</h2>
<h:form>
<p:panelGrid columns="1">
<p:inputText id="minslots" label="#{i18n['queuemgmt.minimumSlotsInQueue']}" value="#{queueManageView.queuebean.minimumSlotsInQueue}" />
<p:inputText id="reservingsize" label="#{i18n['queuemgmt.reservingSize']}" value="#{queueManageView.queuebean.reservingSize}" />
<p:inputText id="defaultTimeout" label="#{i18n['queuemgmt.defaultTimeoutMin']}" value="#{queueManageView.queuebean.defaultTimeoutMin}" />
<p:panelGrid columns="2">
<p:outputLabel for="minslots" value="#{i18n['queuemgmt.minimumSlotsInQueue']}" />
<p:inputText id="minslots" value="#{queueManageView.queuebean.minimumSlotsInQueue}" />
<p:outputLabel for="reservingsize" value="#{i18n['queuemgmt.reservingSize']}" />
<p:inputText id="reservingsize" value="#{queueManageView.queuebean.reservingSize}" />
<p:outputLabel for="defaultTimeout" value="#{i18n['queuemgmt.defaultTimeoutMin']}" />
<p:inputText id="defaultTimeout" value="#{queueManageView.queuebean.defaultTimeoutMin}" />
</p:panelGrid>
<p:commandButton ajax="false"></p:commandButton>
<p:commandButton ajax="false" value="#{i18n['queuemgmt.saveProperties']}"></p:commandButton>
</h:form>
<h2>Manage queue</h2>
<h:form>
<p:panelGrid columns="2">
<p:outputLabel for="username" value="#{i18n['queuemgmt.username']}" />
<p:inputText id="username" value="#{queueManageView.username}" />
<p:outputLabel for="expiretime" value="#{i18n['queuemgmt.time']}" />
<p:calendar id="expiretime" label="" value="#{queueManageView.time}" pattern="#{sessionHandler.datetimeFormat}" timeZone="#{sessionHandler.timezone}" />
</p:panelGrid>
<p:commandButton action="#{queueManageView.addToReserving}" ajax="false" value="#{i18n['queuemgmt.adduser']}" />
<p:commandButton action="#{queueManageView.forceRemove}" ajax="false" value="#{i18n['queuemgmt.remove']}" />
</h:form>
<h:outputText value="#{queueManageView.now}">
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}" timeZone="#{sessionHandler.timezone}" />
</h:outputText>
<h2>Currently reserving</h2>
<p:dataTable var="u" value="#{queueManageView.userReserving}">
<p:column>
......@@ -35,21 +52,13 @@
</p:column>
<p:column headerText="Created">
<h:outputText value="#{u.created}">
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}"
timeZone="#{sessionHandler.timezone}" />
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}" timeZone="#{sessionHandler.timezone}" />
</h:outputText>
</p:column>
<p:column headerText="Reservation timeout">
<p:calendar
value="#{u.seenTime}"
pattern="#{sessionHandler.datetimeFormat}"
timeZone="#{sessionHandler.timezone}" showOn="button"
/>
<h:outputText value="#{u.reservationTimeout}">
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}"
timeZone="#{sessionHandler.timezone}" />
<h:outputText value="#{u.reservationTimeout}">
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}" timeZone="#{sessionHandler.timezone}" />
</h:outputText>
</p:column>
</p:dataTable>
......@@ -61,16 +70,11 @@
</p:column>
<p:column headerText="Created">
<h:outputText value="#{u.created}">
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}"
timeZone="#{sessionHandler.timezone}" />
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}" timeZone="#{sessionHandler.timezone}" />
</h:outputText>
</p:column>
<p:column headerText="Seen time">
<p:calendar
value="#{u.seenTime}"
pattern="#{sessionHandler.datetimeFormat}"
timeZone="#{sessionHandler.timezone}" showOn="button"
/>
<p:calendar value="#{u.seenTime}" pattern="#{sessionHandler.datetimeFormat}" timeZone="#{sessionHandler.timezone}" showOn="button" />
</p:column>
</p:dataTable>
......
......@@ -20,7 +20,7 @@
<link rel="stylesheet" type="text/css" href="#{request.contextPath}/resources/templates/primelayout/css/skinning.css" />
<link rel="stylesheet" type="text/css" href="#{request.contextPath}/resources/templates/primelayout/css/structual.css" />
<link rel="stylesheet" type="text/css" href="#{request.contextPath}/resources/templates/custom_components.css" />
<script type="text/javascript" src="#{request.contextPath}/resources/script/prime_calendar.js" ></script>
<script type="text/javascript" src="#{request.contextPath}/resources/script/prime_calendar.js" ></script>
<ui:insert name="headerdata" />
......
......@@ -62,7 +62,7 @@ public class BortalExceptionHandler extends ExceptionHandlerWrapper {
logger.debug("Found exception! handing it: {}", t.getClass().toString());
if (t instanceof ViewExpiredException) {
errorpage(i, t, "viewExpired");
errorpage(i, t, "/viewExpired");
}
Throwable cause = t.getCause();
for (int loop = 0; loop < 20 && cause != null; ++loop) {
......
......@@ -71,7 +71,7 @@ public class UserRestView {
@Path("/eventuser/{cardauthcode}")
public EventUserRestPojo getEventUser(@PathParam("cardauthcode") String code) {
EventUser user = userbean.getUser(code);
EventUser user = userbean.getUserByAuthcode(code);
if(user != null)
return new EventUserRestPojo(user);
else
......
......@@ -139,7 +139,7 @@ public class AjaxMapView extends GenericCDIView {
{
logger.info("Entering queue");
if (isQueueEnabled())
queueEntry = quebean.enterQueue(initMap(), permbean.getCurrentUser());
queueEntry = quebean.enterQueue(initMap(), userview.getSelectedUser());
else {
logger.warn("QueueNot enabled. Not entering queue");
}
......@@ -167,7 +167,7 @@ public class AjaxMapView extends GenericCDIView {
}
public Integer getQueuePosition() {
return quebean.getQueuePosition(initMap(), permbean.getCurrentUser());
return quebean.getQueuePosition(initMap(), userview.getSelectedUser());
}
public Long getPlacesLeftToSelect() {
......@@ -194,7 +194,7 @@ public class AjaxMapView extends GenericCDIView {
public boolean isReserving()
{
if (reserving == null) {
reserving = quebean.isReserving(initMap(), permbean.getCurrentUser());
reserving = quebean.isReserving(initMap(), userview.getSelectedUser());
}
return reserving;
}
......@@ -202,7 +202,7 @@ public class AjaxMapView extends GenericCDIView {
public boolean canUserBuy() {
return permbean.hasPermission(MapPermission.BUY_PLACES) &&
(permbean.hasPermission(MapPermission.MANAGE_OTHERS) ||
quebean.isReserving(initMap(), permbean.getCurrentUser())
quebean.isReserving(initMap(), userview.getSelectedUser())
);
}
......
package fi.codecrew.moya.web.cdiview.map;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
......@@ -12,9 +13,11 @@ import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.beans.PermissionBeanLocal;
import fi.codecrew.moya.beans.PlaceBeanLocal;
import fi.codecrew.moya.beans.QueueBeanLocal;
import fi.codecrew.moya.beans.QueueBeanLocal.MapQueueI;
import fi.codecrew.moya.beans.UserBeanLocal;
import fi.codecrew.moya.enums.apps.MapPermission;
import fi.codecrew.moya.model.EventMap;
import fi.codecrew.moya.model.EventUser;
......@@ -38,9 +41,21 @@ public class QueueManageView extends GenericCDIView {
private MapQueueI queue;
private String username;
private Date time = new Date(System.currentTimeMillis() + 1000 * 60 * 60);
@EJB
private UserBeanLocal userbean;
@EJB
private PermissionBeanLocal permissionbean;
private static final Logger logger = LoggerFactory.getLogger(QueueManageView.class);
public Date getNow()
{
return new Date();
}
public void initView() {
if (super.requirePermissions(MapPermission.MANAGE_MAPS) && map == null) {
map = placebean.findMap(mapId);
......@@ -51,6 +66,28 @@ public class QueueManageView extends GenericCDIView {
}
}
public String addToReserving() {
EventUser u = userbean.findEventuserByLogin(username);
if (u == null) {
super.addFaceMessage("Username not found!");
}
else {
quebean.forceAddToReserving(map, u, getTime());
}
return null;
}
public String forceRemove() {
EventUser u = userbean.findEventuserByLogin(username);
if (u == null) {
super.addFaceMessage("Username not found!");
}
else {
quebean.forceRemove(map, u);
}
return null;
}
public ListDataModel<MapReservationQueueEntry> getUserQueue() {
List<MapReservationQueueEntry> ret = new ArrayList<>();
if (queue == null)
......@@ -101,4 +138,20 @@ public class QueueManageView extends GenericCDIView {
{
return quebean;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
}
......@@ -357,6 +357,8 @@ placegroupview.owner = Omistaja
placegroupview.placetransferred = Paikka annettu eteenp\u00E4in
placegroupview.toptext = \
placeslot.state.expired = Vanhentunut
poll.edit = edit
print = Print
......@@ -469,4 +471,3 @@ usercart.showoverview = Vie tarkastusn\u00E4kym\u00E4\u00E4n
viewlectures.title = Kurssit ja luennot
yes = Kyll\u00E4
placeslot.state.expired=Vanhentunut
......@@ -955,6 +955,7 @@ placeslot.place = Place
placeslot.product = Slot product
placeslot.showBill = Show bill
placeslot.state = State
placeslot.state.expired = Expired
placeslot.state.notPaid = Not paid
placeslot.state.paid = Paid
placeslot.stateExpired = Expired
......@@ -1048,6 +1049,15 @@ productshop.plusOne = +1
productshop.plusTen = +10
productshop.total = Total
queuemgmt.adduser = Add user as reserving
queuemgmt.defaultTimeoutMin = Reservation time
queuemgmt.minimumSlotsInQueue = Minimum slotscount to enter queue
queuemgmt.remove = Remove login from queue
queuemgmt.reservingSize = Number of people reserving at the same time
queuemgmt.saveProperties = Save properties
queuemgmt.time = Reservation time
queuemgmt.username = Login
reader.assocToCard = Associate to card
reader.automaticProduct = Default product
reader.automaticProductCount = Amount
......@@ -1677,4 +1687,3 @@ voting.create.voteEnd = Voting close
voting.create.voteStart = Voting start
yes = Yes
placeslot.state.expired=Expired
......@@ -938,6 +938,7 @@ placeslot.place = Paikka
placeslot.product = Tuote
placeslot.showBill = N\u00E4yt\u00E4 lasku
placeslot.state = Tila
placeslot.state.expired = Vanhentunut
placeslot.state.notPaid = Ei maksettu
placeslot.state.paid = Maksettu
placeslot.stateExpired = Vanhentunut
......@@ -1033,6 +1034,15 @@ productshop.plusOne = +1
productshop.plusTen = +10
productshop.total = Yhteens\u00E4
queuemgmt.adduser = Lis\u00E4\u00E4 varaamaan
queuemgmt.defaultTimeoutMin = Varausaika
queuemgmt.minimumSlotsInQueue = Jonoonp\u00E4\u00E4syn v\u00E4himm\u00E4ispaikkam\u00E4\u00E4r\u00E4
queuemgmt.remove = Poista k\u00E4ytt\u00E4j\u00E4 jonosta
queuemgmt.reservingSize = Samanaikaisesti varaamaan p\u00E4\u00E4sevien m\u00E4\u00E4r\u00E4
queuemgmt.saveProperties = Tallenna arvot
queuemgmt.time = Varausaika
queuemgmt.username = K\u00E4ytt\u00E4j\u00E4tunnus
reader.assocToCard = Yhdist\u00E4 korttiin
reader.automaticProduct = Oletustuote
reader.automaticProductCount = M\u00E4\u00E4r\u00E4
......@@ -1659,4 +1669,3 @@ voting.create.voteEnd = \u00C4\u00E4nestys kiinni
voting.create.voteStart = \u00C4\u00E4nestys auki
yes = Kyll\u00E4
placeslot.state.expired=Vanhentunut
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!