Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
Max Mecklin
/
Moya
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Wiki
Settings
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit 36f285a2
authored
Mar 14, 2017
by
Tuukka Kivilahti
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
made some stuff for placequeue, some fixes also
1 parent
fc4dfef2
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
341 additions
and
34 deletions
code/moya-beans-client/ejbModule/fi/codecrew/moya/beans/PlaceBeanLocal.java
code/moya-beans-client/ejbModule/fi/codecrew/moya/beans/map/QueueBeanLocal.java
code/moya-beans/ejbModule/fi/codecrew/moya/beans/BootstrapBean.java
code/moya-beans/ejbModule/fi/codecrew/moya/beans/PlaceBean.java
code/moya-beans/ejbModule/fi/codecrew/moya/beans/map/MapQueue.java
code/moya-beans/ejbModule/fi/codecrew/moya/beans/map/QueueBean.java
code/moya-beans/ejbModule/fi/codecrew/moya/facade/MapQueueRulesFacade.java
code/moya-database/src/main/java/fi/codecrew/moya/model/MapQueueRules.java
code/moya-database/src/main/java/fi/codecrew/moya/model/map/MapReservationQueueEntry.java
code/moya-web/WebContent/neomap/quemgmt.xhtml
code/moya-web/WebContent/neomap/reserve.xhtml
code/moya-web/src/main/java/fi/codecrew/moya/rest/placemap/v1/PlacemapRestViewV1.java
code/moya-web/src/main/java/fi/codecrew/moya/web/cdiview/map/AjaxMapView.java
code/moya-web/src/main/java/fi/codecrew/moya/web/cdiview/map/QueueManageView.java
code/moya-web/src/main/resources/fi/codecrew/moya/resources/i18n.properties
code/moya-web/src/main/resources/fi/codecrew/moya/resources/i18n_en.properties
code/moya-web/src/main/resources/fi/codecrew/moya/resources/i18n_fi.properties
code/moya-beans-client/ejbModule/fi/codecrew/moya/beans/PlaceBeanLocal.java
View file @
36f285a
...
@@ -56,6 +56,8 @@ public interface PlaceBeanLocal {
...
@@ -56,6 +56,8 @@ public interface PlaceBeanLocal {
boolean
releasePlace
(
Place
place
);
boolean
releasePlace
(
Place
place
);
boolean
userReleasePlace
(
Place
place
);
Place
mergeChanges
(
Place
place
);
Place
mergeChanges
(
Place
place
);
PlaceGroup
buySelectedPlaces
(
EventUser
user
)
throws
BortalCatchableException
;
PlaceGroup
buySelectedPlaces
(
EventUser
user
)
throws
BortalCatchableException
;
...
...
code/moya-beans-client/ejbModule/fi/codecrew/moya/beans/map/QueueBeanLocal.java
View file @
36f285a
...
@@ -7,6 +7,7 @@ import javax.ejb.Local;
...
@@ -7,6 +7,7 @@ import javax.ejb.Local;
import
fi.codecrew.moya.model.EventMap
;
import
fi.codecrew.moya.model.EventMap
;
import
fi.codecrew.moya.model.EventUser
;
import
fi.codecrew.moya.model.EventUser
;
import
fi.codecrew.moya.model.MapQueueRules
;
import
fi.codecrew.moya.model.map.MapReservationQueueEntry
;
import
fi.codecrew.moya.model.map.MapReservationQueueEntry
;
@Local
@Local
...
@@ -26,6 +27,10 @@ public interface QueueBeanLocal {
...
@@ -26,6 +27,10 @@ public interface QueueBeanLocal {
MapQueueI
getMapQueue
(
EventMap
map
);
MapQueueI
getMapQueue
(
EventMap
map
);
void
saveQueue
(
MapQueueI
queue
,
EventMap
map
);
MapQueueRules
findRules
(
EventMap
map
);
public
interface
MapQueueI
{
public
interface
MapQueueI
{
Collection
<
MapReservationQueueEntry
>
getQueue
();
Collection
<
MapReservationQueueEntry
>
getQueue
();
...
...
code/moya-beans/ejbModule/fi/codecrew/moya/beans/BootstrapBean.java
View file @
36f285a
...
@@ -417,7 +417,6 @@ public class BootstrapBean implements BootstrapBeanLocal {
...
@@ -417,7 +417,6 @@ public class BootstrapBean implements BootstrapBeanLocal {
});
});
dbUpdates
.
add
(
new
String
[]
{
dbUpdates
.
add
(
new
String
[]
{
"ALTER TABLE products ADD COLUMN min_buy_count INTEGER default 0;"
"ALTER TABLE products ADD COLUMN min_buy_count INTEGER default 0;"
});
});
...
@@ -426,6 +425,11 @@ public class BootstrapBean implements BootstrapBeanLocal {
...
@@ -426,6 +425,11 @@ public class BootstrapBean implements BootstrapBeanLocal {
"ALTER TABLE discounts ADD COLUMN sort INTEGER NOT NULL default 10;"
"ALTER TABLE discounts ADD COLUMN sort INTEGER NOT NULL default 10;"
});
});
dbUpdates
.
add
(
new
String
[]
{
"CREATE TABLE map_queue_rules (id SERIAL NOT NULL, meta json, reserving_size INTEGER, default_timeout_min INTEGER, minium_slots_in_queue INTEGER, map_id INTEGER NOT NULL, PRIMARY KEY (id))"
,
"ALTER TABLE map_queue_rules ADD CONSTRAINT FK_map_queue_rules_map_id FOREIGN KEY (map_id) REFERENCES maps (id)"
,
});
}
}
...
...
code/moya-beans/ejbModule/fi/codecrew/moya/beans/PlaceBean.java
View file @
36f285a
...
@@ -494,6 +494,21 @@ public class PlaceBean implements PlaceBeanLocal {
...
@@ -494,6 +494,21 @@ public class PlaceBean implements PlaceBeanLocal {
return
releasePlacePriv
(
place
)
!=
null
;
return
releasePlacePriv
(
place
)
!=
null
;
}
}
/**
* User release place
*
* @param place The place to be released
* @return true when successfull, on any erroro false.
*/
@Override
@RolesAllowed
({
MapPermission
.
S_BUY_PLACES
,
MapPermission
.
S_MANAGE_OTHERS
})
public
boolean
userReleasePlace
(
Place
place
)
{
place
=
placeFacade
.
reload
(
place
);
PlaceSlot
s
=
releasePlacePriv
(
place
);
return
(
s
==
null
||
s
.
getUsed
()
==
null
);
}
private
PlaceSlot
releasePlacePriv
(
Place
place
)
{
private
PlaceSlot
releasePlacePriv
(
Place
place
)
{
EventUser
user
=
permbean
.
getCurrentUser
();
EventUser
user
=
permbean
.
getCurrentUser
();
if
(
place
.
getGroup
()
!=
null
||
place
.
getCurrentUser
()
==
null
if
(
place
.
getGroup
()
!=
null
||
place
.
getCurrentUser
()
==
null
...
...
code/moya-beans/ejbModule/fi/codecrew/moya/beans/map/MapQueue.java
View file @
36f285a
package
fi
.
codecrew
.
moya
.
beans
.
map
;
package
fi
.
codecrew
.
moya
.
beans
.
map
;
import
java.util.Collection
;
import
java.util.*
;
import
java.util.Collections
;
import
java.util.Date
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.PriorityQueue
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentMap
;
import
java.util.concurrent.ConcurrentMap
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
fi.codecrew.moya.model.MapQueueRules
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
...
@@ -24,9 +19,11 @@ public class MapQueue implements MapQueueI {
...
@@ -24,9 +19,11 @@ public class MapQueue implements MapQueueI {
private
int
defaultTimeoutMin
=
10
;
private
int
defaultTimeoutMin
=
10
;
private
int
minimumSlotsInQueue
=
1
;
private
int
minimumSlotsInQueue
=
1
;
private
int
reservingSize
=
5
;
private
int
reservingSize
=
5
;
// private final Set<MapReservationQueueEntry> reserving = new HashSet<>();
// private final Set<MapReservationQueueEntry> reserving = new HashSet<>();
private
final
Set
<
EventUser
>
reserving
=
Collections
.
newSetFromMap
(
new
ConcurrentHashMap
<>());
private
final
Set
<
EventUser
>
reserving
=
Collections
.
newSetFromMap
(
new
ConcurrentHashMap
<>());
private
final
PriorityQueue
<
MapReservationQueueEntry
>
queue
=
new
PriorityQueue
<>();
//private final PriorityQueue<MapReservationQueueEntry> queue = new PriorityQueue<>();
private
final
List
<
MapReservationQueueEntry
>
queue
=
new
ArrayList
<>();
private
final
ConcurrentMap
<
EventUser
,
MapReservationQueueEntry
>
queEntries
=
new
ConcurrentHashMap
<>();
private
final
ConcurrentMap
<
EventUser
,
MapReservationQueueEntry
>
queEntries
=
new
ConcurrentHashMap
<>();
private
final
Integer
mapId
;
private
final
Integer
mapId
;
//private final Object reservingLock = new Object();
//private final Object reservingLock = new Object();
...
@@ -35,10 +32,23 @@ public class MapQueue implements MapQueueI {
...
@@ -35,10 +32,23 @@ public class MapQueue implements MapQueueI {
public
MapQueue
(
EventMap
map
)
{
public
MapQueue
(
EventMap
map
)
{
this
.
mapId
=
map
.
getId
();
this
.
mapId
=
map
.
getId
();
}
public
MapQueue
(
EventMap
map
,
MapQueueRules
rules
)
{
this
(
map
);
if
(
rules
!=
null
)
{
this
.
defaultTimeoutMin
=
rules
.
getDefaultTimeoutMin
();
this
.
minimumSlotsInQueue
=
rules
.
getMinimumSlotsInQueue
();
this
.
reservingSize
=
rules
.
getReservingSize
();
}
}
}
void
timeoutEntries
()
{
void
doHousekeeping
()
{
timeoutEntries
();
}
private
void
timeoutEntries
()
{
logger
.
info
(
"Timeouting entries"
);
logger
.
info
(
"Timeouting entries"
);
// give 10 seconds mercy ( and give us some time to go through all entries)
// give 10 seconds mercy ( and give us some time to go through all entries)
Date
now
=
new
Date
(
System
.
currentTimeMillis
()
+
1000
*
15
);
Date
now
=
new
Date
(
System
.
currentTimeMillis
()
+
1000
*
15
);
...
@@ -81,13 +91,17 @@ public class MapQueue implements MapQueueI {
...
@@ -81,13 +91,17 @@ public class MapQueue implements MapQueueI {
private
final
AtomicBoolean
modifyReservers
=
new
AtomicBoolean
(
false
);
private
final
AtomicBoolean
modifyReservers
=
new
AtomicBoolean
(
false
);
private
void
checkReservingEntry
()
{
private
void
checkReservingEntry
()
{
if
(
reserving
.
size
()
<
getReservingSize
()
&&
modifyReservers
.
compareAndSet
(
false
,
true
))
{
if
(
reserving
.
size
()
<
getReservingSize
()
&&
modifyReservers
.
compareAndSet
(
false
,
true
))
{
try
{
try
{
if
(
reserving
.
size
()
<
getReservingSize
())
{
if
(
reserving
.
size
()
<
getReservingSize
()
&&
!
queue
.
isEmpty
())
{
MapReservationQueueEntry
queEntry
=
queue
.
poll
();
MapReservationQueueEntry
queEntry
=
queue
.
get
(
0
);
queue
.
remove
(
0
);
Collections
.
sort
(
queue
);
if
(
queEntry
!=
null
)
{
if
(
queEntry
!=
null
)
{
reserving
.
add
(
queEntry
.
getUser
());
reserving
.
add
(
queEntry
.
getUser
());
queEntry
.
setReservationTimeout
(
new
Date
(
System
.
currentTimeMillis
()
+
getDefaultTimeoutMin
()
*
60
*
1000
));
queEntry
.
setReservationTimeout
(
new
Date
(
System
.
currentTimeMillis
()
+
getDefaultTimeoutMin
()
*
60
*
1000
));
...
@@ -112,6 +126,8 @@ public class MapQueue implements MapQueueI {
...
@@ -112,6 +126,8 @@ public class MapQueue implements MapQueueI {
while
(
queue
.
remove
(
entry
))
{
while
(
queue
.
remove
(
entry
))
{
}
}
}
}
Collections
.
sort
(
queue
);
checkReservingEntry
();
checkReservingEntry
();
return
ret
;
return
ret
;
...
@@ -122,6 +138,8 @@ public class MapQueue implements MapQueueI {
...
@@ -122,6 +138,8 @@ public class MapQueue implements MapQueueI {
if
(!
reserving
.
contains
(
user
)
&&
!
queue
.
contains
(
ret
))
{
if
(!
reserving
.
contains
(
user
)
&&
!
queue
.
contains
(
ret
))
{
queue
.
add
(
ret
);
queue
.
add
(
ret
);
Collections
.
sort
(
queue
);
// Check if the user can be put to reservation queue immediately
// Check if the user can be put to reservation queue immediately
checkReservingEntry
();
checkReservingEntry
();
...
@@ -195,7 +213,7 @@ public class MapQueue implements MapQueueI {
...
@@ -195,7 +213,7 @@ public class MapQueue implements MapQueueI {
}
}
@Override
@Override
public
PriorityQueue
<
MapReservationQueueEntry
>
getQueue
()
{
public
List
<
MapReservationQueueEntry
>
getQueue
()
{
return
queue
;
return
queue
;
}
}
...
...
code/moya-beans/ejbModule/fi/codecrew/moya/beans/map/QueueBean.java
View file @
36f285a
...
@@ -5,7 +5,6 @@ import java.util.List;
...
@@ -5,7 +5,6 @@ import java.util.List;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.atomic.AtomicLong
;
import
java.util.concurrent.atomic.AtomicLong
;
import
javax.annotation.OverridingMethodsMustInvokeSuper
;
import
javax.annotation.security.DeclareRoles
;
import
javax.annotation.security.DeclareRoles
;
import
javax.annotation.security.RolesAllowed
;
import
javax.annotation.security.RolesAllowed
;
import
javax.ejb.Asynchronous
;
import
javax.ejb.Asynchronous
;
...
@@ -17,6 +16,8 @@ import javax.ejb.Singleton;
...
@@ -17,6 +16,8 @@ import javax.ejb.Singleton;
import
javax.ejb.TransactionManagement
;
import
javax.ejb.TransactionManagement
;
import
javax.ejb.TransactionManagementType
;
import
javax.ejb.TransactionManagementType
;
import
fi.codecrew.moya.facade.MapQueueRulesFacade
;
import
fi.codecrew.moya.model.*
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
...
@@ -25,10 +26,6 @@ import fi.codecrew.moya.beans.PermissionBeanLocal;
...
@@ -25,10 +26,6 @@ import fi.codecrew.moya.beans.PermissionBeanLocal;
import
fi.codecrew.moya.beans.PlaceBeanLocal
;
import
fi.codecrew.moya.beans.PlaceBeanLocal
;
import
fi.codecrew.moya.enums.apps.MapPermission
;
import
fi.codecrew.moya.enums.apps.MapPermission
;
import
fi.codecrew.moya.facade.PlaceSlotFacade
;
import
fi.codecrew.moya.facade.PlaceSlotFacade
;
import
fi.codecrew.moya.model.EventMap
;
import
fi.codecrew.moya.model.EventUser
;
import
fi.codecrew.moya.model.LanEventPropertyKey
;
import
fi.codecrew.moya.model.PlaceSlot
;
import
fi.codecrew.moya.model.map.MapReservationQueueEntry
;
import
fi.codecrew.moya.model.map.MapReservationQueueEntry
;
/**
/**
...
@@ -62,6 +59,9 @@ public class QueueBean implements QueueBeanLocal {
...
@@ -62,6 +59,9 @@ public class QueueBean implements QueueBeanLocal {
@EJB
@EJB
private
PermissionBeanLocal
permbean
;
private
PermissionBeanLocal
permbean
;
@EJB
private
MapQueueRulesFacade
mapQueueRulesFacade
;
@Lock
(
LockType
.
READ
)
@Lock
(
LockType
.
READ
)
@Override
@Override
public
boolean
isReserving
(
EventMap
map
,
EventUser
user
)
{
public
boolean
isReserving
(
EventMap
map
,
EventUser
user
)
{
...
@@ -101,7 +101,7 @@ public class QueueBean implements QueueBeanLocal {
...
@@ -101,7 +101,7 @@ public class QueueBean implements QueueBeanLocal {
try
{
try
{
final
long
oldTime
=
nextReservingTimeoutCheck
.
get
();
final
long
oldTime
=
nextReservingTimeoutCheck
.
get
();
for
(
MapQueue
m
:
mapqueues
.
values
())
{
for
(
MapQueue
m
:
mapqueues
.
values
())
{
m
.
timeoutEntries
();
m
.
doHousekeeping
();
}
}
// DO housekeeping every 10 seconds.
// DO housekeeping every 10 seconds.
...
@@ -119,7 +119,9 @@ public class QueueBean implements QueueBeanLocal {
...
@@ -119,7 +119,9 @@ public class QueueBean implements QueueBeanLocal {
MapQueue
ret
=
mapqueues
.
get
(
map
.
getId
());
MapQueue
ret
=
mapqueues
.
get
(
map
.
getId
());
if
(
ret
==
null
)
{
if
(
ret
==
null
)
{
ret
=
new
MapQueue
(
map
);
ret
=
new
MapQueue
(
map
,
mapQueueRulesFacade
.
findByMap
(
map
));
MapQueue
nret
=
mapqueues
.
putIfAbsent
(
map
.
getId
(),
ret
);
MapQueue
nret
=
mapqueues
.
putIfAbsent
(
map
.
getId
(),
ret
);
if
(
nret
!=
null
)
{
if
(
nret
!=
null
)
{
ret
=
nret
;
ret
=
nret
;
...
@@ -231,6 +233,30 @@ public class QueueBean implements QueueBeanLocal {
...
@@ -231,6 +233,30 @@ public class QueueBean implements QueueBeanLocal {
}
}
@Override
@Override
public
void
saveQueue
(
MapQueueI
queue
,
EventMap
map
)
{
MapQueueRules
rules
=
mapQueueRulesFacade
.
findByMap
(
map
);
if
(
rules
==
null
)
{
rules
=
new
MapQueueRules
();
rules
.
setMap
(
map
);
mapQueueRulesFacade
.
create
(
rules
);
rules
=
mapQueueRulesFacade
.
reload
(
rules
);
}
rules
.
setDefaultTimeoutMin
(
queue
.
getDefaultTimeoutMin
());
rules
.
setMinimumSlotsInQueue
(
queue
.
getMinimumSlotsInQueue
());
rules
.
setReservingSize
(
queue
.
getReservingSize
());
mapQueueRulesFacade
.
merge
(
rules
);
}
@Override
public
MapQueueRules
findRules
(
EventMap
map
)
{
return
mapQueueRulesFacade
.
findByMap
(
map
);
}
@Override
@Lock
(
LockType
.
READ
)
@Lock
(
LockType
.
READ
)
@RolesAllowed
(
MapPermission
.
S_MANAGE_MAPS
)
@RolesAllowed
(
MapPermission
.
S_MANAGE_MAPS
)
public
void
forceRemove
(
EventMap
e
,
EventUser
u
)
{
public
void
forceRemove
(
EventMap
e
,
EventUser
u
)
{
...
...
code/moya-beans/ejbModule/fi/codecrew/moya/facade/MapQueueRulesFacade.java
0 → 100644
View file @
36f285a
/*
* Copyright Codecrew Ry
*
* All rights reserved.
*
* This license applies to any software containing a notice placed by the
* copyright holder. Such software is herein referred to as the Software.
* This license covers modification, distribution and use of the Software.
*
* Any distribution and use in source and binary forms, with or without
* modification is not permitted without explicit written permission from the
* copyright owner.
*
* A non-exclusive royalty-free right is granted to the copyright owner of the
* Software to use, modify and distribute all modifications to the Software in
* future versions of the Software.
*
*/
package
fi
.
codecrew
.
moya
.
facade
;
import
fi.codecrew.moya.model.EventMap
;
import
fi.codecrew.moya.model.MapQueueRules
;
import
fi.codecrew.moya.model.MapQueueRules_
;
import
javax.ejb.LocalBean
;
import
javax.ejb.Stateless
;
import
javax.persistence.criteria.CriteriaBuilder
;
import
javax.persistence.criteria.CriteriaQuery
;
import
javax.persistence.criteria.Root
;
@Stateless
@LocalBean
public
class
MapQueueRulesFacade
extends
IntegerPkGenericFacade
<
MapQueueRules
>
{
public
MapQueueRulesFacade
()
{
super
(
MapQueueRules
.
class
);
}
public
MapQueueRules
findByMap
(
EventMap
map
)
{
if
(
map
==
null
)
{
throw
new
NullPointerException
(
"Map must be given to MapQueueRules.findByMap"
);
}
CriteriaBuilder
cb
=
getEm
().
getCriteriaBuilder
();
CriteriaQuery
<
MapQueueRules
>
cq
=
cb
.
createQuery
(
MapQueueRules
.
class
);
Root
<
MapQueueRules
>
root
=
cq
.
from
(
MapQueueRules
.
class
);
cq
.
where
(
cb
.
equal
(
root
.
get
(
MapQueueRules_
.
map
),
map
));
return
getSingleNullableResult
(
getEm
().
createQuery
(
cq
).
setMaxResults
(
1
));
}
}
code/moya-database/src/main/java/fi/codecrew/moya/model/MapQueueRules.java
0 → 100644
View file @
36f285a
/*
* Copyright Codecrew Ry
*
* All rights reserved.
*
* This license applies to any software containing a notice placed by the
* copyright holder. Such software is herein referred to as the Software.
* This license covers modification, distribution and use of the Software.
*
* Any distribution and use in source and binary forms, with or without
* modification is not permitted without explicit written permission from the
* copyright owner.
*
* A non-exclusive royalty-free right is granted to the copyright owner of the
* Software to use, modify and distribute all modifications to the Software in
* future versions of the Software.
*
*/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package
fi
.
codecrew
.
moya
.
model
;
import
javax.persistence.*
;
import
java.awt.*
;
import
java.util.Calendar
;
/**
*
*/
@Entity
@Table
(
name
=
"map_queue_rules"
)
public
class
MapQueueRules
extends
GenericEntity
{
private
static
final
long
serialVersionUID
=
1L
;
@Column
(
name
=
"reserving_size"
)
private
Integer
reservingSize
=
5
;
@Column
(
name
=
"default_timeout_min"
)
private
Integer
defaultTimeoutMin
=
10
;
@Column
(
name
=
"minium_slots_in_queue"
)
private
Integer
minimumSlotsInQueue
=
1
;
@JoinColumn
(
name
=
"map_id"
,
referencedColumnName
=
"id"
)
@ManyToOne
private
EventMap
map
;
public
MapQueueRules
()
{
super
();
}
public
Integer
getReservingSize
()
{
return
reservingSize
;
}
public
void
setReservingSize
(
Integer
reservingSize
)
{
this
.
reservingSize
=
reservingSize
;
}
public
Integer
getDefaultTimeoutMin
()
{
return
defaultTimeoutMin
;
}
public
void
setDefaultTimeoutMin
(
Integer
defaultTimeoutMin
)
{
this
.
defaultTimeoutMin
=
defaultTimeoutMin
;
}
public
Integer
getMinimumSlotsInQueue
()
{
return
minimumSlotsInQueue
;
}
public
void
setMinimumSlotsInQueue
(
Integer
minimumSlotsInQueue
)
{
this
.
minimumSlotsInQueue
=
minimumSlotsInQueue
;
}
public
EventMap
getMap
()
{
return
map
;
}
public
void
setMap
(
EventMap
map
)
{
this
.
map
=
map
;
}
}
code/moya-database/src/main/java/fi/codecrew/moya/model/map/MapReservationQueueEntry.java
View file @
36f285a
...
@@ -92,9 +92,17 @@ public class MapReservationQueueEntry extends GenericEntity implements Comparabl
...
@@ -92,9 +92,17 @@ public class MapReservationQueueEntry extends GenericEntity implements Comparabl
}
}
@Override
@Override
/**
* Smaller is bigger.
*
* Bigger first.
*/
public
int
compareTo
(
MapReservationQueueEntry
o
)
{
public
int
compareTo
(
MapReservationQueueEntry
o
)
{
return
getPlaceslotcount
().
compareTo
(
o
.
getPlaceslotcount
());
if
(
o
==
null
||
o
.
getPlaceslotcount
()
==
null
)
return
-
1
;
return
o
.
getPlaceslotcount
().
compareTo
(
getPlaceslotcount
());
}
}
public
Integer
getPlaceslotcount
()
{
public
Integer
getPlaceslotcount
()
{
...
...
code/moya-web/WebContent/neomap/quemgmt.xhtml
View file @
36f285a
...
@@ -14,17 +14,22 @@
...
@@ -14,17 +14,22 @@
<ui:define
name=
"content"
>
<ui:define
name=
"content"
>
<h2>
Queue properties
</h2>
<h2>
Queue properties
</h2>
<h:form>
<h:form>
<p:panelGrid
columns=
"2"
>
<h3><h:outputText
value=
"#{i18n['queuemgmt.biggestIsFirst']}"
/>
</h3>
<p:panelGrid
columns=
"3"
id=
"queueGrid"
>
<p:outputLabel
for=
"minslots"
value=
"#{i18n['queuemgmt.minimumSlotsInQueue']}"
/>
<p:outputLabel
for=
"minslots"
value=
"#{i18n['queuemgmt.minimumSlotsInQueue']}"
/>
<p:inputText
id=
"minslots"
value=
"#{queueManageView.queue.minimumSlotsInQueue}"
/>
<p:inputText
id=
"minslots"
value=
"#{queueManageView.queue.minimumSlotsInQueue}"
/>
<h:outputText
value=
"#{i18n['queuemgmt.inDatabase']}: #{queueManageView.defaultValues.minimumSlotsInQueue}"
/>
<p:outputLabel
for=
"reservingsize"
value=
"#{i18n['queuemgmt.reservingSize']}"
/>
<p:outputLabel
for=
"reservingsize"
value=
"#{i18n['queuemgmt.reservingSize']}"
/>
<p:inputText
id=
"reservingsize"
value=
"#{queueManageView.queue.reservingSize}"
/>
<p:inputText
id=
"reservingsize"
value=
"#{queueManageView.queue.reservingSize}"
/>
<h:outputText
value=
"#{i18n['queuemgmt.inDatabase']}: #{queueManageView.defaultValues.reservingSize}"
/>
<p:outputLabel
for=
"defaultTimeout"
value=
"#{i18n['queuemgmt.defaultTimeoutMin']}"
/>
<p:outputLabel
for=
"defaultTimeout"
value=
"#{i18n['queuemgmt.defaultTimeoutMin']}"
/>
<p:inputText
id=
"defaultTimeout"
value=
"#{queueManageView.queue.defaultTimeoutMin}"
/>
<p:inputText
id=
"defaultTimeout"
value=
"#{queueManageView.queue.defaultTimeoutMin}"
/>
<h:outputText
value=
"#{i18n['queuemgmt.inDatabase']}: #{queueManageView.defaultValues.defaultTimeoutMin}"
/>
</p:panelGrid>
</p:panelGrid>
<p:commandButton
ajax=
"false"
value=
"#{i18n['queuemgmt.saveProperties']}"
></p:commandButton>
<p:commandButton
value=
"#{i18n['queuemgmt.saveProperties']}"
actionListener=
"#{queueManageView.saveToDatabase}"
update=
"queueGrid"
></p:commandButton>
</h:form>
</h:form>
...
...
code/moya-web/WebContent/neomap/reserve.xhtml
View file @
36f285a
...
@@ -70,18 +70,22 @@
...
@@ -70,18 +70,22 @@
</p:column>
</p:column>
</p:dataTable>
</p:dataTable>
<br
/><br
/>
<ui:fragment
rendered=
"#{ajaxMapView.reserving}"
>
<ui:fragment
rendered=
"#{ajaxMapView.reserving}"
>
<div
style=
"margin: 5px;"
>
<div
style=
"margin: 5px;"
>
<h:form
id=
"placeselectform"
>
<h:form
id=
"placeselectform"
>
<p:commandButton
onclick=
"$(window).unbind('beforeunload');"
rendered=
"#{ajaxMapView.canUserBuy()}"
value=
"#{i18n['mapView.buyPlaces']}"
actionListener=
"#{ajaxMapView.buySelectedPlaces()}"
/>
<p:commandButton
onclick=
"$(window).unbind('beforeunload');"
rendered=
"#{ajaxMapView.canUserBuy()}"
value=
"#{i18n['mapView.buyPlaces']}"
actionListener=
"#{ajaxMapView.buySelectedPlaces()}"
/>
</h:form>
</h:form>
</div>
</div>
<h:outputText
value=
"#{i18n['mapView.reserveTimeLeft']}: "
/>
<span
id=
"reserveTimeLeft"
/><br/>
</ui:fragment>
</ui:fragment>
<!-- Print queue status -->
<!-- Print queue status -->
<ui:fragment
rendered=
"#{ajaxMapView.queueEnabled and not ajaxMapView.reserving}"
>
<ui:fragment
rendered=
"#{ajaxMapView.queueEnabled and not ajaxMapView.reserving}"
>
<h3><h:outputText
value=
"#{i18n['mapView.youAreInQueue']}"
/></h3>
<h3><h:outputText
value=
"#{i18n['mapView.youAreInQueue']}"
/></h3>
<h4><h:outputText
value=
"#{i18n['queuemgmt.biggestIsFirst']}"
/>
</h4>
<div
style=
"margin: 1em;"
>
<div
style=
"margin: 1em;"
>
<h:outputText
value=
"#{i18n['mapView.queuePosition']}: "
/>
<h:outputText
value=
"#{i18n['mapView.queuePosition']}: "
/>
...
@@ -98,6 +102,7 @@
...
@@ -98,6 +102,7 @@
<script
type=
"text/javascript"
>
<script
type=
"text/javascript"
>
// Queue is enabled and we are reserving.
// Queue is enabled and we are reserving.
var
queueReserving
=
#
{(
ajaxMapView
.
queueEnabled
and
not
ajaxMapView
.
reserving
)?
"true"
:
"false"
};
var
queueReserving
=
#
{(
ajaxMapView
.
queueEnabled
and
not
ajaxMapView
.
reserving
)?
"true"
:
"false"
};
var
queueSelectingPlaces
=
#
{(
ajaxMapView
.
queueEnabled
and
ajaxMapView
.
reserving
)?
"true"
:
"false"
};
function
updateMap
()
{
function
updateMap
()
{
...
@@ -114,6 +119,23 @@
...
@@ -114,6 +119,23 @@
}).
fail
(
function
()
{
}).
fail
(
function
()
{
location
.
reload
();
location
.
reload
();
});
});
}
else
if
(
queueSelectingPlaces
)
{
$
.
getJSON
(
"#{request.contextPath}/rest/placemap/v1/queueStillReserving/#{ajaxMapView.map.id}/#{ajaxMapView.eventuser.id}"
)
.
done
(
function
(
data
)
{
if
(
data
.
value
==
0
)
{
alert
(
"#{i18n['reservequeue.reservingTimeIsUpAlert']}"
);
$
(
window
).
unbind
(
'beforeunload'
);
location
.
href
=
"/"
;
}
var
secsLeft
=
(
#
{
ajaxMapView
.
reservingTimeslotEndtime
}
/1000
)
-
((
new Date
())
.getTime
()
/
1000
);
$
(
"#reserveTimeLeft"
).
text
(
Math
.
floor
(
secsLeft
/
60
)
+
":"
+
Math
.
round
(
secsLeft
-
(
60
*
Math
.
floor
(
secsLeft
/
60
)
)
)
);
}).
fail
(
function
()
{
location
.
reload
();
});
}
}
}
}
...
@@ -130,7 +152,6 @@
...
@@ -130,7 +152,6 @@
location
.
reload
();
location
.
reload
();
}
else
{
}
else
{
$
(
"#queuepos"
).
text
(
data
.
value
);
$
(
"#queuepos"
).
text
(
data
.
value
);
var
d
=
new
Date
();
$
(
"#queueupdated"
).
text
(
new
Date
().
toTimeString
().
replace
(
/.*
(\d{2}
:
\d{2}
:
\d{2})
.*/
,
"$1"
));
$
(
"#queueupdated"
).
text
(
new
Date
().
toTimeString
().
replace
(
/.*
(\d{2}
:
\d{2}
:
\d{2})
.*/
,
"$1"
));
}
}
}
}
...
...
code/moya-web/src/main/java/fi/codecrew/moya/rest/placemap/v1/PlacemapRestViewV1.java
View file @
36f285a
...
@@ -181,6 +181,29 @@ public class PlacemapRestViewV1 {
...
@@ -181,6 +181,29 @@ public class PlacemapRestViewV1 {
return
root
;
return
root
;
}
}
@GET
@Path
(
"/queueStillReserving/{mapid}/{userid}"
)
public
IntegerRoot
getStillReserving
(
@PathParam
(
"mapid"
)
Integer
mapid
,
@PathParam
(
"userid"
)
Integer
userid
)
{
EventUser
user
=
null
;
if
(
userid
!=
null
)
{
user
=
userbean
.
findByEventUserId
(
userid
);
}
else
{
user
=
permbean
.
getCurrentUser
();
}
if
(
user
==
null
)
{
return
null
;
}
EventMap
map
=
placebean
.
findMap
(
mapid
);
IntegerRoot
root
=
new
IntegerRoot
();
root
.
setValue
(
quebean
.
isReserving
(
map
,
user
)?
1
:
0
);
return
root
;
}
@POST
@POST
@Path
(
"/place/{place}"
)
@Path
(
"/place/{place}"
)
public
Response
togglePlaceReservation
(
@PathParam
(
"place"
)
Integer
placeId
)
public
Response
togglePlaceReservation
(
@PathParam
(
"place"
)
Integer
placeId
)
...
@@ -200,7 +223,7 @@ public class PlacemapRestViewV1 {
...
@@ -200,7 +223,7 @@ public class PlacemapRestViewV1 {
boolean
success
=
false
;
boolean
success
=
false
;
if
(
p
.
isReservedFor
(
user
))
{
if
(
p
.
isReservedFor
(
user
))
{
success
=
placebean
.
r
eleasePlace
(
p
);
success
=
placebean
.
userR
eleasePlace
(
p
);
}
else
if
(
p
.
isBuyable
()
&&
!
p
.
isTaken
())
{
}
else
if
(
p
.
isBuyable
()
&&
!
p
.
isTaken
())
{
logger
.
info
(
"Rest Reserving place for place {}"
,
p
);
logger
.
info
(
"Rest Reserving place for place {}"
,
p
);
success
=
placebean
.
reservePlace
(
p
,
user
);
success
=
placebean
.
reservePlace
(
p
,
user
);
...
@@ -209,7 +232,7 @@ public class PlacemapRestViewV1 {
...
@@ -209,7 +232,7 @@ public class PlacemapRestViewV1 {
ResponseBuilder
resp
=
null
;
ResponseBuilder
resp
=
null
;
if
(
success
)
{
if
(
success
)
{
p
=
placebean
.
find
(
placeId
);
p
=
placebean
.
find
(
placeId
);
List
<
Place
>
thisplace
=
new
ArrayList
<
Place
>();
List
<
Place
>
thisplace
=
new
ArrayList
<>();
thisplace
.
add
(
p
);
thisplace
.
add
(
p
);
resp
=
Response
.
ok
(
PojoUtils
.
parseSimplePlaces
(
thisplace
,
user
,
permbean
.
hasPermission
(
UserPermission
.
VIEW_ALL
)));
resp
=
Response
.
ok
(
PojoUtils
.
parseSimplePlaces
(
thisplace
,
user
,
permbean
.
hasPermission
(
UserPermission
.
VIEW_ALL
)));
}
else
{
}
else
{
...
@@ -257,7 +280,7 @@ public class PlacemapRestViewV1 {
...
@@ -257,7 +280,7 @@ public class PlacemapRestViewV1 {
}
}
private
ArrayList
<
PlaceCodePojo
>
makePlaceCodePojos
(
List
<
Place
>
places
)
{
private
ArrayList
<
PlaceCodePojo
>
makePlaceCodePojos
(
List
<
Place
>
places
)
{
ArrayList
<
PlaceCodePojo
>
ret
=
new
ArrayList
<
PlaceCodePojo
>();
ArrayList
<
PlaceCodePojo
>
ret
=
new
ArrayList
<>();
for
(
Place
p
:
places
)
{
for
(
Place
p
:
places
)
{
if
(
p
.
getCode
()
==
null
||
p
.
getCode
().
isEmpty
())
{
if
(
p
.
getCode
()
==
null
||
p
.
getCode
().
isEmpty
())
{
String
newcode
=
null
;
String
newcode
=
null
;
...
...
code/moya-web/src/main/java/fi/codecrew/moya/web/cdiview/map/AjaxMapView.java
View file @
36f285a
package
fi
.
codecrew
.
moya
.
web
.
cdiview
.
map
;
package
fi
.
codecrew
.
moya
.
web
.
cdiview
.
map
;
import
java.
util.Collection
;
import
java.
awt.*
;
import
java.util.
HashMap
;
import
java.util.
*
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
javax.ejb.EJB
;
import
javax.ejb.EJB
;
import
javax.enterprise.context.RequestScoped
;
import
javax.enterprise.context.RequestScoped
;
...
@@ -232,6 +231,16 @@ public class AjaxMapView extends GenericCDIView {
...
@@ -232,6 +231,16 @@ public class AjaxMapView extends GenericCDIView {
return
reserving
;
return
reserving
;
}
}
public
long
getReservingTimeslotEndtime
()
{
Date
timeout
=
quebean
.
getReservationTimeout
(
initMap
());
if
(
timeout
==
null
)
return
0
;
return
timeout
.
getTime
();
}
public
boolean
canUserBuy
()
{
public
boolean
canUserBuy
()
{
return
permbean
.
hasPermission
(
MapPermission
.
BUY_PLACES
)
&&
(
permbean
.
hasPermission
(
MapPermission
.
MANAGE_OTHERS
)
return
permbean
.
hasPermission
(
MapPermission
.
BUY_PLACES
)
&&
(
permbean
.
hasPermission
(
MapPermission
.
MANAGE_OTHERS
)
||
quebean
.
isReserving
(
initMap
(),
userview
.
getSelectedUser
()));
||
quebean
.
isReserving
(
initMap
(),
userview
.
getSelectedUser
()));
...
...
code/moya-web/src/main/java/fi/codecrew/moya/web/cdiview/map/QueueManageView.java
View file @
36f285a
...
@@ -9,6 +9,7 @@ import javax.enterprise.context.ConversationScoped;
...
@@ -9,6 +9,7 @@ import javax.enterprise.context.ConversationScoped;
import
javax.faces.model.ListDataModel
;
import
javax.faces.model.ListDataModel
;
import
javax.inject.Named
;
import
javax.inject.Named
;
import
fi.codecrew.moya.model.MapQueueRules
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
...
@@ -38,6 +39,8 @@ public class QueueManageView extends GenericCDIView {
...
@@ -38,6 +39,8 @@ public class QueueManageView extends GenericCDIView {
private
EventMap
map
;
private
EventMap
map
;
private
MapQueueRules
rules
;
private
fi
.
codecrew
.
moya
.
beans
.
map
.
QueueBeanLocal
.
MapQueueI
queue
;
private
fi
.
codecrew
.
moya
.
beans
.
map
.
QueueBeanLocal
.
MapQueueI
queue
;
private
String
username
;
private
String
username
;
...
@@ -59,6 +62,8 @@ public class QueueManageView extends GenericCDIView {
...
@@ -59,6 +62,8 @@ public class QueueManageView extends GenericCDIView {
if
(
super
.
requirePermissions
(
MapPermission
.
MANAGE_MAPS
)
&&
map
==
null
)
{
if
(
super
.
requirePermissions
(
MapPermission
.
MANAGE_MAPS
)
&&
map
==
null
)
{
map
=
placebean
.
findMap
(
mapId
);
map
=
placebean
.
findMap
(
mapId
);
rules
=
quebean
.
findRules
(
map
);
queue
=
quebean
.
getMapQueue
(
map
);
queue
=
quebean
.
getMapQueue
(
map
);
logger
.
info
(
"Got queue {} for map {} with id {} to manage"
,
queue
,
map
,
mapId
);
logger
.
info
(
"Got queue {} for map {} with id {} to manage"
,
queue
,
map
,
mapId
);
super
.
beginConversation
();
super
.
beginConversation
();
...
@@ -154,4 +159,13 @@ public class QueueManageView extends GenericCDIView {
...
@@ -154,4 +159,13 @@ public class QueueManageView extends GenericCDIView {
public
void
setTime
(
Date
time
)
{
public
void
setTime
(
Date
time
)
{
this
.
time
=
time
;
this
.
time
=
time
;
}
}
public
void
saveToDatabase
()
{
quebean
.
saveQueue
(
queue
,
map
);
rules
=
quebean
.
findRules
(
map
);
// refresh
}
public
MapQueueRules
getDefaultValues
()
{
return
rules
;
}
}
}
code/moya-web/src/main/resources/fi/codecrew/moya/resources/i18n.properties
View file @
36f285a
...
@@ -899,7 +899,7 @@ queuemgmt.defaultTimeoutMin = Reservation time
...
@@ -899,7 +899,7 @@ queuemgmt.defaultTimeoutMin = Reservation time
queuemgmt.minimumSlotsInQueue
=
Minimum amount of places to enter queue
queuemgmt.minimumSlotsInQueue
=
Minimum amount of places to enter queue
queuemgmt.remove
=
Remove user from queue
queuemgmt.remove
=
Remove user from queue
queuemgmt.reservingSize
=
Number of people reserving at the same time
queuemgmt.reservingSize
=
Number of people reserving at the same time
queuemgmt.saveProperties
=
Save properties
queuemgmt.saveProperties
=
Save properties
to Database
queuemgmt.time
=
Reservation time
queuemgmt.time
=
Reservation time
queuemgmt.username
=
Login
queuemgmt.username
=
Login
...
@@ -1582,3 +1582,8 @@ yes = Yes
...
@@ -1582,3 +1582,8 @@ yes = Yes
page.product.shopClosed.header
=
Shop is closed!
page.product.shopClosed.header
=
Shop is closed!
page.product.shopClosed.notOpenYet
=
Shop is not opened. Try again later.
page.product.shopClosed.notOpenYet
=
Shop is not opened. Try again later.
page.product.shopClosed.alreadyClosed
=
Shop is closed, welcome back in next event!
page.product.shopClosed.alreadyClosed
=
Shop is closed, welcome back in next event!
queuemgmt.inDatabase
=
Value in database
queuemgmt.biggestFirst
=
Biggest group first
queuemgmt.biggestIsFirst
=
Bigger group automaticly rises up in queue.
reservequeue.reservingTimeIsUpAlert
=
Timeslot for your place reservation has timeouted. Pleace go back to queue to continue.
mapView.reserveTimeLeft
=
Time to reserve places
code/moya-web/src/main/resources/fi/codecrew/moya/resources/i18n_en.properties
View file @
36f285a
...
@@ -1163,7 +1163,7 @@ queuemgmt.defaultTimeoutMin = Reservation time
...
@@ -1163,7 +1163,7 @@ queuemgmt.defaultTimeoutMin = Reservation time
queuemgmt.minimumSlotsInQueue
=
Minimum amount of places to enter queue
queuemgmt.minimumSlotsInQueue
=
Minimum amount of places to enter queue
queuemgmt.remove
=
Remove user from queue
queuemgmt.remove
=
Remove user from queue
queuemgmt.reservingSize
=
Number of people reserving at the same time
queuemgmt.reservingSize
=
Number of people reserving at the same time
queuemgmt.saveProperties
=
Save properties
queuemgmt.saveProperties
=
Save properties
to Database
queuemgmt.time
=
Reservation time
queuemgmt.time
=
Reservation time
queuemgmt.username
=
Login
queuemgmt.username
=
Login
...
@@ -1860,3 +1860,8 @@ yes = Yes
...
@@ -1860,3 +1860,8 @@ yes = Yes
page.product.shopClosed.header
=
Shop is closed!
page.product.shopClosed.header
=
Shop is closed!
page.product.shopClosed.notOpenYet
=
Shop is not opened. Try again later.
page.product.shopClosed.notOpenYet
=
Shop is not opened. Try again later.
page.product.shopClosed.alreadyClosed
=
Shop is closed, welcome back in next event!
page.product.shopClosed.alreadyClosed
=
Shop is closed, welcome back in next event!
queuemgmt.inDatabase
=
Value in database
queuemgmt.biggestFirst
=
Biggest group first
queuemgmt.biggestIsFirst
=
Bigger group automaticly rises up in queue.
reservequeue.reservingTimeIsUpAlert
=
Timeslot for your place reservation has timeouted. Pleace go back to queue to continue.
mapView.reserveTimeLeft
=
Time to reserve places
code/moya-web/src/main/resources/fi/codecrew/moya/resources/i18n_fi.properties
View file @
36f285a
...
@@ -1150,7 +1150,7 @@ queuemgmt.defaultTimeoutMin = Varausaika
...
@@ -1150,7 +1150,7 @@ queuemgmt.defaultTimeoutMin = Varausaika
queuemgmt.minimumSlotsInQueue
=
Jonoonp
\u
00E4
\u
00E4syn v
\u
00E4himm
\u
00E4ispaikkam
\u
00E4
\u
00E4r
\u
00E4
queuemgmt.minimumSlotsInQueue
=
Jonoonp
\u
00E4
\u
00E4syn v
\u
00E4himm
\u
00E4ispaikkam
\u
00E4
\u
00E4r
\u
00E4
queuemgmt.remove
=
Poista k
\u
00E4ytt
\u
00E4j
\u
00E4 jonosta
queuemgmt.remove
=
Poista k
\u
00E4ytt
\u
00E4j
\u
00E4 jonosta
queuemgmt.reservingSize
=
Samanaikaisesti varaamaan p
\u
00E4
\u
00E4sevien m
\u
00E4
\u
00E4r
\u
00E4
queuemgmt.reservingSize
=
Samanaikaisesti varaamaan p
\u
00E4
\u
00E4sevien m
\u
00E4
\u
00E4r
\u
00E4
queuemgmt.saveProperties
=
Tallenna arvot
queuemgmt.saveProperties
=
Tallenna arvot
tietokantaan
queuemgmt.time
=
Varausaika
queuemgmt.time
=
Varausaika
queuemgmt.username
=
K
\u
00E4ytt
\u
00E4j
\u
00E4tunnus
queuemgmt.username
=
K
\u
00E4ytt
\u
00E4j
\u
00E4tunnus
...
@@ -1847,3 +1847,8 @@ yes = Kyll\u00E4
...
@@ -1847,3 +1847,8 @@ 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
\u
00E4 alkanut, Kokeile uudelleen my
\u
00F6hemmin.
page.product.shopClosed.notOpenYet
=
Tapahtuman lipunmyynti ei ole viel
\u
00E4 alkanut, Kokeile uudelleen my
\u
00F6hemmin.
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.biggestFirst
=
Isoin ryhm
\u
00E4 ensin
queuemgmt.biggestIsFirst
=
Isompi ryhm
\u
00E4 nousee automaattisesti jonossa edemm
\u
00E4ksi.
reservequeue.reservingTimeIsUpAlert
=
Sinulle varattu varausauka on kulunut loppuun! Palaa takaisin 'varaa paikkasi' -sivulle jatkaaksesi.
mapView.reserveTimeLeft
=
Aikaa varata paikkasi
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment