Commit 73de394a by Tuomas Riihimäki

merged..

2 parents 1ac3c7b1 0ffb1686
Showing with 646 additions and 286 deletions
......@@ -21,6 +21,7 @@ import com.pdfjet.TextLine;
import fi.insomnia.bortal.facade.CardTemplateFacade;
import fi.insomnia.bortal.facade.EventUserFacade;
import fi.insomnia.bortal.facade.UserFacade;
import fi.insomnia.bortal.model.CardTemplate;
import fi.insomnia.bortal.model.EventUser;
import fi.insomnia.bortal.model.PrintedCard;
......@@ -34,49 +35,54 @@ import fi.insomnia.bortal.utilities.BarcodeUtils;
@LocalBean
public class CardPrintBean implements CardPrintBeanLocal {
@EJB private UserBean userBean;
@EJB private EventUserFacade eventUserFacade;
@EJB private CardTemplateBean cardTemplateBean;
@EJB private CardTemplateFacade cardTemplateFacade;
/**
* Default constructor.
*/
public CardPrintBean() {
// TODO Auto-generated constructor stub
}
//TODO: Roles?
public MassPrintResult getUserCardsAsPrintablePdf(List<Integer> userIdList) throws Exception {
ArrayList<EventUser> listOfEventUsers = new ArrayList<EventUser>();
for(Integer userId : userIdList) {
listOfEventUsers.add(eventUserFacade.find(userId));
}
@EJB
private UserBean userBean;
@EJB
private EventUserFacade eventUserFacade;
@EJB
private CardTemplateBean cardTemplateBean;
@EJB
private CardTemplateFacade cardTemplateFacade;
@EJB
private UserFacade userfacade;
/**
* Default constructor.
*/
public CardPrintBean() {
// TODO Auto-generated constructor stub
}
// TODO: Roles?
public MassPrintResult getUserCardsAsPrintablePdf(List<Integer> userIdList) throws Exception {
ArrayList<EventUser> listOfEventUsers = new ArrayList<EventUser>();
for (Integer userId : userIdList) {
listOfEventUsers.add(eventUserFacade.find(userId));
}
return constructPdf(listOfEventUsers);
}
public MassPrintResult getUserCardAsPrintablePdf(Integer userId) throws Exception {
ArrayList<EventUser> listOfEventUsers = new ArrayList<EventUser>();
listOfEventUsers.add(eventUserFacade.find(userId));
return constructPdf(listOfEventUsers);
}
public void acceptMassPrintResult(MassPrintResult mpr) {
for(EventUser eu : mpr.getAffectedUsers()) {
PrintedCard printedCard = cardTemplateBean.checkPrintedCard(eu);
printedCard.setPrintCount(printedCard.getPrintCount()+1);
System.out.println("Print count "+printedCard.getPrintCount());
}
cardTemplateFacade.flush();
}
private MassPrintResult constructPdf(List<EventUser> users) throws Exception {
}
public MassPrintResult getUserCardAsPrintablePdf(Integer userId) throws Exception {
ArrayList<EventUser> listOfEventUsers = new ArrayList<EventUser>();
listOfEventUsers.add(eventUserFacade.find(userId));
return constructPdf(listOfEventUsers);
}
public void acceptMassPrintResult(MassPrintResult mpr) {
for (EventUser eu : mpr.getAffectedUsers()) {
PrintedCard printedCard = cardTemplateBean.checkPrintedCard(eu);
printedCard.setPrintCount(printedCard.getPrintCount() + 1);
System.out.println("Print count " + printedCard.getPrintCount());
}
cardTemplateFacade.flush();
}
private MassPrintResult constructPdf(List<EventUser> users) throws Exception {
// double[] pageSize = new double[] { cardBackground.getWidth(),
// cardBackground.getHeight() };
......@@ -88,91 +94,91 @@ public class CardPrintBean implements CardPrintBeanLocal {
double pagex = 155.52; // 54,0 mm
double pagey = 243.84; // 85,5 mm
MassPrintResult mpr = new MassPrintResult();
for(EventUser user : users) {
for (EventUser user : users) {
user = userfacade.reload(user);
PrintedCard printedCard = cardTemplateBean.checkPrintedCard(user);
if(printedCard == null)
if (printedCard == null)
continue;
CardTemplate cardTemplate = printedCard.getTemplate();
BufferedImage cardBackground = ImageIO.read(new ByteArrayInputStream(
cardTemplate.getImage()));
BufferedImage faceBufferedImage = ImageIO
.read(new ByteArrayInputStream(user.getCurrentImage()
.getImageData()));
int originalWidth = faceBufferedImage.getWidth();
int originalHeight = faceBufferedImage.getHeight();
int width = originalWidth;
int height = (int)Math.round(originalWidth*(1/0.7317073170731707));
if(height > originalHeight) {
int height = (int) Math.round(originalWidth * (1 / 0.7317073170731707));
if (height > originalHeight) {
height = originalHeight;
width = (int)Math.round(originalHeight*0.7317073170731707);
width = (int) Math.round(originalHeight * 0.7317073170731707);
}
int offsetx = (originalWidth - width)/2;
int offsety = (originalHeight - height)/2;
int offsetx = (originalWidth - width) / 2;
int offsety = (originalHeight - height) / 2;
faceBufferedImage = faceBufferedImage.getSubimage(offsetx, offsety, width, height);
Page page = new Page(pdf, new double[] { pagex, pagey });
// Render background image
Image templateImage = new Image(pdf,
convertBufferedImageToPng(cardBackground), ImageType.PNG);
templateImage.setPosition(0, 0);
templateImage.scaleBy(0.245);
templateImage.drawOn(page);
// Render face image
Image faceImage = new Image(pdf,
convertBufferedImageToPng(faceBufferedImage), ImageType.PNG);
faceImage.setPosition(15.5, 67);
//faceImage.scaleBy(0.32);
faceImage.scaleBy(((410.0*0.245)/faceImage.getHeight()));
// faceImage.scaleBy(0.32);
faceImage.scaleBy(((410.0 * 0.245) / faceImage.getHeight()));
faceImage.drawOn(page);
// Render texts
// Big font for nick
com.pdfjet.Font nickFont = new com.pdfjet.Font(pdf, CoreFont.HELVETICA);
nickFont.setSize(16.0);
// User nick text
TextLine nickTextLine = new TextLine(nickFont);
nickTextLine.setText(user.getUser().getNick());
nickTextLine.setPosition(19.0, 193.0);
nickTextLine.setColor(new double[] {1.0, 1.0, 1.0});
nickTextLine.setColor(new double[] { 1.0, 1.0, 1.0 });
nickTextLine.drawOn(page);
// Smaller font
com.pdfjet.Font font = new com.pdfjet.Font(pdf, CoreFont.HELVETICA);
font.setSize(10.0);
// Full name text
String wholeName = user.getUser().getFirstnames() + " "
+ user.getUser().getLastname();
TextLine wholeNameText = new TextLine(font);
wholeNameText.setText(wholeName);
wholeNameText.setPosition(17.0, 212.0);
wholeNameText.setColor(new double[] {1.0, 1.0, 1.0});
wholeNameText.setColor(new double[] { 1.0, 1.0, 1.0 });
wholeNameText.drawOn(page);
// Role text
TextLine roleTextLine = new TextLine(font);
roleTextLine.setText(cardTemplate.getName());
roleTextLine.setPosition(17.0, 223.0);
roleTextLine.setColor(new double[] {1.0, 1.0, 1.0});
roleTextLine.setColor(new double[] { 1.0, 1.0, 1.0 });
roleTextLine.drawOn(page);
// Barcode
String barcodeString = String.valueOf(user.getUser().getCreated()
.getTime().getTime());
......@@ -184,18 +190,19 @@ public class CardPrintBean implements CardPrintBeanLocal {
barCodeImage.setPosition(0.0, 243.5);
barCodeImage.scaleBy(0.7);
barCodeImage.drawOn(page);
mpr.getAffectedUsers().add(user);
}
pdf.flush();
outputStream.close();
if(mpr.getAffectedUsers().size() == 0) throw new Exception("No cards generated");
if (mpr.getAffectedUsers().size() == 0)
throw new Exception("No cards generated");
mpr.setPdf(outputStream.toByteArray());
return mpr;
}
private ByteArrayInputStream convertBufferedImageToPng(BufferedImage img)
}
private ByteArrayInputStream convertBufferedImageToPng(BufferedImage img)
throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
ImageIO.write(img, "png", outStream);
......
......@@ -47,7 +47,6 @@ public class MenuBean implements MenuBeanLocal {
@EJB
private PermissionBeanLocal permbean;
@SuppressWarnings("unused")
private static final Logger logger = LoggerFactory.getLogger(MenuBean.class);
@RolesAllowed(SpecialPermission.S_SUPERADMIN)
......@@ -58,11 +57,110 @@ public class MenuBean implements MenuBeanLocal {
initializeMenu();
}
@RolesAllowed(SpecialPermission.S_SUPERADMIN)
@Override
public void flushOldMenu()
{
navifacade.deleteAllDefaults();
initializeOldMenu();
}
private synchronized void initializeMenu() {
int menusort = 100;
logger.info("Initializing menu");
LanEvent ev = eventbean.getCurrentEvent();
// Etusivu
MenuNavigation frontnavi = new MenuNavigation(ev, "topnavi.frontpage", menusort = +10);
frontnavi.addPage(menuitemfacade.findOrCreate("/index"), UserPermission.ANYUSER);
navifacade.create(frontnavi);
// Kauppa
MenuNavigation shopTopmenu = new MenuNavigation(ev, "topnavi.shop", menusort = +10);
shopTopmenu.addPage(menuitemfacade.findOrCreate("/place/placemap"), MapPermission.VIEW);
shopTopmenu.addPage(menuitemfacade.findOrCreate("/place/myGroups"), UserPermission.VIEW_SELF);
shopTopmenu.addPage(null, null);
shopTopmenu.addPage(menuitemfacade.findOrCreate("/shop/createBill"), BillPermission.CREATE_BILL);
shopTopmenu.addPage(menuitemfacade.findOrCreate("/user/accountEvents"), UserPermission.VIEW_SELF);
shopTopmenu.addPage(menuitemfacade.findOrCreate("/bill/list"), BillPermission.VIEW_OWN);
MenuNavigation prodsubmenu = shopTopmenu.addPage(null, null);
prodsubmenu.setKey("topnavi.shop.products");
prodsubmenu.addPage(menuitemfacade.findOrCreate("/product/list"), ShopPermission.LIST_ALL_PRODUCTS);
prodsubmenu.addPage(menuitemfacade.findOrCreate("/product/create"), ShopPermission.MANAGE_PRODUCTS);
MenuNavigation adminshop = shopTopmenu.addPage(null, null);
adminshop.setKey("topnavi.shop.adminshop");
adminshop.addPage(menuitemfacade.findOrCreate("/shop/showReaderEvents"), ShopPermission.SHOP_TO_OTHERS);
adminshop.addPage(menuitemfacade.findOrCreate("/shop/listReaders"), ShopPermission.SHOP_TO_OTHERS);
MenuNavigation billnavi = shopTopmenu.addPage(null, null);
billnavi.setKey("topnavi.shop.bill");
billnavi.addPage(menuitemfacade.findOrCreate("/bill/billSummary"), BillPermission.READ_ALL);
billnavi.addPage(menuitemfacade.findOrCreate("/bill/listAll"), BillPermission.WRITE_ALL);
navifacade.create(shopTopmenu);
MenuNavigation eventTopmenu = new MenuNavigation(ev, "topnavi.event", menusort = +10);
eventTopmenu.addPage(menuitemfacade.findOrCreate("/map/list"), MapPermission.MANAGE_MAPS);
eventTopmenu.addPage(menuitemfacade.findOrCreate("/map/create"), MapPermission.MANAGE_MAPS);
eventTopmenu.addPage(null, null);
eventTopmenu.addPage(menuitemfacade.findOrCreate("/voting/compolist"), CompoPermission.VIEW_COMPOS);
eventTopmenu.addPage(menuitemfacade.findOrCreate("/voting/myEntries"), CompoPermission.VIEW_COMPOS);
eventTopmenu.addPage(menuitemfacade.findOrCreate("/voting/create"), CompoPermission.MANAGE);
eventTopmenu.addPage(null, null);
eventTopmenu.addPage(menuitemfacade.findOrCreate("/poll/index"), PollPermission.ANSWER);
navifacade.create(eventTopmenu);
MenuNavigation profileTopmenu = new MenuNavigation(ev, "topnavi.profile", menusort = +10);
profileTopmenu.addPage(menuitemfacade.findOrCreate("/useradmin/create"), UserPermission.VIEW_ALL);
profileTopmenu.addPage(menuitemfacade.findOrCreate("/useradmin/list"), UserPermission.VIEW_ALL).setHeader("submenu.user.manageuserlinks");
profileTopmenu.addPage(menuitemfacade.findOrCreate("/user/edit"), UserPermission.VIEW_SELF);
profileTopmenu.addPage(menuitemfacade.findOrCreate("/user/changePassword"), UserPermission.VIEW_SELF);
MenuNavigation usermgmt = profileTopmenu.addPage(null, null);
usermgmt.setKey("topnavi.user.mgmt");
usermgmt.addPage(menuitemfacade.findOrCreate("/role/create"), UserPermission.WRITE_ROLES);
usermgmt.addPage(menuitemfacade.findOrCreate("/role/list"), UserPermission.READ_ROLES).setHeader("submenu.user.rolelinks");
usermgmt.addPage(menuitemfacade.findOrCreate("/orgrole/list"), UserPermission.READ_ORGROLES);
usermgmt.addPage(menuitemfacade.findOrCreate("/orgrole/create"), UserPermission.WRITE_ORGROLES);
usermgmt.addPage(menuitemfacade.findOrCreate("/useradmin/listCardTemplates"), UserPermission.READ_ROLES);
usermgmt.addPage(menuitemfacade.findOrCreate("/useradmin/createCardTemplate"), UserPermission.WRITE_ROLES);
navifacade.create(profileTopmenu);
MenuNavigation miscTopmenu = new MenuNavigation(ev, "topnavi.misc", menusort = +10);
miscTopmenu.addPage(menuitemfacade.findOrCreate("/pages/list"), ContentPermission.MANAGE_PAGES);
miscTopmenu.addPage(menuitemfacade.findOrCreate("/pages/create"), ContentPermission.MANAGE_PAGES);
miscTopmenu.addPage(menuitemfacade.findOrCreate("/utils/flushCache"), ContentPermission.MANAGE_PAGES);
navifacade.create(miscTopmenu);
// frontTopnavi.addPage(menuitemfacade.findOrCreate("/user/create"),
// UserPermission.CREATE_NEW);
// frontTopnavi.addPage(menuitemfacade.findOrCreate("/auth/sendResetMail"),
// UserPermission.LOGIN);
// frontTopnavi.addPage(menuitemfacade.findOrCreate("/user/invite"),
// UserPermission.INVITE_USERS);
// ////////////////////////////////////////////////////
// ////////////////////////////////////////////////////
// ////////////////////////////////////////////////////
// ////////////////////////////////////////////////////
// ////////////////////////////////////////////////////
// ////////////////////////////////////////////////////
// ////////////////////////////////////////////////////
}
private synchronized void initializeOldMenu() {
LanEvent ev = eventbean.getCurrentEvent();
int menusort = 100;
MenuNavigation usernavi = new MenuNavigation(ev, "supernavi.user");
MenuNavigation usernavi = new MenuNavigation(ev, "supernavi.user", menusort = +10);
navifacade.create(usernavi);
......@@ -130,7 +228,7 @@ public class MenuBean implements MenuBeanLocal {
compoMenu.addPage(menuitemfacade.findOrCreate("/voting/submitEntry"), null).setVisible(false);
compoMenu.addPage(menuitemfacade.findOrCreate("/voting/details"), null).setVisible(false);
MenuNavigation adminnavi = new MenuNavigation(ev, "supernavi.admin");
MenuNavigation adminnavi = new MenuNavigation(ev, "supernavi.admin", menusort = +10);
navifacade.create(adminnavi);
MenuNavigation adminuser = adminnavi.addPage(null, null);
......
......@@ -71,6 +71,8 @@ public class MenuNavigationFacade extends IntegerPkGenericFacade<MenuNavigation>
cb.equal(root.get(MenuNavigation_.event), eventbean.getCurrentEvent()),
cb.isTrue(root.get(MenuNavigation_.visible)));
cq.orderBy(cb.asc(root.get(MenuNavigation_.sort)));
return getEm().createQuery(cq).getResultList();
}
......
......@@ -17,4 +17,6 @@ public interface MenuBeanLocal {
List<MenuNavigation> getTopmenus();
void flushOldMenu();
}
......@@ -82,8 +82,9 @@ public class MenuNavigation extends GenericEntity implements Comparable<MenuNavi
super();
}
public MenuNavigation(LanEvent ev, String keyString) {
public MenuNavigation(LanEvent ev, String keyString, Integer sort) {
super();
this.sort = sort;
this.event = ev;
this.key = keyString;
this.visible = true;
......@@ -186,8 +187,11 @@ public class MenuNavigation extends GenericEntity implements Comparable<MenuNavi
// used only for initialization function...
public MenuNavigation addPage(Menuitem item, IAppPermission permission) {
if (children == null) {
int childSort = 100;
if (children == null || children.size() == 0) {
children = new ArrayList<MenuNavigation>();
} else {
childSort = children.get(children.size() - 1).getSort() + 10;
}
MenuNavigation add = new MenuNavigation();
add.setSort(pagesort += 10);
......@@ -200,6 +204,7 @@ public class MenuNavigation extends GenericEntity implements Comparable<MenuNavi
add.setPermission(permission);
add.setParent(this);
add.setVisible(true);
add.setSort(childSort);
children.add(add);
return add;
......
......@@ -30,17 +30,19 @@ public class I18n {
public static String get(String key) {
String value = null;
try {
value = getResourceBundle().getString(key);
} catch (MissingResourceException e) {
value = null;
}
if (key == null) {
value = "########";
} else if (value == null) {
value = "???" + key + "???";
} else {
try {
value = getResourceBundle().getString(key);
} catch (MissingResourceException e) {
value = null;
}
if (value == null) {
value = "???" + key + "???";
}
}
return value;
}
......
......@@ -9,13 +9,14 @@ public class SearchQuery implements Serializable {
private int pagesize = 20;
private String sort = null;
private String search = null;
private Boolean direction = false;
public SearchQuery()
{
super();
}
public SearchQuery(int page, int pagesize, String sort, String search) {
public SearchQuery(int page, int pagesize, String sort, String search, boolean direction) {
super();
this.page = page;
this.pagesize = pagesize;
......@@ -69,4 +70,12 @@ public class SearchQuery implements Serializable {
}
}
public Boolean isDirection() {
return direction;
}
public void setDirection(Boolean direction) {
this.direction = direction;
}
}
......@@ -10,7 +10,7 @@
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Production</param-value>
<!--<param-value>Development</param-value>-->
<!--<param-value>Development</param-value> -->
</context-param>
<context-param>
......@@ -142,8 +142,8 @@
<servlet-name>PlaceGroupPdf</servlet-name>
<url-pattern>/PlaceGroupPdf</url-pattern>
</servlet-mapping>
<context-param>
<!-- <context-param>
<param-name>primefaces.THEME</param-name>
<param-value>bortal</param-value>
</context-param>
</context-param> -->
</web-app>
\ No newline at end of file
......@@ -51,26 +51,11 @@
</div>
</div>
<ui:fragment rendered="#{menuView.getMenu(0).size() > 1}">
<div id="top-menu">
<ul>
<li jsfc="ui:repeat" var="menuitem" value="#{menuView.getMenu(0)}">
<h:link outcome="#{menuitem.outcome}" value="#{i18n[menuitem.navigation.key]}" styleClass="#{menuitem.selected?'active':''}" />
</li>
</ul>
</div>
</ui:fragment>
</div>
<div id="main">
<div id="main-nav">
<ul>
<li jsfc="ui:repeat" var="menuitem" value="#{menuView.getMenu(1)}">
<h:link outcome="#{menuitem.outcome}" value="#{i18n[menuitem.navigation.key]}" styleClass="#{menuitem.selected?'active':''}" />
</li>
</ul>
</div>
<p:menubar model="#{primeMenuView.menuModel}"/>
<div class="container top">
<h:link rendered="#{layoutView.manageContent}" styleClass="editorlink" value="#{i18n['layout.editTop']}" outcome="/pages/manage">
......@@ -91,9 +76,10 @@
</div>
</ui:fragment>
<div id="left">
<div id="left">
<ui:insert name="title" />
<h:messages globalOnly="true" />
<p:messages severity="info" />
<h:messages />
<ui:repeat var="cont1" value="#{menuView.getPagecontent('top')}">
<h:outputText value="#{cont1.content}" escape="false" />
</ui:repeat>
......
......@@ -3,13 +3,11 @@
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:tools="http://java.sun.com/jsf/composite/cditools"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title></title>
</h:head>
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui" >
<h:body>
<ui:composition template="/layout/#{sessionHandler.layout}/template.xhtml">
<ui:param name="thispage" value="page.permissionDenied" />
<ui:define name="content">
<h1>#{i18n['permissiondenied.header']}</h1>
<p>
......@@ -19,4 +17,4 @@
</ui:define>
</ui:composition>
</h:body>
</html>
</html>
......@@ -88,7 +88,7 @@
</h:dataTable>
<div>
<h:outputText value="#{i18n['productshop.total']} " />
<h:outputText value="#{productShopView.totalPrice}">
<h:outputText value="#{productShopView.cartPrice}">
<f:convertNumber maxFractionDigits="2" minFractionDigits="2" />
</h:outputText>
</div>
......
......@@ -2,23 +2,46 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:tools="http://java.sun.com/jsf/composite/tools">
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:p="http://primefaces.org/ui" xmlns:tools="http://java.sun.com/jsf/composite/tools">
<composite:interface>
</composite:interface>
<composite:implementation>
<h:outputScript library="primefaces" name="jquery/jquery.js" target="head" />
<h:dataTable styleClass="bordertable" id="user" value="#{userSearchView.results}" var="user">
<h:column>
<p:dataTable id="user" value="#{userSearchView.results}" var="user">
<p:column>
<f:facet name="header">
<h:link value="#{i18n['user.nick']}" includeViewParams="true">
<f:param name="sort" value="nick" />
<f:param name="page" value="0" />
</h:link>
</f:facet>
<h:outputText styleClass="hoverable" value="#{(empty user.nick)?'----':user.nick}" />
<div class="userdata_popup">
<h:outputText styleClass="hoverable" value="#{(empty user.nick)?'----':user.nick}" />
</p:column>
<p:column>
<f:facet name="header">
<h:link value="#{i18n['user.firstnames']}" includeViewParams="true">
<f:param name="sort" value="firstnames" />
<f:param name="page" value="0" />
</h:link>
</f:facet>
<h:outputText value="#{user.firstnames}" />
</p:column>
<p:column>
<f:facet name="header">
<h:link value="#{i18n['user.lastName']}" includeViewParams="true">
<f:param name="sort" value="lastname" />
</h:link>
</f:facet>
<h:outputText value="#{user.lastname}" />
</p:column>
<p:column>
<p:commandButton onClick="location.replace('#{request.contextPath}/useradmin/edit.jsf?userid=#{user.id}')">#{i18n['user.edit']}</p:commandButton>
<p:commandButton id="userinfoBtn" value="Info" type="button" />
<p:overlayPanel for="userinfoBtn">
<h:panelGrid columns="2">
<img style="width:100px;" src="#{request.contextPath}/dydata/userimage/#{user.currentImage.id}.img" alt="image" />
......@@ -33,43 +56,16 @@
<h:outputText value="#{user.email}"/> <br />
</h:panelGroup>
</h:panelGrid>
</div>
</h:column>
<h:column>
<f:facet name="header">
<h:link value="#{i18n['user.firstNames']}" includeViewParams="true">
<f:param name="sort" value="firstnames" />
<f:param name="page" value="0" />
</h:link>
</f:facet>
<h:outputText value="#{user.firstnames}" />
</h:column>
<h:column>
<f:facet name="header">
<h:link value="#{i18n['user.lastName']}" includeViewParams="true">
<f:param name="sort" value="lastname" />
</h:link>
</f:facet>
<h:outputText value="#{user.lastname}" />
</h:column>
<h:column>
<f:facet name="header">
<h:link value="#{i18n['user.email']}" includeViewParams="true">
<f:param name="sort" value="email" />
</h:link>
</f:facet>
<h:outputText value="#{user.email}" />
</h:column>
<h:column>
<button onClick="location.replace('#{request.contextPath}/useradmin/edit.jsf?userid=#{user.id}')">#{i18n['user.edit']}</button>
</h:column>
</p:overlayPanel>
</p:column>
<!-- <h:column>
<h:commandButton action="#{userView.shop()}" value="#{i18n['user.shop']}" />
</h:column> -->
</h:dataTable>
</p:dataTable>
<script>
jQuery(function() {
jQuery(".hoverable").hover(function () {
......
/* General css, use for non-layout purposes for general elements */
/* userlistview popup */
.userdata_popup {
position: absolute;
border: 1px solid black;
background: white;
border-radius: 3px;
display: none;
width: 300px;
height: 150px;
position: absolute;
border: 1px solid black;
background: white;
border-radius: 3px;
display: none;
width: 300px;
height: 150px;
}
/* general class for hoverable usage */
.hoverable {
}
.hidden {
display: none;
}
#webcamcontainer {
}
#shopItems {}
#shopItems {
}
.ui-panel-title {
text-overflow: clip;
}
.shopItem {
position: relative;
float:left;
width: 64px;
height: 64px;
background: gold;
float: left;
width: 72px;
height: 72px;
background: burlywood;
border: 1px solid black;
margin: 2px;
}
.shopItem:hover {
background: goldenrod;
a.shopItem {
color: black !important;
}
.shopItem a {
display: block;
width: 100%;
height: 100%;
color: black;
text-decoration: none;
a.shopItem div {
position: absolute;
height: 72px;
width: 72px;
text-align: center;
/* Firefox */
display: -moz-box;
-moz-box-orient: horizontal;
-moz-box-pack: center;
-moz-box-align: center;
/* Safari and Chrome */
display: -webkit-box;
-webkit-box-orient: horizontal;
-webkit-box-pack: center;
-webkit-box-align: center;
/* W3C */
display: box;
box-orient: horizontal;
box-pack: center;
box-align: center;
clip: rect(0, 72px, 72px, 0);
}
}
a.shopItem:hover {
background: darkgoldenrod;
}
a.shopItem:active {
background: red;
}
\ No newline at end of file
......@@ -24,15 +24,15 @@
<h:panelGroup>
<div id="shopItems">
<ui:repeat value="#{productShopView.shoppingcart}" var="cart">
<h:commandLink styleClass="shopItem"
action="#{productShopView.addOne}">
<h:commandLink styleClass="shopItem" action="#{productShopView.addOne}">
<f:ajax render="@form" />
<div>
#{cart.product.name}<br />
#{cart.product.name}<br />
<h:outputText value="#{cart.product.price}">
<f:convertNumber maxFractionDigits="2" minFractionDigits="2" />
</h:outputText>eur
<f:convertNumber maxFractionDigits="2" minFractionDigits="2" />
</h:outputText>
eur
</div>
</h:commandLink>
</ui:repeat>
......@@ -44,21 +44,23 @@
<h:outputLabel value="#{i18n['shop.barcode']}" />
<h:inputText id="barcode" value="#{productShopView.barcode}" />
<h:commandButton action="#{productShopView.readBarcode}"
onclick="blip(); return true;"
value="#{i18n['shop.readBarcode']}">
<h:commandButton action="#{productShopView.readBarcode}" onclick="blip(); return true;" value="#{i18n['shop.readBarcode']}">
<f:ajax render="@form" onevent="barcodeReadEvent" execute="@form" />
</h:commandButton>
<br />
<p:dataTable id="prods" value="#{productShopView.boughtItems}"
var="prods">
<p:dataTable id="prods" value="#{productShopView.boughtItems}" var="prods">
<p:column>
<f:facet name="header">
<h:outputText value="#{i18n['shop.count']}" />
</f:facet>
<h:outputText value="#{prods.count}" />
<p:inplace>
<p:inputText value="#{prods.count}" size="4">
<f:ajax event="valueChange" render="@form" />
<f:convertNumber minFractionDigits="0" maxFractionDigits="2" />
</p:inputText>
</p:inplace>
</p:column>
<p:column>
......@@ -79,18 +81,27 @@
<f:facet name="header">
<h:outputText value="#{i18n['shop.actions']}" />
</f:facet>
<h:commandButton action="#{productShopView.removeBought()}"
value="Poista" />
<h:commandButton action="#{productShopView.removeBought()}" value="Poista" />
</p:column>
</p:dataTable>
<div style="font-weight: bold;">
<h:outputText value="#{i18n['shop.totalPrice']}" />
<span class="shoptotal"> <h:outputText value="#{productShopView.totalPrice}">
<h:outputText value="#{i18n['shop.cartPrice']}" />
<h:outputText styleClass="shoptotal" value="#{productShopView.cartPrice}">
<f:convertNumber maxFractionDigits="2" minFractionDigits="2" />
</h:outputText>
<br />
<h:outputLabel value="#{i18n['shop.currentBalance']}" />
<h:outputText styleClass="shoptotal" value="#{productShopView.accountCredits}">
<f:convertNumber maxFractionDigits="2" minFractionDigits="2" />
</h:outputText>
<br />
<h:outputLabel value="#{i18n['shop.transactionTotal']}" />
<h:outputText styleClass="shoptotal" value="#{productShopView.transactionTotal}">
<f:convertNumber maxFractionDigits="2" minFractionDigits="2" />
</h:outputText></span>
</h:outputText>
</div>
<br />
<br />
<h:outputLabel value="#{i18n['shop.cash']}" />
......@@ -98,19 +109,21 @@
<f:ajax render="@form" event="valueChange" />
</h:inputText> -->
<input type="text" class="inputval" value="" size="5" onblur="calc()" />
<br />
<h:outputLabel value="#{i18n['shop.cashback']}" /><input id="returnval" type="text" size="5" value="0" />
<br />
<h:outputLabel value="#{i18n['shop.cashback']}" />
<input id="returnval" type="text" size="5" value="0" />
<input type="button" value="#{i18n['shop.calcsubtotal']}" onclick="calc()" />
<br />
<h:outputLabel value="#{i18n['shop.accountBalance']}" />
<h:outputText value=" #{productShopView.accountCredits}">
<f:convertNumber />
</h:outputText>
<br/>
<h:outputLabel value="#{i18n['shop.']}" />
<h:outputText value=" #{productShopView.accountBalance}">
<f:convertNumber />
</h:outputText>
<h:commandButton action="#{productShopView.buyCash()}" value="#{i18n['shop.buyCash']}" />
<h:commandButton action="#{productShopView.buyCredit()}" onclick="return confirm('#{i18n['shop.confirmCreditBuy']}');" value="#{i18n['shop.buyCredit']}" />
</h:panelGroup>
</h:panelGrid>
......
<!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:users="http://java.sun.com/jsf/composite/cditools/user"
xmlns:tools="http://java.sun.com/jsf/composite/cditools" 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:users="http://java.sun.com/jsf/composite/cditools/user"
xmlns:tools="http://java.sun.com/jsf/composite/cditools" xmlns:p="http://primefaces.org/ui" xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<ui:composition template="/layout/#{sessionHandler.layout}/template.xhtml">
<f:metadata>
......
......@@ -64,14 +64,17 @@ public class SessionHandler {
public String getLayout() {
// TODO: layout selection code missing!!
// return "stream1";
template = "insomnia2";
return template;
/*
if (template == null) {
template = eventbean.getPropertyString(LanEventPropertyKey.EVENT_LAYOUT);
}
if (template == null) {
template = "template1";
}
return template;
return template; */
}
// public boolean hasPermission(String target, String permission) {
......
......@@ -450,9 +450,7 @@ product.totalPrice = Total
product.unitName = Unit name
product.vat = VAT
productShopView.readBarcode = Read barcode
products.save = Save
products.save = Save
productsShopView.readBarcode = Read
......@@ -625,7 +623,7 @@ svm.pending.successMessage = Payment pending. You will receive email after payme
svm.success.errorMessage = Payment could not be verified!
svm.success.successMessage = Payment was successfull. You can now your credits in the system.
template.loggedInAs = Logged in as:
template.loggedInAs = Logged in as
topnavi.adminshop = Adminshop
topnavi.billing = Billing
......@@ -665,6 +663,7 @@ user.hasImage = Image
user.image = Image
user.imagelist = Saved images
user.imagesubmit = Send image
user.insert = Insert
user.insertToken = Insert token
user.invalidLoginCredentials = Invalid user credentials
user.invite = Invite
......
......@@ -416,27 +416,26 @@ poll.end = Sulje kysely
poll.name = Kyselyn nimi
poll.save = L\u00E4het\u00E4 vastauksesi
product.barcode = Viivakoodi
product.billed = Laskutettu
product.boughtTotal = Tuotteita laskutettu
product.cart.count = Ostoskoriin
product.cashed = Ostettu k\u00E4teisell\u00E4
product.color = V\u00E4ri k\u00E4ytt\u00F6liittym\u00E4ss\u00E4
product.create = Luo tuote
product.createDiscount = Lis\u00E4\u00E4 m\u00E4\u00E4r\u00E4alennus
product.edit = Muokkaa
product.name = Tuotteen nimi
product.paid = Maksettu
product.prepaid = Prepaid
product.prepaidInstant = Luodaan kun prepaid maksetaan
product.price = Tuotteen hinta
product.providedRole = Tuote m\u00E4\u00E4ritt\u00E4\u00E4 roolin
product.save = Tallenna
product.shopInstant = Luo k\u00E4teismaksu tuotteille
product.sort = J\u00E4rjestys luku
product.totalPrice = Summa
product.unitName = Tuoteyksikk\u00F6
product.vat = ALV
product.barcode = Viivakoodi
product.billed = Laskutettu
product.boughtTotal = Tuotteita laskutettu
product.cart.count = Ostoskoriin
product.cashed = Ostettu k\u00E4teisell\u00E4
product.color = V\u00E4ri k\u00E4ytt\u00F6liittym\u00E4ss\u00E4
product.create = Luo tuote
product.createDiscount = Lis\u00E4\u00E4 m\u00E4\u00E4r\u00E4alennus
product.edit = Muokkaa
product.name = Tuotteen nimi
product.paid = Maksettu
product.prepaid = Prepaid
product.prepaidInstant = Luodaan kun prepaid maksetaan
product.price = Tuotteen hinta
product.save = Tallenna
product.shopInstant = Luo k\u00E4teismaksu tuotteille
product.sort = J\u00E4rjestys luku
product.totalPrice = Summa
product.unitName = Tuoteyksikk\u00F6
product.vat = ALV
productShopView.readBarcode = Lue viivakoodi
......@@ -612,7 +611,7 @@ svm.pending.successMessage = Maksukuittausta odotetaan. Kuittauksesta l\u00E4het
svm.success.errorMessage = Verkkomaksua ei voitu verifioida! Virheest\u00E4 on raportoitu eteenp\u00E4in.
svm.success.successMessage = Verkkomaksu onnistui.
template.loggedInAs = Kirjautunut tunnuksella:
template.loggedInAs = Kirjautunut tunnuksella
topnavi.adminshop = Kauppa
topnavi.billing = Laskutus
......
......@@ -84,13 +84,13 @@ public abstract class GenericCDIView implements Serializable {
navihandler.saveDestination(viewidbuilder.toString());
logger.debug("Permission denied. Saving navi {} for later use", viewidbuilder.toString());
// navihandler.navigateTo("/permissionDenied");
fcont.getApplication().getNavigationHandler().handleNavigation(fcont, null, "/permissionDenied");
fcont.getApplication().getNavigationHandler().handleNavigation(fcont, null, "/permissionDenied?faces-redirect=true");
}
return ret;
}
protected void addFaceMessage(String string, Object... params) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(I18n.get(string, params)));
}
......
......@@ -19,6 +19,7 @@ public abstract class PaginationView<T extends ModelInterface> extends GenericCD
private SearchQuery searchQuery = new SearchQuery();
protected Long resultcount = 0L;
private Long pagecount = 0L;
// protected String sort;
// protected String search;
private List<T> results;
......@@ -148,4 +149,12 @@ public abstract class PaginationView<T extends ModelInterface> extends GenericCD
this.searchQuery = searchQuery;
}
public Boolean isDirection() {
return searchQuery.isDirection();
}
public void setDirection(Boolean direction) {
searchQuery.setDirection(direction);
}
}
......@@ -158,7 +158,7 @@ public class PlaceView extends GenericCDIView {
public String searchUser() {
super.beginConversation();
userlist = new ListDataModel<User>(userbean.getUsers(new SearchQuery(0, 0, null, searchuser)).getResults());
userlist = new ListDataModel<User>(userbean.getUsers(new SearchQuery(0, 0, null, searchuser, false)).getResults());
return null;
}
......
package fi.insomnia.bortal.web.cdiview.menu;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import org.primefaces.component.menuitem.MenuItem;
import org.primefaces.component.separator.Separator;
import org.primefaces.component.submenu.Submenu;
import org.primefaces.model.DefaultMenuModel;
import org.primefaces.model.MenuModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.insomnia.bortal.beans.MenuBeanLocal;
import fi.insomnia.bortal.model.MenuNavigation;
import fi.insomnia.bortal.utilities.I18n;
import fi.insomnia.bortal.web.cdiview.GenericCDIView;
@Named
@RequestScoped
public class PrimeMenuView extends GenericCDIView {
private static final long serialVersionUID = -5720164797157054213L;
// private String pagename;
// // @Inject
// // private transient LayoutView layoutview;
//
@EJB
private transient MenuBeanLocal menubean;
// private LinkedList<List<JsfMenuitem>> menus;
// private HashSet<MenuNavigation> navis;
// private Map<String, List<PageContent>> contents = new HashMap<String,
// List<PageContent>>();
// @EJB
// private transient SitePageBeanLocal pagebean;
private DefaultMenuModel menuModel;
private static final Logger logger = LoggerFactory.getLogger(PrimeMenuView.class);
public MenuModel getMenuModel()
{
if (menuModel == null)
{
menuModel = new DefaultMenuModel();
// menubean.findNavigation(layoutview.getPagepath());
List<MenuNavigation> tops = menubean.getTopmenus();
for (MenuNavigation m : tops)
{
if (m.getItem() != null && m.getChildren().isEmpty())
{
MenuItem menuitem = mkMenuitem(m);
if (menuitem != null)
{
menuModel.addMenuItem(menuitem);
}
} else {
Submenu subm = addSubmenu(m);
if (subm != null)
{
menuModel.addSubmenu(subm);
}
}
}
}
return menuModel;
}
private Submenu addSubmenu(MenuNavigation m) {
Submenu ret = null;
if (m.isVisible() && (m.getPermission() == null || super.hasPermission(m.getPermission())))
{
ret = new Submenu();
ret.setLabel(I18n.get(m.getKey()));
for (MenuNavigation child : m.getChildren())
{
if (child.getChildren().isEmpty()) {
if (child.getItem() != null)
{
MenuItem item = mkMenuitem(child);
if (item != null)
{
item.setValue(I18n.get(child.getKey()));
ret.getChildren().add(item);
}
} else if (ret.getChildCount() > 0) {
ret.getChildren().add(new Separator());
}
} else {
Submenu subm = addSubmenu(child);
if (subm != null)
{
subm.setLabel(I18n.get(child.getKey()));
ret.getChildren().add(subm);
}
}
}
if (ret.getChildCount() == 0)
{
ret = null;
}
}
return ret;
}
private MenuItem mkMenuitem(MenuNavigation m) {
MenuItem item = null;
if (m.isVisible() && (m.getPermission() == null || super.hasPermission(m.getPermission())))
{
item = new MenuItem();
String outcome;
if (m.getSitepage() != null)
{
outcome = new StringBuilder("/pages/index?id=").append(m.getSitepage().getId()).toString();
} else {
outcome = m.getItem().getUrl();
}
String key = I18n.get(m.getKey());
item.setValue(key);
item.setOutcome(outcome);
}
return item;
}
}
package fi.insomnia.bortal.web.cdiview.shop;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.ejb.EJB;
......@@ -61,6 +63,7 @@ public class ProductShopView extends GenericCDIView {
private BillEditView billEditView;
private boolean hasLimits = false;
private boolean blip = false;
private ListDataModel<ProductShopItem> boughtItems;
public void initBillView() {
if (requirePermissions(ShopPermission.LIST_USERPRODUCTS)
......@@ -80,8 +83,7 @@ public class ProductShopView extends GenericCDIView {
if (requirePermissions(ShopPermission.SHOP_TO_OTHERS)
&& shoppingcart == null) {
shoppingcart = new ListDataModel<ProductShopItem>(
ProductShopItem.productGTList(productBean
.findForStaffshop()));
ProductShopItem.productList(productBean.findForStaffshop()));
updateCartLimits(null);
logger.debug("Initialized shoppingcart to {}", shoppingcart);
this.beginConversation();
......@@ -91,34 +93,41 @@ public class ProductShopView extends GenericCDIView {
public String add(Integer count) {
ProductShopItem item = shoppingcart.getRowData();
item.setCount(item.getCount().add(BigDecimal.valueOf(count)));
updateCartLimits(item);
return null;
}
public String addOne()
{
public String addOne() {
return add(1);
}
public String addMinusOne()
{
public String addMinusOne() {
return add(-1);
}
public String addTen()
{
public String addTen() {
return add(10);
}
public String addMinusTen()
{
public String addMinusTen() {
return add(-10);
}
public void updateCartLimits(ProductShopItem item) {
if (boughtItems == null) {
boughtItems = new ListDataModel<ProductShopItem>(
new ArrayList<ProductShopItem>());
}
List<ProductShopItem> listdata = (List<ProductShopItem>) boughtItems
.getWrappedData();
if (item != null && !listdata.contains(item)) {
listdata.add(item);
}
Map<Integer, BigDecimal> prodCounts = new HashMap<Integer, BigDecimal>();
for (ProductShopItem sc : shoppingcart) {
prodCounts.put(sc.getProduct().getId(), sc.getCount());
......@@ -128,11 +137,9 @@ public class ProductShopView extends GenericCDIView {
prodCounts, user);
// Update the updated cart first
if (item != null)
{
if (item != null) {
BigDecimal l = limits.get(item.getProduct().getId());
if (item.updateLimit(l))
{
if (item.updateLimit(l)) {
updateCartLimits(null);
return;
}
......@@ -145,33 +152,59 @@ public class ProductShopView extends GenericCDIView {
}
n.updateLimit(l);
}
}
public String removeBought() {
ProductShopItem row = boughtItems.getRowData();
row.setCount(row.getCount().subtract(BigDecimal.ONE));
updateCartLimits(row);
return null;
}
// public ListDataModel<ProductShopItem> getProducts() {
// List<ProductShopItem> prods = new ArrayList<ProductShopItem>();
// for (ProductShopItem sc : shoppingcart) {
// if (sc.getCount() != null && sc.getCount().compareTo(BigDecimal.ONE) !=
// -1) {
// prods.add(sc);
// }
// }
// return prods;
//
// }
public void updateAllCartLimits() {
updateCartLimits(null);
}
public BigDecimal getAccountBalance() {
public BigDecimal getTransactionTotal()
{
BigDecimal ret = getCartPrice().subtract(getAccountCredits());
if (BigDecimal.ZERO.compareTo(ret) > 0)
{
ret = BigDecimal.ZERO;
}
return ret;
}
public BigDecimal getBalanceAfterTransaction() {
BigDecimal ret = user.getAccountBalance();
ret = ret.add(getCash());
ret = ret.subtract(getTotalPrice());
ret = ret.subtract(getCartPrice());
logger.info("User accountbalance {}, cash{}, total {}. retBalance {}",
new Object[] { user.getAccountBalance(), getCash(),
getTotalPrice(), ret });
getCartPrice(), ret });
return ret;
}
public BigDecimal getAccountCredits() {
BigDecimal ret = user.getAccountBalance();
ret = ret.add(getCash());
logger.info("User accountbalance {}, cash{}, total {}. retBalance {}",
new Object[] { user.getAccountBalance(), getCash(),
getTotalPrice(), ret });
return ret;
}
public BigDecimal getTotalPrice() {
public BigDecimal getCartPrice() {
BigDecimal ret = BigDecimal.ZERO;
for (ProductShopItem cart : shoppingcart) {
ret = ret.add(cart.getPrice());
......@@ -206,32 +239,31 @@ public class ProductShopView extends GenericCDIView {
}
public String buyCash() {
cash = getTotalPrice();
public String buyCashback() {
logger.info("buying cash {}", cash);
commitShoppingCart();
return null;
}
public String buyCredit() {
setCash(BigDecimal.ZERO);
commitShoppingCart();
return null;
}
public String commitShoppingCart() {
EventUser retuser = null;
for (ProductShopItem shopitem : shoppingcart) {
if (shopitem.getCount().compareTo(BigDecimal.ZERO) > 0) {
retuser = productBean.createAccountEvent(shopitem.getProduct(), shopitem.getCount(), user).getUser();
retuser = productBean.createAccountEvent(shopitem.getProduct(),
shopitem.getCount(), user).getUser();
}
}
if (cash != null && cash.compareTo(BigDecimal.ZERO) != 0) {
Product credProd = productBean.findCreditProduct();
retuser = productBean.createAccountEvent(credProd, cash, user).getUser();
retuser = productBean.createAccountEvent(credProd, cash, user)
.getUser();
}
if (retuser != null) {
user = retuser;
......@@ -288,7 +320,7 @@ public class ProductShopView extends GenericCDIView {
public BigDecimal getCash() {
if (payInstant) {
cash = getTotalPrice();
cash = getCartPrice();
logger.info("Getting instantcash as {}", cash);
}
if (cash == null) {
......@@ -340,4 +372,12 @@ public class ProductShopView extends GenericCDIView {
this.blip = blip;
}
public ListDataModel<ProductShopItem> getBoughtItems() {
return boughtItems;
}
public void setBoughtItems(ListDataModel<ProductShopItem> boughtItems) {
this.boughtItems = boughtItems;
}
}
......@@ -107,7 +107,7 @@ public class ReaderView extends GenericCDIView {
if (usersearch == null || usersearch.length() < 2) {
super.addFaceMessage("user.tooShortSearch");
} else {
userlist = UserCardWrapper.initWrapper(userbean.getUsers(new SearchQuery(0, 0, null, usersearch)).getResults(), userbean);
userlist = UserCardWrapper.initWrapper(userbean.getUsers(new SearchQuery(0, 0, null, usersearch, false)).getResults(), userbean);
}
return null;
......
......@@ -24,6 +24,24 @@ public class ProductShopItem {
private BigDecimal price;
private BigDecimal limit;
public BigDecimal getCreditPrice()
{
if (BigDecimal.ZERO.compareTo(price) < 0)
{
return price;
}
return BigDecimal.ZERO;
}
public BigDecimal getDebitPrice()
{
if (BigDecimal.ZERO.compareTo(price) > 0)
{
return price;
}
return BigDecimal.ZERO;
}
public ProductShopItem(Product prod) {
super();
this.product = prod;
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!