Commit 15355127 by Tuukka Kivilahti

Merge branch 'gitversion' into 'master'

Fix parsing of git version from package generation

There was already a somewhat broken version of maven
plugin which saves the current git versions from build
time. Fixed it.. :)

TODO: Show git build version, build date, etc on every page?

See merge request !371
2 parents ac295b49 f71032c4
...@@ -20,10 +20,10 @@ ...@@ -20,10 +20,10 @@
<!-- this is false by default, forces the plugin to generate the git.properties <!-- this is false by default, forces the plugin to generate the git.properties
file --> file -->
<generateGitPropertiesFile>true</generateGitPropertiesFile> <generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>./target/classes/git.properties</generateGitPropertiesFilename>
<!-- The path for the to be generated properties file, it's relative <!-- The path for the to be generated properties file, it's relative
to ${project.basedir} --> to ${project.basedir} -->
<generateGitPropertiesFilename>src/main/java/moya-git.properties</generateGitPropertiesFilename>
<dotGitDirectory>${project.basedir}/../../.git</dotGitDirectory> <dotGitDirectory>${project.basedir}/../../.git</dotGitDirectory>
</configuration> </configuration>
</plugin> </plugin>
......
...@@ -26,8 +26,6 @@ public enum MapPermission implements IAppPermission { ...@@ -26,8 +26,6 @@ public enum MapPermission implements IAppPermission {
VIEW, // ("View maps"), VIEW, // ("View maps"),
MANAGE_MAPS, MANAGE_MAPS,
MOVE_PLACES, MOVE_PLACES,
//RELEASE_PLACE, // ("Create and modify maps")
; ;
public static final String S_MANAGE_OTHERS = "MAP/MANAGE_OTHERS"; public static final String S_MANAGE_OTHERS = "MAP/MANAGE_OTHERS";
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
*/ */
package fi.codecrew.moya.utilities; package fi.codecrew.moya.utilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Properties; import java.util.Properties;
...@@ -25,100 +28,43 @@ import java.util.Properties; ...@@ -25,100 +28,43 @@ import java.util.Properties;
public class GitRepositoryState { public class GitRepositoryState {
private static GitRepositoryState gitRepositoryState; private static GitRepositoryState gitRepositoryState;
private static final Logger logger = LoggerFactory.getLogger(GitRepositoryState.class);
private final Properties properties;
public static GitRepositoryState getGitRepositoryState() throws IOException public static GitRepositoryState getGitRepositoryState() {
{
if (gitRepositoryState == null) { if (gitRepositoryState == null) {
gitRepositoryState = new GitRepositoryState(); gitRepositoryState = new GitRepositoryState();
} }
return gitRepositoryState; return gitRepositoryState;
} }
private final String branch; private GitRepositoryState() {
private final String describe; logger.info("Initializing git status");
private final String describeShort; this.properties = new Properties();
private final String commitId; try {
private final String buildUserName; InputStream resource = getClass().getResourceAsStream("/git.properties");
private final String buildUserEmail;
private final String buildTime; if (resource == null) {
private final String commitUserName; logger.warn("Resource not found!");
private final String commitUserEmail; return;
private final String commitMessageShort; }
private final String commitMessageFull;
private final String commitTime; this.properties.load(resource);
logger.info("Git keys:", this.properties.keys());
private GitRepositoryState() throws IOException } catch (IOException e) {
{ logger.warn("Error initializing git proerties", e);
InputStream resource = getClass().getClassLoader().getResourceAsStream("moya-git.properties");
if (resource == null)
{
throw new IOException("ResourceFile not found");
} }
Properties properties = new Properties();
properties.load(resource);
this.branch = properties.get("git.branch").toString();
this.describe = properties.get("git.commit.id.describe").toString();
this.describeShort = properties.get("git.commit.id.describe-short").toString();
this.commitId = properties.get("git.commit.id").toString();
this.buildUserName = properties.get("git.build.user.name").toString();
this.buildUserEmail = properties.get("git.build.user.email").toString();
this.buildTime = properties.get("git.build.time").toString();
this.commitUserName = properties.get("git.commit.user.name").toString();
this.commitUserEmail = properties.get("git.commit.user.email").toString();
this.commitMessageShort = properties.get("git.commit.message.short").toString();
this.commitMessageFull = properties.get("git.commit.message.full").toString();
this.commitTime = properties.get("git.commit.time").toString();
}
public String getBranch() {
return branch;
}
public String getDescribe() {
return describe;
}
public String getDescribeShort() {
return describeShort;
}
public String getCommitId() {
return commitId;
}
public String getBuildUserName() {
return buildUserName;
}
public String getBuildUserEmail() {
return buildUserEmail;
}
public String getBuildTime() {
return buildTime;
}
public String getCommitUserName() {
return commitUserName;
} }
public String getCommitUserEmail() { public String getProperty(String key) {
return commitUserEmail; String retStr = null;
} if (properties != null || key != null) {
Object ret = properties.get(key);
public String getCommitMessageShort() { if (ret != null) {
return commitMessageShort; retStr = ret.toString();
} }
}
public String getCommitMessageFull() { return retStr;
return commitMessageFull;
}
public String getCommitTime() {
return commitTime;
} }
} }
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<f:event type="preRenderView" listener="#{billListView.initUsersBills}" /> <f:event type="preRenderView" listener="#{billListView.initUsersBills}" />
</f:metadata> </f:metadata>
<h1><h:outputText value="#{i18n['bill.list.header']}" />></h1>
<ui:define name="content"> <ui:define name="content">
<h:form id="billList" styleClass="moya_datatable3"> <h:form id="billList" styleClass="moya_datatable3">
......
...@@ -28,9 +28,17 @@ ...@@ -28,9 +28,17 @@
<h3> <h3>
<h:outputText value="#{i18n['placemove.header']}"/> <h:outputText value="#{i18n['placemove.header']}"/>
</h3> </h3>
<p:fragment id="placeselector">
<h:form>
<h:outputText value="#{i18n['placemove.noMovablePlaces']}" rendered="#{mapPlacechangeView.slots.rowCount == 0}"/>
<p:fragment id="placeselector" rendered="#{mapPlacechangeView.slots.rowCount > 0}">
<ui:fragment rendered="#{!mapPlacechangeView.movingForSelf}">
<h2><h:link outcome="/useradmin/edit" value="#{i18n['placemove.movingFor']}: #{mapPlacechangeView.user.wholeName}">
<f:param value="#{mapPlacechangeView.user.user.id}" name="userid"/>
</h:link></h2>
</ui:fragment>
<h:form>
<p:dataTable id="slottable" tableStyle="width: auto;" var="slot" <p:dataTable id="slottable" tableStyle="width: auto;" var="slot"
value="#{mapPlacechangeView.slots}"> value="#{mapPlacechangeView.slots}">
<!-- rowStyleClass="#{mapPlacechangeView.srcPlace.contains(slot.place) ? 'selected' : 'unselected'}" --> <!-- rowStyleClass="#{mapPlacechangeView.srcPlace.contains(slot.place) ? 'selected' : 'unselected'}" -->
...@@ -46,7 +54,7 @@ ...@@ -46,7 +54,7 @@
</p:column> </p:column>
<p:column headerText="#{i18n['placemove.placeuser']}"> <p:column headerText="#{i18n['placemove.placeuser']}">
<h:outputText rendered="#{!empty slot.src.place.currentUser}" <h:outputText rendered="#{!empty slot.src.place.currentUser}"
value="#{slot.src.place.currentUser.wholeNmae}"/> value="#{slot.src.place.currentUser.wholeName}"/>
<h:outputText rendered="#{empty slot.src.place.currentUser}" <h:outputText rendered="#{empty slot.src.place.currentUser}"
value="-"/> value="-"/>
</p:column> </p:column>
...@@ -83,7 +91,6 @@ ...@@ -83,7 +91,6 @@
<h:form id="placemove"> <h:form id="placemove">
<p:commandButton <p:commandButton
disabled="#{!mapPlacechangeView.isReadyForCommit()}" disabled="#{!mapPlacechangeView.isReadyForCommit()}"
rendered="#{ajaxMapView.canUserBuy()}"
value="#{i18n['placemove.commitMove']}" value="#{i18n['placemove.commitMove']}"
action="#{mapPlacechangeView.commitMove()}" ajax="false"/> action="#{mapPlacechangeView.commitMove()}" ajax="false"/>
</h:form> </h:form>
......
...@@ -22,9 +22,7 @@ ...@@ -22,9 +22,7 @@
</ui:define> </ui:define>
<ui:define name="content"> <ui:define name="content">
<h:link outcome="/neomap/moveplaces" value="#{i18n['placegroupview.moveUsersPlaces']}">
<f:param name="userId" value="#{userView.user.user.id}"/>
</h:link>
<h:outputText rendered="#{empty placeGroupView.groupMemberships}" <h:outputText rendered="#{empty placeGroupView.groupMemberships}"
value="#{i18n['placegroupview.noMemberships']}"/> value="#{i18n['placegroupview.noMemberships']}"/>
...@@ -76,6 +74,10 @@ ...@@ -76,6 +74,10 @@
value="#{i18n['placegroup.printPdf']}"/> value="#{i18n['placegroup.printPdf']}"/>
</p> </p>
<h:link outcome="/neomap/moveplaces" value="#{i18n['placegroupview.moveUsersPlaces']}">
<f:param name="userId" value="#{userView.user.user.id}"/>
</h:link>
<h2>#{i18n['placetoken.pageHeader']}</h2> <h2>#{i18n['placetoken.pageHeader']}</h2>
<p>#{i18n['placetoken.topText']}</p> <p>#{i18n['placetoken.topText']}</p>
<h:form id="placeTokenForm"> <h:form id="placeTokenForm">
......
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "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" <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:c="http://java.sun.com/jsp/jstl/core">
<h:body> <h:body>
<ui:composition template="#{sessionHandler.template}"> <ui:composition template="#{sessionHandler.template}">
<ui:define name="content"> <ui:define name="content">
#{sessionHandler.flushCache()} Buttons have moved to <h:link outcome="/utils/index/"/> This page just clears cache.. Use with caution!
#{sessionHandler.flushCache()}
<h:form>
<!-- Enable only when needed: -->
<h:commandButton action="#{testView.sendMultibuggageSpam}" value="MULTIUSERSPAM" onclick="return confirm('SPAMSPAMSPAMS?!');" />
<h:commandButton action="#{testView.resetMenu()}" value="Reset to newui menu" onclick="return confirm('THIS WILL RESET ALL MODIFICATIONS TO DEFAULT MENU!!\n Are you really sure?!');" />
<h:commandButton action="#{testView.resetOldMenu()}" value="Reset to old menu" onclick="return confirm('THIS WILL RESET ALL MODIFICATIONS TO DEFAULT MENU!!\n Are you really sure?!');" />
</h:form>
</ui:define> </ui:define>
</ui:composition> </ui:composition>
</h:body> </h:body>
......
<!DOCTYPE html <!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "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" <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:users="http://java.sun.com/jsf/composite/tools/user" xmlns:c="http://java.sun.com/jsp/jstl/core"> xmlns:users="http://java.sun.com/jsf/composite/tools/user" xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:body> <h:body>
<ui:composition template="#{sessionHandler.template}"> <ui:composition template="#{sessionHandler.template}">
<ui:param name="thispage" value="page.eventorg.edit" />
<ui:define name="content"> <ui:define name="content">
<h1>Random utility stuff</h1>
<h:form> <h:form>
<ul>
<li><h:commandButton action="#{sessionHandler.flushCache()}" value="Flush cache"/></li>
<li><h:commandButton action="#{testView.makeTestData()}" value="Make test data"/></li>
<li><h:commandButton action="#{testView.resetMenu()}" value="Reset to newui menu"
onclick="return confirm('THIS WILL RESET ALL MODIFICATIONS TO DEFAULT MENU!!\n Are you really sure?!');"/></li>
<li><h:commandButton action="#{testView.resetOldMenu()}" value="Reset to old menu"
onclick="return confirm('THIS WILL RESET ALL MODIFICATIONS TO DEFAULT MENU!!\n Are you really sure?!');"/></li>
<li><h:commandButton action="#{testView.sendMultibuggageSpam}" value="MULTIUSERSPAM" onclick="return confirm('SPAMSPAMSPAMS?!');"/></li>
<h:commandButton action="#{sessionHandler.flushCache()}" value="Flush cache" /> </ul>
<h:commandButton action="#{testView.makeTestData()}" value="Make test data" />
<h:commandButton action="#{testView.resetMenu()}" value="Reset menu" onclick="return confirm('THIS WILL RESET ALL MODIFICATIONS TO DEFAULT MENU!!\n Are you really sure?!');" />
<h:commandButton action="#{sessionHandler.reindexCompass()}" value="Reindex Compass" />
</h:form> </h:form>
<h2>Version data</h2>
<ul>
<li>Build time #{testView.gitProps.getProperty('git.build.time')}</li>
<li>Build user: #{testView.gitProps.getProperty('git.build.user.name')}</li>
<li>Commit time #{testView.gitProps.getProperty('git.commit.time')}</li>
<li>Git id #{testView.gitProps.getProperty('git.commit.id.abbrev')}</li>
</ul>
</ui:define> </ui:define>
</ui:composition> </ui:composition>
</h:body> </h:body>
......
<!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:users="http://java.sun.com/jsf/composite/tools/user"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:body>
<ui:composition template="#{sessionHandler.template}">
<ui:param name="thispage" value="page.eventorg.edit" />
<ui:define name="content">
#{sessionHandler.reindexCompass()}
</ui:define>
</ui:composition>
</h:body>
</html>
\ No newline at end of file
...@@ -21,7 +21,9 @@ package fi.codecrew.moya.web; ...@@ -21,7 +21,9 @@ package fi.codecrew.moya.web;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.Serializable; import java.io.Serializable;
import java.io.StringWriter; import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.Base64;
import java.util.Map; import java.util.Map;
import java.util.zip.CRC32; import java.util.zip.CRC32;
...@@ -86,7 +88,13 @@ public class ErrorPageView implements Serializable { ...@@ -86,7 +88,13 @@ public class ErrorPageView implements Serializable {
} }
public String getTime() { public String getTime() {
String stamp = "0x" + Long.toHexString(System.currentTimeMillis()); ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
// Casting to int will give us millisecond precision for about 24 days
// which should be enough for our purposes..
buffer.putInt((int)System.currentTimeMillis());
String stamp = Base64.getEncoder().encodeToString(buffer.array());
// We don't need padding.. get rid of them.
stamp = stamp.replace("=","");
logger.error("Error occured at {} trail {}", stamp, getTrail()); logger.error("Error occured at {} trail {}", stamp, getTrail());
return stamp; return stamp;
} }
......
...@@ -30,6 +30,7 @@ import javax.enterprise.context.RequestScoped; ...@@ -30,6 +30,7 @@ import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import fi.codecrew.moya.utilities.GitRepositoryState;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -105,6 +106,10 @@ public class TestDataView extends GenericCDIView { ...@@ -105,6 +106,10 @@ public class TestDataView extends GenericCDIView {
return null; return null;
} }
public GitRepositoryState getGitProps() {
return GitRepositoryState.getGitRepositoryState();
}
public void sendMultibuggageSpam() { public void sendMultibuggageSpam() {
......
...@@ -119,6 +119,10 @@ public class MapPlacechangeView extends GenericCDIView { ...@@ -119,6 +119,10 @@ public class MapPlacechangeView extends GenericCDIView {
} }
} }
public boolean isMovingForSelf(){
return permbean.getCurrentUser().equals(user);
}
public String commitMove() { public String commitMove() {
HashMap<Place, Place> change = new HashMap<Place, Place>(); HashMap<Place, Place> change = new HashMap<Place, Place>();
......
...@@ -83,7 +83,6 @@ bortalApplication.license.VIEW_OWN_CODES = Can view own licenses ...@@ -83,7 +83,6 @@ bortalApplication.license.VIEW_OWN_CODES = Can view own licenses
bortalApplication.map.BUY_PLACES = Reserve and buy places from map bortalApplication.map.BUY_PLACES = Reserve and buy places from map
bortalApplication.map.MANAGE_MAPS = Create and modify maps bortalApplication.map.MANAGE_MAPS = Create and modify maps
bortalApplication.map.MANAGE_OTHERS = Manage other users reservations in map bortalApplication.map.MANAGE_OTHERS = Manage other users reservations in map
bortalApplication.map.RELEASE_PLACE = Can release place
bortalApplication.map.VIEW = View maps bortalApplication.map.VIEW = View maps
bortalApplication.poll.ANSWER = Can answer and view availabe polls bortalApplication.poll.ANSWER = Can answer and view availabe polls
bortalApplication.poll.CREATE = Create and manage polls bortalApplication.poll.CREATE = Create and manage polls
...@@ -1610,3 +1609,6 @@ product.dependency.MAX_SUPPORTED_COUNT=Only up to same number of products can be ...@@ -1610,3 +1609,6 @@ product.dependency.MAX_SUPPORTED_COUNT=Only up to same number of products can be
submenu.neomap.moveplaces=Change places submenu.neomap.moveplaces=Change places
mapEdit.removeSelectedPlaces=Delete places mapEdit.removeSelectedPlaces=Delete places
bortalApplication.map.MOVE_PLACES =Selfservice place moving
bill.list.header =Orders
placemove.noMovablePlaces =No movable places
...@@ -171,7 +171,6 @@ bortalApplication.license.VIEW_OWN_CODES = Can view ...@@ -171,7 +171,6 @@ bortalApplication.license.VIEW_OWN_CODES = Can view
bortalApplication.map.BUY_PLACES = Reserve and buy places from map bortalApplication.map.BUY_PLACES = Reserve and buy places from map
bortalApplication.map.MANAGE_MAPS = Create and modify maps bortalApplication.map.MANAGE_MAPS = Create and modify maps
bortalApplication.map.MANAGE_OTHERS = Manage other users reservations in map bortalApplication.map.MANAGE_OTHERS = Manage other users reservations in map
bortalApplication.map.RELEASE_PLACE = Can release place
bortalApplication.map.VIEW = View maps bortalApplication.map.VIEW = View maps
bortalApplication.networkauthentication.CAN_ADMINISTER_ASSOCIATIONS = Can manage network associations bortalApplication.networkauthentication.CAN_ADMINISTER_ASSOCIATIONS = Can manage network associations
bortalApplication.networkauthentication.CAN_ASSOCIATE = Can associate to network bortalApplication.networkauthentication.CAN_ASSOCIATE = Can associate to network
...@@ -1891,3 +1890,6 @@ placemove.alreadyTaken=Moving the places was cancelled because place {0} was alr ...@@ -1891,3 +1890,6 @@ placemove.alreadyTaken=Moving the places was cancelled because place {0} was alr
placegroupview.moveUsersPlaces=Move users places placegroupview.moveUsersPlaces=Move users places
submenu.neomap.moveplaces=Change places submenu.neomap.moveplaces=Change places
mapEdit.removeSelectedPlaces=Delete places mapEdit.removeSelectedPlaces=Delete places
bortalApplication.map.MOVE_PLACES = Selfservice place moving
bill.list.header = Orders
placemove.noMovablePlaces = No movable places
...@@ -172,8 +172,7 @@ bortalApplication.license.VIEW_OWN_CODES = Voi katse ...@@ -172,8 +172,7 @@ bortalApplication.license.VIEW_OWN_CODES = Voi katse
bortalApplication.map.BUY_PLACES = Voi varata ja ostaa konepaikkoja kartalta bortalApplication.map.BUY_PLACES = Voi varata ja ostaa konepaikkoja kartalta
bortalApplication.map.MANAGE_MAPS = Saa luoda ja muokata karttoja bortalApplication.map.MANAGE_MAPS = Saa luoda ja muokata karttoja
bortalApplication.map.MANAGE_OTHERS = Saa hallita muiden k\u00E4ytt\u00E4jien varauksia kartalla bortalApplication.map.MANAGE_OTHERS = Saa hallita muiden k\u00E4ytt\u00E4jien varauksia kartalla
bortalApplication.map.RELEASE_PLACE = Voi vapauttaa paikan bortalApplication.map.RELEASE_PLACE = Voi vapauttaa paikanbortalApplication.map.VIEW = Saa n\u00E4hd\u00E4 kartat
bortalApplication.map.VIEW = Saa n\u00E4hd\u00E4 kartat
bortalApplication.networkauthentication.CAN_ADMINISTER_ASSOCIATIONS = Saa hallinnoida verkkoon liittymisi\u00E4 bortalApplication.networkauthentication.CAN_ADMINISTER_ASSOCIATIONS = Saa hallinnoida verkkoon liittymisi\u00E4
bortalApplication.networkauthentication.CAN_ASSOCIATE = Saa liitty\u00E4 verkkoon bortalApplication.networkauthentication.CAN_ASSOCIATE = Saa liitty\u00E4 verkkoon
bortalApplication.networkauthentication.CAN_ASSOCIATE_MANY_PER_PLACE = Saa liitt\u00E4\u00E4 useamman laitteen samaan paikkaan bortalApplication.networkauthentication.CAN_ASSOCIATE_MANY_PER_PLACE = Saa liitt\u00E4\u00E4 useamman laitteen samaan paikkaan
...@@ -1877,3 +1876,7 @@ placemove.alreadyTaken=Paikkojen siirto peruuntui koska paikka {0} oli jo varatt ...@@ -1877,3 +1876,7 @@ placemove.alreadyTaken=Paikkojen siirto peruuntui koska paikka {0} oli jo varatt
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
bill.list.header = Tilaukset
placemove.noMovablePlaces = Ei siirrett\u00E4vi\u00E4 paikkoja
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!