Commit 27af0ea3 by Tuomas Riihimäki

Merge branch 'master' into shopCountAsValue

Conflicts:
	code/MoyaWeb/src/fi/codecrew/moya/web/cdiview/shop/ProductShopView.java
2 parents 40a6e261 9e7b0f57
Showing with 1428 additions and 792 deletions
......@@ -7,3 +7,4 @@
*~
.metadata
/code/*/target/
/code/*/test-output/
......@@ -189,10 +189,10 @@ public class CardTemplateBean implements CardTemplateBeanLocal {
public CardTemplate getUsersCardtype(EventUser user) {
Set<Role> roles = userbean.localFindUsersRoles(user);
logger.info("Checking roles {} against {}", user, roles);
// logger.info("Checking roles {} against {}", user, roles);
CardTemplate greatestTemplate = null;
for (Role listrole : roles) {
logger.info("Checking role {}", listrole);
// logger.info("Checking role {}", listrole);
if (greatestTemplate == null || (listrole.getCardTemplate() != null && greatestTemplate.getPower() < listrole.getCardTemplate().getPower())) {
greatestTemplate = listrole.getCardTemplate();
}
......
......@@ -138,7 +138,7 @@ public class EventBean implements EventBeanLocal {
@Override
@RolesAllowed({ SpecialPermission.S_SUPERADMIN, EventPermission.S_MANAGE_EVENT })
public LanEvent mergeChanges(LanEvent event) {
if (!permbean.hasPermission(SpecialPermission.SUPERADMIN) && getCurrentEvent().equals(event)) {
if (!permbean.hasPermission(SpecialPermission.SUPERADMIN) && !getCurrentEvent().equals(event)) {
throw new EJBAccessException("Trying to save another event.");
}
return eventFacade.merge(event);
......@@ -187,8 +187,7 @@ public class EventBean implements EventBeanLocal {
public LanEventProperty getProperty(LanEventPropertyKey property) {
return eventPropertyFacade.find(getCurrentEvent(), property);
}
@Override
public long getPropertyLong(LanEventPropertyKey property)
{
......@@ -201,8 +200,6 @@ public class EventBean implements EventBeanLocal {
}
return ret;
}
@Override
public String getPropertyString(LanEventPropertyKey property)
......@@ -266,4 +263,14 @@ public class EventBean implements EventBeanLocal {
return ret;
}
/**
* If you want this event, user getCurrentEvent() This method should be used
* only in special cases...
*/
@Override
@RolesAllowed(EventPermission.S_MANAGE_EVENT)
public LanEvent getEventById(Integer id) {
return eventFacade.find(id);
}
}
......@@ -26,6 +26,8 @@ import fi.codecrew.moya.model.ApiApplicationInstance;
import fi.codecrew.moya.model.ApplicationPermission;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.model.LanEventProperty;
import fi.codecrew.moya.model.LanEventPropertyKey;
import fi.codecrew.moya.model.Role;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.utilities.PasswordFunctions;
......@@ -60,6 +62,8 @@ public class JaasBean implements MoyaRealmBeanRemote {
private ApiApplicationFacade appfacade;
@EJB
private ApiApplicationInstanceFacade appInstanceFacade;
@EJB
private EventBean eventorgbean;
public EventUser tryLogin(String username, String password) {
......@@ -82,7 +86,13 @@ public class JaasBean implements MoyaRealmBeanRemote {
eventUser = null;
user = null;
}
if (user != null && eventUser == null)
LanEventProperty inviteonly = eventbean.getProperty(LanEventPropertyKey.INVITE_ONLY_EVENT);
boolean createEventuser = true;
if (inviteonly != null && inviteonly.isBooleanValue()) {
createEventuser = false;
}
if (createEventuser && user != null && eventUser == null)
{
LanEvent event = eventbean.getCurrentEvent();
eventUser = new EventUser(user, event, null);
......
......@@ -20,6 +20,7 @@ import fi.codecrew.moya.enums.apps.MapPermission;
import fi.codecrew.moya.enums.apps.PollPermission;
import fi.codecrew.moya.enums.apps.ShopPermission;
import fi.codecrew.moya.enums.apps.SpecialPermission;
import fi.codecrew.moya.enums.apps.TerminalPermission;
import fi.codecrew.moya.enums.apps.TournamentPermission;
import fi.codecrew.moya.enums.apps.UserPermission;
import fi.codecrew.moya.facade.MenuNavigationFacade;
......@@ -196,7 +197,7 @@ public class MenuBean implements MenuBeanLocal {
adminShopProducts.addPage(menuitemfacade.findOrCreate("/product/list"), ShopPermission.LIST_ALL_PRODUCTS);
adminShopProducts.addPage(menuitemfacade.findOrCreate("/product/create"), ShopPermission.MANAGE_PRODUCTS);
adminShopProducts.addPage(menuitemfacade.findOrCreate("/product/edit"), ShopPermission.MANAGE_PRODUCTS).setVisible(false);
;
MenuNavigation foodnavi = adminshop.addPage(null, null);
foodnavi.setKey("topnavi.foodwave");
......@@ -256,13 +257,14 @@ public class MenuBean implements MenuBeanLocal {
gamenavi.addPage(menuitemfacade.findOrCreate("/license/manageCodes"), LicensePermission.MANAGE);
adminevent.addPage(menuitemfacade.findOrCreate("/eventorg/editEvent"), EventPermission.MANAGE_PROPERTIES);
navifacade.create(adminmenu);
//MenuNavigation shopmenu = new MenuNavigation(ev, "topnavi.shopnavi", menusort = +10);
// shopnavi.addPage(menuitemfacade.findOrCreate("/index3"),
// UserPermission.ANYUSER);
// navifacade.create(shopmenu);
MenuNavigation tournamentsadm = adminmenu.addPage(null, null);
tournamentsadm.setKey("tournaments.menutitle");
......@@ -273,6 +275,32 @@ public class MenuBean implements MenuBeanLocal {
tournamentsadm.addPage(menuitemfacade.findOrCreate("/tournaments/admin/edit"), TournamentPermission.MANAGE_ALL).setVisible(false);
tournamentsadm.addPage(menuitemfacade.findOrCreate("/tournaments/admin/delete"), TournamentPermission.MANAGE_ALL).setVisible(false);
tournamentsadm.addPage(menuitemfacade.findOrCreate("/tournaments/admin/editrules"), TournamentPermission.MANAGE_ALL).setVisible(false);
MenuNavigation infoviews = adminmenu.addPage(null, null);
infoviews.setKey("topnavi.infoviews");
infoviews.addPage(menuitemfacade.findOrCreate("/admin/adduser/index"), UserPermission.CREATE_NEW);
MenuNavigation infonavi = infoviews.addPage(null, null);
infonavi.setKey("subnavi.info");
infonavi.addPage(menuitemfacade.findOrCreate("/info/index"), TerminalPermission.INFO);
infonavi.addPage(menuitemfacade.findOrCreate("/info/incoming"), TerminalPermission.INFO);
navifacade.create(adminmenu);
//MenuNavigation shopmenu = new MenuNavigation(ev, "topnavi.shopnavi", menusort = +10);
// shopnavi.addPage(menuitemfacade.findOrCreate("/index3"),
// UserPermission.ANYUSER);
// navifacade.create(shopmenu);
/*
* MenuNavigation profileTopmenu = new MenuNavigation(ev,
* "topnavi.profile", menusort = +10);
......
......@@ -590,7 +590,7 @@ public class PlaceBean implements PlaceBeanLocal {
font.setSize(font2);
textLine = new TextLine(font);
textLine.setText(barcodeBean.getPlaceHexcode(place));
textLine.setText(barcodeBean.getPlaceTextCode(place));
textLine.setPosition(currentX, (pagey / 2) + font1);
textLine.setColor(new int[] { 0, 0, 0 });
textLine.drawOn(page);
......
......@@ -30,7 +30,7 @@ public class ProductPBean {
@EJB
private PermissionBean permbean;
@EJB
private DiscountBean discountBean;
@EJB
......@@ -100,10 +100,8 @@ public class ProductPBean {
// discountinstancefacade.create(discInst);
accEventdiscounts.add(new DiscountInstance(ret, d));
}
if (user.getAccountEvents() == null) {
user.setAccountEvents(new ArrayList<AccountEvent>());
}
user.getAccountEvents().add(ret);
user.addAccountevent(ret);
accounteventfacade.create(ret);
logger.debug("create ac {} for user {}", ret, user.getUser());
// flush changes to db.
......
......@@ -155,12 +155,13 @@ public class ReaderBean implements ReaderBeanLocal {
// reader is in autoproduct-mode, create dat product
if (reader.isAutoproduct()) {
EventUser eu = userbean.getEventUser(card.getUser().getUser());
AccountEvent createAc = productPBean.createAccountEvent(reader.getAutomaticProduct(), reader.getAutomaticProductCount(), eu, Calendar.getInstance());
readerfacade.flush();
logger.info("Creating new accountevent from autoproduct {}", createAc);
event.setNotes("Created automatic account event from reader. " + createAc);
EventUser eu = userbean.getEventUser(card.getUser().getUser(), false);
if (eu != null) {
AccountEvent createAc = productPBean.createAccountEvent(reader.getAutomaticProduct(), reader.getAutomaticProductCount(), eu, Calendar.getInstance());
readerfacade.flush();
logger.info("Creating new accountevent from autoproduct {}", createAc);
event.setNotes("Created automatic account event from reader. " + createAc);
}
}
event = readerEventFacade.create(event);
......
......@@ -7,6 +7,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Calendar;
......@@ -20,6 +21,7 @@ import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.EJBAccessException;
import javax.ejb.EJBException;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.imageio.ImageIO;
......@@ -29,18 +31,23 @@ import javax.persistence.PersistenceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.enums.apps.EventPermission;
import fi.codecrew.moya.enums.apps.SpecialPermission;
import fi.codecrew.moya.enums.apps.UserPermission;
import fi.codecrew.moya.facade.AccountEventFacade;
import fi.codecrew.moya.facade.ApprovalFacade;
import fi.codecrew.moya.facade.EventFacade;
import fi.codecrew.moya.facade.EventUserFacade;
import fi.codecrew.moya.facade.FeedbackFacade;
import fi.codecrew.moya.facade.GameIDFacade;
import fi.codecrew.moya.facade.GroupMembershipFacade;
import fi.codecrew.moya.facade.PlaceGroupFacade;
import fi.codecrew.moya.facade.ProductFacade;
import fi.codecrew.moya.facade.RoleFacade;
import fi.codecrew.moya.facade.UserApprovalFacade;
import fi.codecrew.moya.facade.UserFacade;
import fi.codecrew.moya.facade.UserImageFacade;
import fi.codecrew.moya.model.AccountEvent;
import fi.codecrew.moya.model.Approval;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.Feedback;
......@@ -51,6 +58,7 @@ import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.model.LanEventPropertyKey;
import fi.codecrew.moya.model.PlaceGroup;
import fi.codecrew.moya.model.PrintedCard;
import fi.codecrew.moya.model.Product;
import fi.codecrew.moya.model.Role;
import fi.codecrew.moya.model.TournamentGame;
import fi.codecrew.moya.model.User;
......@@ -71,6 +79,7 @@ import fi.codecrew.moya.utilities.SearchResult;
UserPermission.S_INVITE_USERS,
UserPermission.S_MODIFY,
SpecialPermission.S_USER,
EventPermission.S_MANAGE_EVENT,
})
public class UserBean implements UserBeanLocal {
......@@ -129,6 +138,14 @@ public class UserBean implements UserBeanLocal {
private GameIDFacade gameIDFacade;
@EJB
private ProductBeanLocal productbean;
@EJB
private ProductPBean productPrivateBean;
@EJB
private AccountEventFacade accountEventFacade;
@EJB
private EventFacade eventfacade;
@EJB
private ProductFacade productFacade;
@Override
@RolesAllowed(UserPermission.S_VIEW_ALL)
......@@ -627,29 +644,31 @@ public class UserBean implements UserBeanLocal {
}
@Override
public EventUser getEventUser(User user) {
public EventUser getEventUser(User user, boolean create) {
if (user == null || user.getId() == null) {
return null;
}
user = userFacade.find(user.getId());
EventUser ret = eventUserFacade.find(user);
if (ret == null)
if (create && ret == null)
{
ret = new EventUser(user, eventBean.getCurrentEvent(), permbean.getCurrentUser());
eventUserFacade.create(ret);
eventUserFacade.flush();
ret.setCreator(permbean.getCurrentUser());
}
return ret;
}
@Override
public EventUser findByUserId(Integer userid) {
public EventUser findByUserId(Integer userid, boolean createEventuser) {
User user = userFacade.find(userid);
EventUser ret = null;
if (user != null)
{
ret = this.getEventUser(user);
if (user != null) {
ret = this.getEventUser(user, createEventuser);
}
return ret;
}
......@@ -659,9 +678,9 @@ public class UserBean implements UserBeanLocal {
{
User user = userFacade.findByLogin(username);
EventUser ret = null;
if (user.checkPassword(password))
if (user != null && user.checkPassword(password))
{
ret = this.getEventUser(user);
ret = this.getEventUser(user, false);
}
return ret;
......@@ -785,10 +804,85 @@ public class UserBean implements UserBeanLocal {
public User getUser(Integer id) {
User ret = userFacade.find(id);
if (!permbean.getCurrentUser().getUser().equals(ret) && permbean.hasPermission(UserPermission.VIEW_ALL)) {
if (!permbean.getCurrentUser().getUser().equals(ret) && !permbean.hasPermission(UserPermission.VIEW_ALL)) {
throw new EJBAccessException("Tried to fetch user with id " + id + " from database without sufficient permissions");
}
return ret;
}
@Override
@RolesAllowed(EventPermission.S_MANAGE_EVENT)
public BigDecimal transferAccountSaldoFromPreviousEvent(List<User> users, LanEvent source)
{
if (source == null || users == null || users.isEmpty())
return null;
source = eventfacade.reload(source);
LanEvent destination = eventBean.getCurrentEvent();
if (!source.getOrganiser().equals(destination.getOrganiser())) {
throw new EJBException("Trying to move credits between organisations!");
}
final Calendar time = Calendar.getInstance();
final EventUser seller = permbean.getCurrentUser();
final Product dstCredprod = productbean.findCreditProduct();
final Product srcCredprod = productFacade.findProductsByPrice(BigDecimal.ONE.negate(), source).get(0);
if (!srcCredprod.getPrice().equals(dstCredprod.getPrice())) {
throw new RuntimeException("Credit prices do not match!");
}
final BigDecimal creditPrice = srcCredprod.getPrice().negate();
BigDecimal dstTotal = BigDecimal.ZERO;
for (User user : users)
{
EventUser dstUser = eventUserFacade.find(user);
EventUser srcUser = eventUserFacade.getOtherOrganisationsEventuser(dstUser.getUser(), source);
// If source user does not exist, skip over.
if (srcUser == null) {
continue;
}
BigDecimal srcBalance = srcUser.getAccountBalance();
if (srcBalance.compareTo(BigDecimal.ZERO) == 0) {
continue;
}
BigDecimal count = srcBalance.divide(creditPrice);
if (count.compareTo(BigDecimal.ZERO) < 0) {
throw new EJBException("All users should have positive balance!. User with id: " + dstUser.getUser().getId() + " has negative balance!");
}
// Negative accountevent for source user
AccountEvent srcacc = new AccountEvent(srcUser, srcCredprod, creditPrice, count.negate(), time);
srcacc.setDescription("Credits transferred to: '" + destination.getName() + "'");
srcacc.setSeller(seller);
srcUser.addAccountevent(srcacc);
accountEventFacade.create(srcacc);
AccountEvent dstacc = new AccountEvent(dstUser, dstCredprod, creditPrice, count, time);
dstacc.setDescription("Credits transferred from: '" + source.getName() + "'");
dstacc.setSeller(seller);
dstUser.addAccountevent(dstacc);
accountEventFacade.create(dstacc);
logger.info("Transferred {} credits with price {} for user {} from {} to {}", count, creditPrice, srcUser.getUser(), srcUser, dstUser);
dstTotal = dstTotal.add(dstacc.getTotal());
}
return dstTotal;
}
@Override
@RolesAllowed(EventPermission.S_MANAGE_EVENT)
public EventUser getOtherEventsEventuser(User user, LanEvent event) {
event = eventfacade.reload(event);
if (!eventBean.getCurrentEvent().getOrganiser().equals(event.getOrganiser())) {
throw new EJBAccessException("event must be organised by the organisation as this event.");
}
return eventUserFacade.getOtherOrganisationsEventuser(user, event);
}
}
\ No newline at end of file
......@@ -13,6 +13,10 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.SingularAttribute;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.enums.DatabaseHasCompare;
......@@ -22,6 +26,7 @@ import fi.codecrew.moya.facade.callbacks.EventUserAccountSaldoPredicate;
import fi.codecrew.moya.facade.callbacks.EventUserPlacegroupPredicate;
import fi.codecrew.moya.facade.callbacks.EventUserRolefilter;
import fi.codecrew.moya.facade.callbacks.EventUserSearchPredicate;
import fi.codecrew.moya.facade.callbacks.EventuserToUserWrapper;
import fi.codecrew.moya.facade.callbacks.OrderCallback;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.EventUser_;
......@@ -29,6 +34,7 @@ import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.model.User_;
import fi.codecrew.moya.util.UserSearchQuery;
import fi.codecrew.moya.utilities.SearchQuery.QuerySortOrder;
import fi.codecrew.moya.utilities.SearchResult;
import fi.codecrew.moya.utilities.jpa.FacadeCallback;
......@@ -47,6 +53,7 @@ public class EventUserFacade extends IntegerPkGenericFacade<EventUser> {
}
private final Map<Integer, Map<String, Integer>> logincache = new HashMap<Integer, Map<String, Integer>>();
private static final Logger logger = LoggerFactory.getLogger(EventUserFacade.class);
public EventUser findByLogin(final String login) {
LanEvent event = eventBean.getCurrentEvent();
......@@ -82,10 +89,13 @@ public class EventUserFacade extends IntegerPkGenericFacade<EventUser> {
}
public EventUser find(User user) {
LanEvent event = eventBean.getCurrentEvent();
EventUser ret;
if ((ret = checkCache(user.getLogin(), event)) == null)
{
return getOtherOrganisationsEventuser(user, eventBean.getCurrentEvent());
}
public EventUser getOtherOrganisationsEventuser(User user, LanEvent event)
{
EventUser ret = null;
if ((ret = checkCache(user.getLogin(), event)) == null) {
CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<EventUser> cq = cb.createQuery(EventUser.class);
Root<EventUser> root = cq.from(EventUser.class);
......@@ -108,14 +118,30 @@ public class EventUserFacade extends IntegerPkGenericFacade<EventUser> {
public SearchResult<EventUser> searchEventUsers(UserSearchQuery query) {
ArrayList<FacadeCallback<EventUser>> callbacks = new ArrayList<FacadeCallback<EventUser>>();
callbacks.add(new OrderCallback<EventUser>(false, EventUser_.id));
callbacks.add(new EventLimiter(eventBean.getCurrentEvent()));
if (query.getSearch() != null && !query.getSearch().isEmpty())
CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<EventUser> listCQuery = cb.createQuery(EventUser.class);
CriteriaQuery<Long> countCQuery = cb.createQuery(Long.class);
if (query.getSort() != null)
{
boolean asc = false;
if (query.getSortDirection() != null) {
asc = QuerySortOrder.ASCENDING.equals(query.getSortDirection());
}
SingularAttribute<? super User, ?> sortfield = UserFacade.getUserField(query.getSort());
logger.info("Sortig with {}, asc {} ", sortfield, asc);
callbacks.add(new EventuserToUserWrapper(new OrderCallback<User>(asc, sortfield)));
} else {
callbacks.add(new OrderCallback<EventUser>(false, EventUser_.id));
}
callbacks.add(new EventLimiter(eventBean.getCurrentEvent()));
if (query.getSearch() != null && !query.getSearch().isEmpty()) {
callbacks.add(new EventUserSearchPredicate(query.getSearch(), UserFacade.getAttrlist()));
}
if (query.isPlaceAssoc())
{
if (query.isPlaceAssoc()) {
callbacks.add(new EventUserPlacegroupPredicate());
}
if (query.getFilterRoles() != null && !query.getFilterRoles().isEmpty()) {
......@@ -132,11 +158,6 @@ public class EventUserFacade extends IntegerPkGenericFacade<EventUser> {
}
CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<EventUser> listCQuery = cb.createQuery(EventUser.class);
CriteriaQuery<Long> countCQuery = cb.createQuery(Long.class);
From<?, EventUser> listRoot = searchCallbacks(listCQuery, callbacks, EventUser.class);
From<?, EventUser> countRoot = searchCallbacks(countCQuery, callbacks, EventUser.class);
......
......@@ -12,6 +12,7 @@ import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.model.Product;
import fi.codecrew.moya.model.ProductFlag;
import fi.codecrew.moya.model.Product_;
......@@ -44,11 +45,15 @@ public class ProductFacade extends IntegerPkGenericFacade<Product> {
}
public List<Product> findProductsByPrice(BigDecimal price) {
return findProductsByPrice(price, eventbean.getCurrentEvent());
}
public List<Product> findProductsByPrice(BigDecimal price, LanEvent event) {
CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<Product> cq = cb.createQuery(Product.class);
Root<Product> root = cq.from(Product.class);
cq.where(cb.equal(root.get(Product_.event), eventbean.getCurrentEvent()),
cq.where(cb.equal(root.get(Product_.event), event),
cb.equal(root.get(Product_.price), price));
return getEm().createQuery(cq).getResultList();
......
......@@ -15,12 +15,13 @@ import javax.persistence.metamodel.SingularAttribute;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.facade.callbacks.OrderCallback;
import fi.codecrew.moya.facade.callbacks.StringSearchPredicateCreator;
import fi.codecrew.moya.model.User_;
import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.model.User_;
import fi.codecrew.moya.utilities.SearchQuery;
import fi.codecrew.moya.utilities.SearchQuery.QuerySortOrder;
import fi.codecrew.moya.utilities.SearchResult;
import fi.codecrew.moya.utilities.jpa.FacadeCallback;
......@@ -102,11 +103,11 @@ public class UserFacade extends IntegerPkGenericFacade<User> {
public SearchResult<User> searchAllUsers(SearchQuery search) {
List<FacadeCallback<User>> callbacks = new ArrayList<FacadeCallback<User>>();
if (search.getSort() == null || search.getSort().isEmpty()) {
callbacks.add(new OrderCallback<User>(false, User_.id));
} else {
callbacks.add(new OrderCallback<User>(false, search.getSort()));
}
// Ascending if null or not descending..
boolean asc = search.getSortDirection() == null || !QuerySortOrder.DESCENDING.equals(search.getSortDirection());
SingularAttribute<? super User, ?> sortfield = getUserField(search.getSort());
callbacks.add(new OrderCallback<User>(asc, sortfield));
callbacks.add(new StringSearchPredicateCreator<User>(search.getSearch(), getAttrlist()));
return super.searcher(search, callbacks);
......@@ -142,6 +143,68 @@ public class UserFacade extends IntegerPkGenericFacade<User> {
return getEm().createQuery(cq).getResultList();
}
/**
* For example in sorting.
*
* @param fieldname
* @return By default return "id"
*/
public static SingularAttribute<? super User, ?> getUserField(String fieldname) {
SingularAttribute<? super User, ?> sort = User_.id;
if (fieldname != null)
{
switch (fieldname) {
case "created":
sort = User_.created;
break;
case "login":
sort = User_.login;
break;
case "lastname":
sort = User_.lastname;
break;
case "firstnames":
sort = User_.firstnames;
break;
case "birthday":
sort = User_.birthday;
break;
case "nick":
sort = User_.nick;
break;
case "email":
sort = User_.email;
break;
case "address":
sort = User_.address;
break;
case "zip":
sort = User_.zip;
break;
case "postalTown":
sort = User_.postalTown;
break;
case "town":
sort = User_.town;
break;
case "phone":
sort = User_.phone;
break;
case "gender":
sort = User_.gender;
break;
case "confirmTime":
sort = User_.confirmTime;
break;
case "id":
default:
sort = User_.id;
}
}
return sort;
}
// public SearchResult<User> searchEventUsers(SearchQuery query)
// {
// ArrayList<FacadeCallback<EventUser>> callbacks = new
......
......@@ -5,7 +5,7 @@ import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.metamodel.SingularAttribute;
......@@ -27,7 +27,7 @@ public class AndPredicateCreator<A, T extends ModelInterface> implements FacadeC
}
@Override
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, From<?, T> root, List<Predicate> predicates) {
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<T> root, List<Predicate> predicates) {
if (searchval == null || attributes == null || attributes.isEmpty()) {
return;
}
......
......@@ -4,11 +4,11 @@ import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import fi.codecrew.moya.model.EventUser_;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.EventUser_;
import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.utilities.jpa.FacadeCallback;
......@@ -21,7 +21,7 @@ public class EventLimiter implements FacadeCallback<EventUser> {
}
@Override
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, From<?, EventUser> root, List<Predicate> predicates) {
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<EventUser> root, List<Predicate> predicates) {
predicates.add(cb.equal(root.get(EventUser_.event), ev));
}
......
......@@ -5,14 +5,14 @@ import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import fi.codecrew.moya.model.AccountEvent_;
import fi.codecrew.moya.enums.DatabaseValueCompare;
import fi.codecrew.moya.model.AccountEvent;
import fi.codecrew.moya.model.AccountEvent_;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.utilities.jpa.FacadeCallback;
......@@ -27,7 +27,7 @@ public class EventUserAccountSaldoPredicate implements FacadeCallback<EventUser>
}
@Override
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, From<?, EventUser> root, List<Predicate> predicates) {
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<EventUser> root, List<Predicate> predicates) {
Subquery<BigDecimal> subq = cq.subquery(BigDecimal.class);
Root<AccountEvent> acRoot = subq.from(AccountEvent.class);
subq.where(cb.equal(acRoot.get(AccountEvent_.user), root));
......
......@@ -4,17 +4,17 @@ import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import fi.codecrew.moya.model.EventUser_;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.EventUser_;
import fi.codecrew.moya.utilities.jpa.FacadeCallback;
public class EventUserPlacegroupPredicate implements FacadeCallback<EventUser> {
@Override
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, From<?, EventUser> root, List<Predicate> predicates) {
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<EventUser> root, List<Predicate> predicates) {
predicates.add(cb.isNotEmpty(root.get(EventUser_.groupMemberships)));
}
......
......@@ -8,7 +8,6 @@ import java.util.Set;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
......@@ -18,13 +17,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.model.AccountEvent_;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.EventUser_;
import fi.codecrew.moya.model.GroupMembership_;
import fi.codecrew.moya.model.Place_;
import fi.codecrew.moya.model.Product_;
import fi.codecrew.moya.model.Role_;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.Role;
import fi.codecrew.moya.model.Role_;
import fi.codecrew.moya.utilities.jpa.FacadeCallback;
public class EventUserRolefilter implements FacadeCallback<EventUser> {
......@@ -49,7 +48,7 @@ public class EventUserRolefilter implements FacadeCallback<EventUser> {
return checkedRoles;
}
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, From<?, EventUser> root, List<Predicate> predicates) {
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<EventUser> root, List<Predicate> predicates) {
if (roles != null && !roles.isEmpty())
{
HashSet<Integer> roleids = new HashSet<Integer>();
......
package fi.codecrew.moya.facade.callbacks;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.EventUser_;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.utilities.jpa.FacadeCallback;
public class EventuserToUserWrapper implements FacadeCallback<EventUser> {
private final FacadeCallback<User>[] callbacks;
@SafeVarargs
public EventuserToUserWrapper(FacadeCallback<User>... wrapped)
{
this.callbacks = wrapped;
}
@Override
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<EventUser> root, List<Predicate> predicates) {
for (FacadeCallback<User> subcallback : callbacks) {
subcallback.exec(cb, cq, root.get(EventUser_.user), predicates);
}
}
}
......@@ -4,7 +4,7 @@ import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.metamodel.SingularAttribute;
......@@ -25,7 +25,7 @@ public class OrPredicateCreator<A, T extends ModelInterface> implements FacadeCa
}
@Override
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, From<?, T> root, List<Predicate> predicates) {
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<T> root, List<Predicate> predicates) {
if (searchstr == null || attributes == null || attributes.isEmpty()) {
return;
}
......
......@@ -4,11 +4,14 @@ import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.metamodel.SingularAttribute;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.utilities.jpa.FacadeCallback;
import fi.codecrew.moya.utilities.jpa.ModelInterface;
......@@ -17,6 +20,7 @@ public class OrderCallback<T extends ModelInterface> implements FacadeCallback<T
private final SingularAttribute<? super T, ?> sort;
private final boolean asc;
private String sortstr;
private static final Logger logger = LoggerFactory.getLogger(OrderCallback.class);
public OrderCallback(boolean asc, SingularAttribute<? super T, ?> sortAttr) {
sort = sortAttr;
......@@ -31,16 +35,15 @@ public class OrderCallback<T extends ModelInterface> implements FacadeCallback<T
}
@Override
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, From<?, T> root, List<Predicate> predicates) {
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<T> root, List<Predicate> predicates) {
Class<?> rettype = cq.getResultType();
// Check if returntype is entity or are we for example counting results
if (!ModelInterface.class.isAssignableFrom(rettype))
{
if (!ModelInterface.class.isAssignableFrom(rettype)) {
return;
}
Path<?> path = null;
Expression<?> path = null;
if (sort == null) {
if (sortstr == null) {
return;
......@@ -56,6 +59,9 @@ public class OrderCallback<T extends ModelInterface> implements FacadeCallback<T
if (path == null) {
return;
}
if (path.getJavaType().equals(String.class)) {
path = cb.lower((Expression<String>) path);
}
if (asc) {
cq.orderBy(cb.asc(path));
......
......@@ -5,7 +5,6 @@ import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.metamodel.SingularAttribute;
......@@ -44,7 +43,7 @@ public abstract class PathStringSearchPredicateCreator<T extends ModelInterface,
}
@Override
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, From<?, T> path, List<Predicate> predicates) {
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<T> path, List<Predicate> predicates) {
if (searchstr == null || attributes == null || attributes.isEmpty()) {
return;
}
......
......@@ -62,5 +62,11 @@
<artifactId>httpclient</artifactId>
<version>4.3-beta2</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.5</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package fi.codecrew.moya.beans;
import org.testng.annotations.Test;
public class BarcodeTests {
@Test
public void tbd() {
}
}
......@@ -18,8 +18,8 @@ public interface BarcodeBeanLocal {
public InputStream getUserBarcode(EventUser user) throws IOException;
public InputStream getCardBarcode(PrintedCard printedCard) throws IOException;
public String getPlaceHexcode(Place place);
public Place getPlaceFromHexcode(String hexcode);
public String getPlaceTextCode(Place place);
public Place getPlaceFromTextCode(String hexcode);
public String checkVrAuthCode(String code);
public Product getProduct(String barcode);
......
......@@ -35,7 +35,9 @@ public interface EventBeanLocal {
List<LanEventPrivateProperty> getPrivateProperties();
LanEventPrivateProperty saveOrCreatePrivateProperty(LanEventPrivateProperty privateProperty);
long getPropertyLong(LanEventPropertyKey property);
LanEvent getEventById(Integer id);
}
......@@ -2,6 +2,7 @@ package fi.codecrew.moya.beans;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.List;
import javax.ejb.Local;
......@@ -10,6 +11,7 @@ import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.Feedback;
import fi.codecrew.moya.model.GameID;
import fi.codecrew.moya.model.GroupMembership;
import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.model.Role;
import fi.codecrew.moya.model.TournamentGame;
import fi.codecrew.moya.model.User;
......@@ -49,7 +51,7 @@ public interface UserBeanLocal {
* ID of the User entity to be searcher
* @return
*/
EventUser findByUserId(Integer userid);
EventUser findByUserId(Integer userid, boolean createEventuser);
EventUser findByEventUserId(Integer integer);
......@@ -72,12 +74,13 @@ public interface UserBeanLocal {
List<Role> findUsersRoles(EventUser u);
/**
* NOTICE! If the user parameter is a persisted object the returned EventUser has a reloaded user, eg changes to the User object are lost!
* NOTICE! If the user parameter is a persisted object the returned
* EventUser has a reloaded user, eg changes to the User object are lost!
*
* @param user
* @return
*/
EventUser getEventUser(User user);
EventUser getEventUser(User user, boolean create);
EventUser validateUser(String username, String password);
......@@ -103,4 +106,23 @@ public interface UserBeanLocal {
boolean isUserInRole(EventUser user, Integer roleId);
EventUser getOtherEventsEventuser(User user, LanEvent event);
/**
* Transfers account saldo from previous event. Creates negative
* accountevent for source user and positive for dst user. There are few
* requirements.
* <ul>
* <li>User must be the same.
* <li>Organisation must be the same.
* <li>All users should have positive or zero balance on source event.
* </ul>
*
* @param source
* @param dst
* @return Saldo transferred. Zero if no transfer was made, Null if there
* was error..
*/
BigDecimal transferAccountSaldoFromPreviousEvent(List<User> dstEventuser, LanEvent source);
}
......@@ -30,208 +30,211 @@ import org.eclipse.persistence.annotations.OptimisticLockingType;
@OptimisticLocking(type = OptimisticLockingType.CHANGED_COLUMNS)
public class AccountEvent extends GenericEntity {
private static final long serialVersionUID = 2588419823225148100L;
@Column(name = "cash", nullable = false)
private boolean cash = false;
/**
* What 1 unit of this product costs.
*/
@Column(name = "unit_price", nullable = false, precision = 24, scale = 4)
private BigDecimal unitPrice;
/**
* The units of the product, eg 1.345 (l), 5 (units) 888.32 (g)..
*/
@Column(name = "quantity", nullable = false, precision = 24, scale = 4)
private BigDecimal quantity;
/**
* The time this AccountEvent is created.
*/
@Column(name = "event_time", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Calendar eventTime = Calendar.getInstance();
/**
* Is the product delivered to the user.
*/
@Column(name = "delivered")
@Temporal(TemporalType.TIMESTAMP)
private Calendar delivered;
@Column(name = "delivered_count", nullable = false, precision = 24, scale = 4)
private BigDecimal deliveredCount = new BigDecimal(0);
/**
* If this AccountEvent is a product in foodwace, this field is a reference
* to that foodwave.
*/
@JoinColumn(name = "food_wave_id", referencedColumnName = FoodWave.ID_COLUMN)
@ManyToOne
private FoodWave foodWave;
/**
* The product user has acquired and this this AccountEvent is a reference
* to.
*/
@JoinColumn(name = "product_id", referencedColumnName = Product.ID_COLUMN, nullable = false)
@ManyToOne(optional = false)
private Product product;
/**
* The user that bought the products.
*/
@JoinColumn(name = "eventuser_id", referencedColumnName = EventUser.ID_COLUMN, nullable = false)
@ManyToOne(optional = false)
private EventUser user;
/**
* Who sold the items to the user.
*/
@JoinColumn(name = "seller_eventuser_id", referencedColumnName = EventUser.ID_COLUMN)
@ManyToOne(optional = true)
private EventUser seller;
/**
* What discounts user has for this account event. Some magic is applied to
* calculate these.. :)
*/
@OneToMany(mappedBy = "accountEvent", cascade = CascadeType.ALL)
private List<DiscountInstance> discountInstances = new ArrayList<DiscountInstance>();
/**
* When user has paid a bill a Account event for product "Credit" is created
* and reference to that bill is here..
*/
@OneToOne(mappedBy = "accountEvent")
private Bill bill;
@Lob
private String description;
public BigDecimal getTotal() {
return getQuantity().multiply(getUnitPrice());
}
public AccountEvent() {
}
public AccountEvent(EventUser u, Product prod, BigDecimal unitPrice, BigDecimal quantity, Calendar eventTime) {
this.setUnitPrice(unitPrice);
this.setQuantity(quantity);
this.product = prod;
this.eventTime = eventTime;
this.user = u;
}
public Calendar getEventTime() {
return eventTime;
}
public void setEventTime(Calendar eventTime) {
this.eventTime = eventTime;
}
public Calendar getDelivered() {
return delivered;
}
public void setDelivered(Calendar delivered) {
this.delivered = delivered;
}
public EventUser getUser() {
return user;
}
public void setUser(EventUser usersId) {
this.user = usersId;
}
public List<DiscountInstance> getDiscountInstances() {
return discountInstances;
}
public void setDiscountInstances(List<DiscountInstance> discountInstanceList) {
this.discountInstances = discountInstanceList;
}
public void setFoodWave(FoodWave foodWave) {
this.foodWave = foodWave;
}
public FoodWave getFoodWave() {
return foodWave;
}
public void setProduct(Product product) {
this.product = product;
}
public Product getProduct() {
return product;
}
public void setSeller(EventUser seller) {
this.seller = seller;
}
public EventUser getSeller() {
return seller;
}
public void setBill(Bill bill) {
this.bill = bill;
}
public Bill getBill() {
return bill;
}
public void setUnitPrice(BigDecimal unitPrice) {
this.unitPrice = unitPrice;
}
public BigDecimal getUnitPrice() {
return unitPrice;
}
public void setQuantity(BigDecimal quantity) {
this.quantity = quantity;
}
public BigDecimal getQuantity() {
return quantity;
}
public void setCash(boolean cash) {
this.cash = cash;
}
public boolean isCash() {
return cash;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public BigDecimal getDeliveredCount() {
return deliveredCount;
}
private static final long serialVersionUID = 2588419823225148100L;
@Column(name = "cash", nullable = false)
private boolean cash = false;
/**
* What 1 unit of this product costs.
*/
@Column(name = "unit_price", nullable = false, precision = 24, scale = 4)
private BigDecimal unitPrice;
/**
* The units of the product, eg 1.345 (l), 5 (units) 888.32 (g)..
*/
@Column(name = "quantity", nullable = false, precision = 24, scale = 4)
private BigDecimal quantity;
/**
* The time this AccountEvent is created.
*/
@Column(name = "event_time", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Calendar eventTime = Calendar.getInstance();
/**
* Is the product delivered to the user.
*/
@Column(name = "delivered")
@Temporal(TemporalType.TIMESTAMP)
private Calendar delivered;
@Column(name = "delivered_count", nullable = false, precision = 24, scale = 4)
private BigDecimal deliveredCount = new BigDecimal(0);
/**
* If this AccountEvent is a product in foodwace, this field is a reference
* to that foodwave.
*/
@JoinColumn(name = "food_wave_id", referencedColumnName = FoodWave.ID_COLUMN)
@ManyToOne
private FoodWave foodWave;
/**
* The product user has acquired and this this AccountEvent is a reference
* to.
*/
@JoinColumn(name = "product_id", referencedColumnName = Product.ID_COLUMN, nullable = false)
@ManyToOne(optional = false)
private Product product;
/**
* The user that bought the products.
*/
@JoinColumn(name = "eventuser_id", referencedColumnName = EventUser.ID_COLUMN, nullable = false)
@ManyToOne(optional = false)
private EventUser user;
/**
* Who sold the items to the user.
*/
@JoinColumn(name = "seller_eventuser_id", referencedColumnName = EventUser.ID_COLUMN)
@ManyToOne(optional = true)
private EventUser seller;
/**
* What discounts user has for this account event. Some magic is applied to
* calculate these.. :)
*/
@OneToMany(mappedBy = "accountEvent", cascade = CascadeType.ALL)
private List<DiscountInstance> discountInstances = new ArrayList<DiscountInstance>();
/**
* When user has paid a bill a Account event for product "Credit" is created
* and reference to that bill is here..
*/
@OneToOne(mappedBy = "accountEvent")
private Bill bill;
@Lob
private String description;
public BigDecimal getTotal() {
return getQuantity().multiply(getUnitPrice());
}
public AccountEvent() {
}
public AccountEvent(EventUser u, Product prod, BigDecimal unitPrice, BigDecimal quantity, Calendar eventTime) {
if (!u.getEvent().equals(prod.getEvent())) {
throw new RuntimeException("User and product are not in the same event!");
}
this.setUnitPrice(unitPrice);
this.setQuantity(quantity);
this.product = prod;
this.eventTime = eventTime;
this.user = u;
}
public Calendar getEventTime() {
return eventTime;
}
public void setEventTime(Calendar eventTime) {
this.eventTime = eventTime;
}
public Calendar getDelivered() {
return delivered;
}
public void setDelivered(Calendar delivered) {
this.delivered = delivered;
}
public EventUser getUser() {
return user;
}
public void setUser(EventUser usersId) {
this.user = usersId;
}
public List<DiscountInstance> getDiscountInstances() {
return discountInstances;
}
public void setDiscountInstances(List<DiscountInstance> discountInstanceList) {
this.discountInstances = discountInstanceList;
}
public void setFoodWave(FoodWave foodWave) {
this.foodWave = foodWave;
}
public FoodWave getFoodWave() {
return foodWave;
}
public void setProduct(Product product) {
this.product = product;
}
public Product getProduct() {
return product;
}
public void setSeller(EventUser seller) {
this.seller = seller;
}
public EventUser getSeller() {
return seller;
}
public void setBill(Bill bill) {
this.bill = bill;
}
public Bill getBill() {
return bill;
}
public void setUnitPrice(BigDecimal unitPrice) {
this.unitPrice = unitPrice;
}
public BigDecimal getUnitPrice() {
return unitPrice;
}
public void setQuantity(BigDecimal quantity) {
this.quantity = quantity;
}
public BigDecimal getQuantity() {
return quantity;
}
public void setCash(boolean cash) {
this.cash = cash;
}
public boolean isCash() {
return cash;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public BigDecimal getDeliveredCount() {
return deliveredCount;
}
public void setDeliveredCount(BigDecimal deliveredCount) {
this.deliveredCount = deliveredCount;
}
public void setDeliveredCount(BigDecimal deliveredCount) {
this.deliveredCount = deliveredCount;
}
public boolean isEventDelivered() {
return (delivered != null);
}
public boolean isEventDelivered() {
return (delivered != null);
}
}
package fi.codecrew.moya.model;
public enum LanEventPropertyKey {
EVENT_LOGO(Type.DATA, null),
INVITEMAIL_SUBJECT(Type.TEXT, "Invitation to Moya Online Youth Accumulator"),
INVITEMAIL_CONTENT(Type.TEXT, "You have been invited to an event by {1}.\n\nYou can register to intranet at: {0}."),
BILL_PAID_MAIL_SUBJECT(Type.TEXT, "[{0}] Lasku merkitty maksetuksi"),
BILL_PAID_MAIL_CONTENT(Type.TEXT, "Laskusi numero {0} on merkitty maksetuksi. Voit nyt siirtyä lippukauppaan varamaan haluamasi paikat. Tervetuloa tapahtumaan!"),
PORTAL_EMAIL_ADDRESS(Type.TEXT, "moya@codecrew.fi"),
PORTAL_EMAIL_NAME(Type.TEXT, "Moya Online Youth Accumulator"),
EVENT_LOGO(Type.DATA, null),
INVITEMAIL_SUBJECT(Type.TEXT, "Invitation to Moya Online Youth Accumulator"),
INVITEMAIL_CONTENT(Type.TEXT, "You have been invited to an event by {1}.\n\nYou can register to intranet at: {0}."),
BILL_PAID_MAIL_SUBJECT(Type.TEXT, "[{0}] Lasku merkitty maksetuksi"),
BILL_PAID_MAIL_CONTENT(Type.TEXT, "Laskusi numero {0} on merkitty maksetuksi. Voit nyt siirtyä lippukauppaan varamaan haluamasi paikat. Tervetuloa tapahtumaan!"),
PORTAL_EMAIL_ADDRESS(Type.TEXT, "moya@codecrew.fi"),
PORTAL_EMAIL_NAME(Type.TEXT, "Moya Online Youth Accumulator"),
ADMIN_MAIL(Type.TEXT, "moya@codecrew.fi"),
EVENT_LAYOUT(Type.TEXT, "template1"),
SHOP_DEFAULT_CASH(Type.BOOL, null),
PLACECODE_FROM_USER(Type.BOOL, "1"),
PLACECODE_PRINT_ONLY_OWN(Type.BOOL, null),
CHECK_BILL_STATS_PERMISSION(Type.BOOL, null),
GATHER_OTHER_BILL_INFO(Type.BOOL, null),
ALLOW_BILLING(Type.BOOL, null),
BILL_EXPIRE_HOURS(Type.LONG, "168"),
TEMPLATE_PROPERTY1(Type.TEXT, null),
TEMPLATE_PROPERTY2(Type.TEXT, null),
TEMPLATE_PROPERTY3(Type.TEXT, null),
TEMPLATE_PROPERTY4(Type.TEXT, null),
TEMPLATE_PROPERTY5(Type.TEXT, null),
ADMIN_MAIL(Type.TEXT, "moya@codecrew.fi"),
EVENT_LAYOUT(Type.TEXT, "template1"),
SHOP_DEFAULT_CASH(Type.BOOL, null),
PLACECODE_FROM_USER(Type.BOOL, "1"),
PLACECODE_PRINT_ONLY_OWN(Type.BOOL, null),
CHECK_BILL_STATS_PERMISSION(Type.BOOL, null),
GATHER_OTHER_BILL_INFO(Type.BOOL, null),
ALLOW_BILLING(Type.BOOL, null),
BILL_EXPIRE_HOURS(Type.LONG, "168"),
TEMPLATE_PROPERTY1(Type.TEXT, null),
TEMPLATE_PROPERTY2(Type.TEXT, null),
TEMPLATE_PROPERTY3(Type.TEXT, null),
TEMPLATE_PROPERTY4(Type.TEXT, null),
TEMPLATE_PROPERTY5(Type.TEXT, null),
INVITE_ONLY_EVENT(Type.BOOL, null),
;
;
private enum Type {
TEXT, DATE, DATA, BOOL, LONG
};
private enum Type {
TEXT, DATE, DATA, BOOL, LONG
};
private final String defaultvalue;
private final Type type;
private final String defaultvalue;
private final Type type;
public boolean isText() {
return Type.TEXT.equals(type);
}
public boolean isText() {
return Type.TEXT.equals(type);
}
public boolean isDate() {
return Type.DATE.equals(type);
}
public boolean isDate() {
return Type.DATE.equals(type);
}
public boolean isData() {
return Type.DATA.equals(type);
}
public boolean isData() {
return Type.DATA.equals(type);
}
public boolean isBoolean() {
return Type.BOOL.equals(type);
}
public boolean isLong() {
return Type.LONG.equals(type);
}
public boolean isBoolean() {
return Type.BOOL.equals(type);
}
private LanEventPropertyKey(Type t, String def)
{
this.type = t;
defaultvalue = def;
}
public boolean isLong() {
return Type.LONG.equals(type);
}
public String getDefaultvalue() {
return defaultvalue;
}
private LanEventPropertyKey(Type t, String def)
{
this.type = t;
defaultvalue = def;
}
public Type getType() {
return type;
}
public String getDefaultvalue() {
return defaultvalue;
}
public Type getType() {
return type;
}
}
package fi.codecrew.moya.model;
import java.beans.Transient;
import java.util.Calendar;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
......@@ -42,7 +43,7 @@ public class ReaderEvent extends GenericEntity {
private String notes;
@JoinColumn(name = "printed_cards_id", referencedColumnName = "id", nullable = true, updatable = false)
@ManyToOne(optional = false)
@ManyToOne()
private PrintedCard printedCard;
@JoinColumn(name = "readers_id", referencedColumnName = "id", nullable = false, updatable = false)
......@@ -50,17 +51,18 @@ public class ReaderEvent extends GenericEntity {
private Reader reader;
@JoinColumn(name = "event_users_id", referencedColumnName = "id", nullable = true, updatable = false)
@ManyToOne(optional = false)
@ManyToOne()
private EventUser user;
@JoinColumn(name = "places_id", referencedColumnName = "id", nullable = true, updatable = false)
@ManyToOne(optional = false)
@ManyToOne()
private Place place;
@JoinColumn(name = "products_id", referencedColumnName = "id", nullable = true, updatable = false)
@ManyToOne(optional = false)
@ManyToOne()
private Product product;
@Enumerated(EnumType.STRING)
private ReaderEventType type;
public ReaderEvent(Date eventTime, Reader reader, String value) {
......
......@@ -4,14 +4,13 @@ import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
public interface FacadeCallback<C extends ModelInterface> {
// void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Root<C> root,
// List<Predicate> predicates);
void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, From<?, C> root, List<Predicate> predicates);
void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<C> root, List<Predicate> predicates);
}
......@@ -10,16 +10,16 @@
<f:viewParam name="userid" value="#{userView.userid}" />
<f:event type="preRenderView" listener="#{incomingView.initPrintCardView}" />
</f:metadata>
<ui:define name="content">
<ui:define name="content">
<h:outputScript library="primefaces" name="jquery/jquery.js" target="head" />
<h1>#{i18n['incomingflow.userdetails']} </h1>
<h1>#{i18n['incomingflow.userdetails']}</h1>
<h:panelGrid id="cropper" columns="3">
<h:panelGroup>
<user:edit id="usereditor" commitaction="#{incomingView.saveUser()}" commitvalue="#{i18n['user.save']}" camAlwaysOn="true" />
<user:edit id="usereditor" commitaction="#{incomingView.saveUser()}" commitvalue="#{i18n['user.save']}" camAlwaysOn="true" />
</h:panelGroup>
<h:panelGroup>
<h:form id="imgCropperForm" rendered="#{!empty userView.user.currentImage}">
<p:commandButton value="#{i18n['user.imageCropRefresh']}" ajax="false" update="imgCropperForm" />
<p:commandButton value="#{i18n['user.imageCropRefresh']}" ajax="false" update="imgCropperForm" />
<h:outputLabel value="#{i18n['user.cropUserImage']}:" />
<p:imageCropper id="imgCropper" value="#{userView.croppedImage}" aspectRatio="0.7317073170731707" image="/dydata/userimage/#{userView.user.currentImage.id}.img" />
<br />
......@@ -27,18 +27,19 @@
</h:form>
</h:panelGroup>
<h:panelGroup>
<h:form >
<p:graphicImage url="/dydata/usercard/#{userView.user.user.id}.png" width="300" /><br />
<h:commandButton action="#{incomingView.printCard}" value="#{i18n['print']}" /> (status: #{incomingView.printedStatus})
<h:form>
<p:graphicImage url="/dydata/usercard/#{userView.user.user.id}.png" width="300" />
<br />
<h:commandButton action="#{incomingView.printCard}" value="#{i18n['print']}" /> (status: #{incomingView.printedStatus})
</h:form>
</h:panelGroup>
</h:panelGrid>
<h:outputText rendered="#{empty incomingView.groupMemberships}" value="#{i18n['placegroupview.noMemberships']}" />
<h:form rendered="#{!empty incomingView.groupMemberships}" id="placelistform">
<h:form rendered="#{!empty incomingView.groupMemberships}" id="placelistform">
<p:dataTable value="#{incomingView.groupMemberships}" var="member" rowStyleClass="#{member.enteredEvent != null ? 'success':''}">
......@@ -83,15 +84,15 @@
<h:panelGrid columns="2">
<h:outputText value="#{i18n['incomingflow.barcode']}" />
<h:outputText value="#{i18n['incomingflow.multisearch']}" />
<p:autoComplete id="acs" value="#{incomingView.searchBarcode}" completeMethod="#{incomingView.matchBarcode}">
<p:ajax event="itemSelect" listener="#{incomingView.changeUser}" />
</p:autoComplete>
<p:autoComplete id="acsb" value="#{incomingView.searchMulti}" completeMethod="#{incomingView.matchMulti}" converter="#{eventUserConverter}" var="usrx" itemLabel="#{usrx.shortUserDescriptor}" itemValue="#{usrx}">
<p:ajax event="itemSelect" listener="#{incomingView.changeUser}" />
</p:autoComplete>
</h:panelGrid>
</h:panelGrid>
</h:form>
</ui:define>
......
......@@ -9,6 +9,7 @@
xmlns:p="http://primefaces.org/ui"
xmlns:shop="http://java.sun.com/jsf/composite/cditools/shop"
xmlns:reader="http://java.sun.com/jsf/composite/cditools/reader"
xmlns:infoview="http://java.sun.com/jsf/composite/cditools/infoview"
xmlns:tools="http://java.sun.com/jsf/composite/cditools">
<h:body>
<ui:composition
......@@ -22,6 +23,11 @@
<f:event type="preRenderView" listener="#{readerList.initReaderList}" />
</f:metadata>
<ui:define name="headercontent">
<infoview:userselector />
</ui:define>
<ui:define name="content">
<h:form>
......@@ -36,6 +42,7 @@
</ui:define>
</ui:composition>
</h:body>
......
<?xml version='1.0' encoding='UTF-8' ?>
<!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:p="http://primefaces.org/ui"
xmlns:reader="http://java.sun.com/jsf/composite/cditools/reader"
>
<composite:interface>
</composite:interface>
<composite:implementation>
<reader:bacendReader />
</composite:implementation>
</html>
\ No newline at end of file
......@@ -2,24 +2,20 @@
<!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:p="http://primefaces.org/ui">
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:p="http://primefaces.org/ui">
<composite:interface>
</composite:interface>
<composite:implementation>
<p:dataTable styleClass="bordertable" id="usertable" value="#{userSearchView.eventuserModel}" rows="20" paginator="true" lazy="true" var="user">
<p:column>
<f:facet name="header">
<h:link value="#{i18n['user.nick']}" includeViewParams="true">
<f:param name="sort" value="nick" />
</h:link>
</f:facet>
<p:dataTable styleClass="bordertable" id="usertable" value="#{userSearchView.eventuserModel}" rows="20" paginator="true" lazy="true" var="user">
<p:column headerText="#{i18n['user.nick']}" sortBy="nick">
<h:outputText styleClass="hoverable" value="#{(empty user.nick)?'----':user.nick}" />
<div class="userdata_popup">
<h:panelGrid columns="3" >
<h:panelGrid columns="3">
<img style="width: 100px;" src="#{request.contextPath}/dydata/userimage/#{user.currentImage.id}.img" alt="image" />
<h:panelGroup>
......@@ -40,7 +36,7 @@
<h:outputText value="#{user.email}" />
<br />
<h:outputText value="#{i18n['user.accountBalance']}: " />
<h:outputText value="#{user.accountBalance}">
<f:convertNumber maxFractionDigits="2" minFractionDigits="0" />
</h:outputText>
......@@ -49,34 +45,23 @@
</div>
</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>
<p:column sortBy="login" headerText="#{i18n['user.login']}">
<h:outputText value="#{user.login}" />
</p:column>
<p:column headerText="#{i18n['user.firstNames']}" sortBy="firstnames">
<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>
<p:column headerText="#{i18n['user.lastName']}" sortBy="lastname">
<h:outputText value="#{user.lastname}" />
</p:column>
<p:column>
<f:facet name="header">
<h:link value="#{i18n['user.email']}" includeViewParams="true" >
<f:param name="sort" value="email" />
</h:link>
</f:facet>
<p:column headerText="#{i18n['user.email']}" sortBy="email">
<h:outputText value="#{user.email}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="#{i18n['userlist.searchcount']}" />: <h:outputText value="#{userSearchView.resultcount}" />
</f:facet>
<button onclick="location.replace('#{request.contextPath}/useradmin/edit.jsf?userid=#{user.user.id}')">#{i18n['user.edit']}</button>
</p:column>
......@@ -85,15 +70,14 @@
</h:column> -->
</p:dataTable>
<script>
jQuery(function() {
jQuery(".hoverable").hover(function () {
jQuery(this).next().fadeIn('fast');
},
function () {
jQuery(this).next().fadeOut('fast');
});
});
</script>
jQuery(function() {
jQuery(".hoverable").hover(function() {
jQuery(this).next().fadeIn('fast');
}, function() {
jQuery(this).next().fadeOut('fast');
});
});
</script>
</composite:implementation>
</html>
......
......@@ -7,69 +7,65 @@
</composite:interface>
<composite:implementation>
<h:outputScript library="primefaces" name="jquery/jquery.js" target="head" />
<h:outputScript library="primefaces" name="jquery/jquery.js" target="head" />
<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}" />
<p:dataTable id="user" value="#{userSearchView.userModel}" rows="20" var="wra" paginator="true" lazy="true">
<p:column sortBy="nick" headerText="#{i18n['user.nick']}">
<h:outputText value="#{(empty wra.user.nick)?'----':wra.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 sortBy="login" headerText="#{i18n['user.login']}">
<h:outputText value="#{wra.user.login}" />
</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 headerText="#{i18n['user.firstNames']}" sortBy="firstnames">
<h:outputText value="#{wra.user.firstnames}" />
</p:column>
<p:column headerText="#{i18n['user.lastName']}" sortBy="lastname">
<h:outputText value="#{wra.user.lastname}" />
</p:column>
<p:column headerText="#{i18n['user.email']}" sortBy="email">
<h:outputText value="#{wra.user.email}" />
</p:column>
<p:column>
<h:link outcome="/useradmin/edit" value="#{i18n['user.edit']}">
<f:param name="userid" value="#{user.id}" />
<f:facet name="header">
<h:outputText value="#{i18n['userlist.searchcount']}" />: <h:outputText value="#{userSearchView.resultcount}" />
</f:facet>
<h:link rendered="#{!empty wra.eventuser}" outcome="/useradmin/edit" value="#{i18n['user.edit']}">
<f:param name="userid" value="#{wra.user.id}" />
</h:link>
<h:link rendered="#{empty wra.eventuser}" outcome="/useradmin/edit" value="#{i18n['user.addToEvent']}" onclick="return confirm('#{i18n['user.confirmUserToEventAdding']}')">
<f:param name="userid" value="#{wra.user.id}" />
</h:link>
<!-- <p:commandButton onClick="location.replace('#{request.contextPath}/useradmin/edit.jsf?userid=#{user.id}')">#{i18n['user.edit']}</p:commandButton>
<!-- <p:commandButton onClick="location.replace('#{request.contextPath}/useradmin/edit.jsf?userid=#{wra.user.id}')">#{i18n['user.edit']}</p:commandButton>
<p:overlayPanel for="userinfoBtn">
<h:panelGrid columns="2">
<img style="width:100px;" src="#{request.contextPath}/dydata/userimage/#{user.currentImage.id}.img" alt="image" />
<img style="width:100px;" src="#{request.contextPath}/dydata/userimage/#{wra.user.currentImage.id}.img" alt="image" />
<h:panelGroup>
<h:outputText value="#{user.nick}"/> <br />
<h:outputText value="#{user.firstnames} #{user.lastname}"/> <br />
<h:outputText value="#{wra.user.nick}"/> <br />
<h:outputText value="#{wra.user.firstnames} #{wra.user.lastname}"/> <br />
<hr />
<h:outputText value="#{user.address}"/> <br />
<h:outputText value="#{user.zip} #{user.postalTown}"/> <br />
<h:outputText value="#{wra.user.address}"/> <br />
<h:outputText value="#{wra.user.zip} #{wra.user.postalTown}"/> <br />
<br />
<h:outputText value="#{user.phone}"/> <br />
<h:outputText value="#{user.email}"/> <br />
<h:outputText value="#{wra.user.phone}"/> <br />
<h:outputText value="#{wra.user.email}"/> <br />
</h:panelGroup>
</h:panelGrid>
</p:overlayPanel>
-->
-->
</p:column>
<!-- <h:column>
<h:commandButton action="#{userView.shop()}" value="#{i18n['user.shop']}" />
</h:column> -->
</p:dataTable>
<script>
jQuery(function() {
jQuery(".hoverable").hover(function () {
......
......@@ -283,12 +283,29 @@ label {
text-decoration: none;
}
#header_left {
float: left;
width: 400px;
}
#header_center {
float: left;
widows: 300px;
}
#header_right {
text-align: right;
float: right;
width: 400px;
}
.success {
color: #006600;
}
\ No newline at end of file
}
\ No newline at end of file
......@@ -14,6 +14,7 @@
<link rel="icon" href="#{request.contextPath}/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="#{request.contextPath}/resources/templates/blipview/css/style.css" />
<link rel="stylesheet" type="text/css" href="#{request.contextPath}/resources/templates/blipview/css/general.css" />
<link rel="stylesheet" type="text/css" href="#{request.contextPath}/resources/templates/custom_components.css" />
<ui:insert name="headerdata" />
</h:head>
......@@ -37,8 +38,17 @@
</h1>
</ui:fragment>
</c:otherwise>
</c:choose>
</h:link>
<div class="topmenu">
<h:form>
<p:menubar rendered="#{primeMenuView.hasSecondaryMenu}" model="#{primeMenuView.secondaryMenuModel}" />
</h:form>
</div>
</div>
<div id="header_center">
<ui:insert name="headercontent" />
</div>
<div id="header_right">
<img src="#{request.contextPath}/resources/templates/template1/img/moya_logo.png" />
......
......@@ -16,14 +16,16 @@
}
.hidden {
display: none;
}
#webcamcontainer {
}
.noborderTable tr,.noborderTable td {
border: none;
padding: 0 0 1px 0;
}
#shopItems {
}
......@@ -77,7 +79,6 @@ a.shopItem:active {
background: red;
}
.prime-menu-selected div
{
display:block;
.prime-menu-selected div {
display: block;
}
\ No newline at end of file
......@@ -8,34 +8,31 @@
<ui:define name="content">
<h:form id="wrapform">
<h:dataTable id="tbl" border="1" value="#{importView.wrapper}" var="wra">
<h:column>
<h:selectBooleanCheckbox id="skip" value="#{wra.skip}" />
</h:column>
<h:column>
<h:outputText value="#{wra.user.login}" />
</h:column>
<h:column>
<h:outputText value="#{wra.user.firstnames}" />
</h:column>
<h:column>
<h:outputText value="#{wra.user.lastname}" />
</h:column>
<h:column>
<h:outputText value="#{wra.user.email}" />
</h:column>
<h:column>
<h:outputText value="#{wra.user.accountBalance}" />
</h:column>
<h:column>
<h:selectOneRadio id="selected" value="#{wra.selected}" layout="pageDirection" converter="#{userConverter}">
<f:selectItems var="pot" value="#{wra.potential}" itemLabel="#{pot.id}/#{pot.login}/#{pot.firstnames}/#{pot.lastname}" />
</h:selectOneRadio>
</h:column>
</h:dataTable>
<h:commandButton action="#{importView.commitImport}" value="#{i18n['userImport.commit']}" />
</h:form>
<p:dataTable id="tbl" border="1" value="#{importView.users}" var="wra">
<p:column headerText="User id">
<h:outputText value="#{wra.user.id}" />
</p:column>
<p:column headerText="Eventuser id">
<h:outputText value="#{wra.eventuser.id}" />
</p:column>
<p:column headerText="Login">
<h:outputText value="#{wra.user.login}" />
</p:column>
<p:column headerText="Firstname">
<h:outputText value="#{wra.user.firstnames}" />
</p:column>
<p:column headerText="Lastname">
<h:outputText value="#{wra.user.lastname}" />
</p:column>
<p:column headerText="Email">
<h:outputText value="#{wra.user.email}" />
</p:column>
</p:dataTable>
</ui:define>
</ui:composition>
</h:body>
......
......@@ -12,11 +12,6 @@
<h:form enctype="multipart/form-data">
<h:panelGrid columns="3">
<h:outputLabel for="templ" value="#{i18n['importuser.template']}" />
<h:selectOneMenu id="templ" value="#{importView.template}" converter="#{cardTemplateConverter}">
<f:selectItems value="#{importView.templates}" var="templ" itemLabel="#{templ.name}" />
</h:selectOneMenu>
<h:message for="templ" />
<h:outputLabel for="file" value="#{i18n['importuser.file']}"/>
<p:fileUpload id="file" value="#{importView.file}" mode="simple" />
......
......@@ -2,7 +2,7 @@
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:f="http://java.sun.com/jsf/core">
xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui">
<h:body>
<ui:composition template="#{sessionHandler.template}">
<f:metadata>
......@@ -19,66 +19,48 @@
<ui:define name="content">
<h:outputLabel value="#{i18n['user.accountBalance']}: " for="accountbalance" />
<h:outputText id="accountbalance" value="#{userView.user.accountBalance}" />
<h:dataTable border="1" id="ac" value="#{userView.user.accountEvents}" var="ac">
<h:column>
<f:facet name="header">
<h:outputText value="#{i18n['accountEvent.productname']}" />
</f:facet>
<p:dataTable border="1" styleClass="actable" id="ac" value="#{userView.user.accountEvents}" var="ac" rowIndexVar="rowIndex">
<p:column headerText="#{i18n['accountEvent.productname']}">
<p:tooltip for="@(.actable tr[role=row][data-ri=#{rowIndex}])" value="This is row number #{rowIndex}" />
<h:outputText value="#{ac.product.name}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{i18n['accountEvent.quantity']}" />
</f:facet>
</p:column>
<p:column headerText="#{i18n['accountEvent.quantity']}">
<h:outputText value="#{ac.quantity}">
<f:convertNumber minFractionDigits="2" maxFractionDigits="2" />
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{i18n['accountEvent.unitPrice']}" />
</f:facet>
</p:column>
<p:column headerText="#{i18n['accountEvent.unitPrice']}">
<h:outputText value="#{ac.unitPrice}">
<f:convertNumber minFractionDigits="2" maxFractionDigits="2" />
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{i18n['accountEvent.total']}" />
</f:facet>
</p:column>
<p:column headerText="#{i18n['accountEvent.total']}">
<h:outputText value="#{ac.total}">
<f:convertNumber minFractionDigits="2" maxFractionDigits="2" />
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{i18n['accountEvent.eventTime']}" />
</f:facet>
</p:column>
<p:column headerText="#{i18n['accountEvent.eventTime']}">
<h:outputText value="#{ac.eventTime.time}">
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}" timeZone="#{sessionHandler.timezone}" />
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{i18n['accountEvent.delivered']}" />
</f:facet>
</p:column>
<p:column headerText="#{i18n['accountEvent.delivered']}">
<h:outputText rendered="#{!empty ac.delivered}" value="#{ac.delivered.time}">
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}" timeZone="#{sessionHandler.timezone}" />
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{i18n['accountEvent.foodwave']}" />
</f:facet>
</p:column>
<p:column headerText="#{i18n['accountEvent.foodwave']}">
<h:outputText rendered="#{!empty ac.foodWave}" value="#{ac.foodWave.name}" />
</h:column>
</p:column>
<h:column>
<p:column>
<h:link outcome="/useradmin/editAccountevent" value="#{i18n['accountEvent.edit']}">
<f:param name="id" value="#{ac.id}" />
</h:link>
</h:column>
</h:dataTable>
</p:column>
</p:dataTable>
</ui:define>
</ui:composition>
</h:body>
......
......@@ -20,19 +20,19 @@
<h:panelGrid columns="3">
<h:outputLabel for="user" value="#{i18n['accountEvent.user']}" />
<h:outputText id="user" value="#{accountEventView.accountevent.user.user.id} / #{accountEventView.accountevent.user.user.wholeName}" />
<h:outputText id="user" value="#{accountEventView.accountevent.user.user.id} / #{accountEventView.accountevent.user.user.nick} /#{accountEventView.accountevent.user.user.wholeName}" />
<h:message for="user" />
<h:outputLabel for="price" value="#{i18n['accountEvent.price']}" />
<h:inputText id="price" value="#{accountEventView.accountevent.unitPrice}">
<p:inputText id="price" value="#{accountEventView.accountevent.unitPrice}">
<f:convertNumber minFractionDigits="0" maxFractionDigits="4" />
</h:inputText>
</p:inputText>
<h:message for="price" />
<h:outputLabel for="quantity" value="#{i18n['accountEvent.quantity']}" />
<h:inputText id="quantity" value="#{accountEventView.accountevent.quantity}">
<p:inputText id="quantity" value="#{accountEventView.accountevent.quantity}">
<f:convertNumber minFractionDigits="0" maxFractionDigits="4" />
</h:inputText>
</p:inputText>
<h:message for="quantity" />
<h:outputLabel for="time" value="#{i18n['accountEvent.eventTime']}" />
......@@ -43,14 +43,22 @@
<h:link id="fw" rendered="#{!empty accountEventView.accountevent.foodWave}" value="#{accountEventView.accountevent.foodWave.name}" outcome="/foodmanager/listOrders">
<f:param name="foodwaveid" value="#{accountEventView.accountevent.foodWave.id}" />
</h:link>
<h:outputText rendered="#{empty accountEventView.accountevent.foodWave}"/>
<h:outputText rendered="#{empty accountEventView.accountevent.foodWave}" />
<h:message for="fw" />
<h:outputLabel for="delivered" value="#{i18n['accountEvent.delivered']}" />
<p:calendar rendered="#{!empty accountEventView.accountevent.delivered}" id="delivered" value="#{accountEventView.accountevent.delivered.time}" pattern="#{sessionHandler.datetimeFormat}" timeZone="#{sessionHandler.timezone}" />
<h:outputText rendered="#{empty accountEventView.accountevent.delivered}" />
<p:calendar rendered="#{!empty accountEventView.accountevent.delivered}" id="delivered" value="#{accountEventView.accountevent.delivered.time}" pattern="#{sessionHandler.datetimeFormat}"
timeZone="#{sessionHandler.timezone}" />
<h:outputText rendered="#{empty accountEventView.accountevent.delivered}" />
<h:message for="delivered" />
<h:outputLabel for="seller" value="#{i18n['accountEvent.seller']}" />
<h:outputText id="seller" value="#{accountEventView.accountevent.seller.user.nick} / #{accountEventView.accountevent.seller.user.wholeName}" />
<h:message for="seller" />
<p:outputLabel for="description" value="#{i18n['accountEvent.description']}" />
<p:inputTextarea id="description" cols="30" rows="5" value="#{accountEventView.accountevent.description}" />
<p:message for="description" />
</h:panelGrid>
<h:commandButton action="#{accountEventView.save()}" rendered="#{accountEventView.canSave}" value="#{i18n['accountEvent.save']}" />
......
......@@ -19,7 +19,7 @@
<h1>#{i18n['userlist.header']}</h1>
<h:form>
<h:form id="pageform">
<h:panelGrid columns="2">
<h:panelGroup>
......@@ -51,22 +51,28 @@
<h:commandButton value="#{i18n['userlist.search']}" action="#{userSearchView.newSearch()}" />
</h:panelGroup>
<h:panelGroup>
<a style="display: #{((userCartView.isEmpty())?'block':'none')}" onclick="$('#usercart').show(); $(this).hide();"><h:outputText value="#{i18n['usercart.showCart']}" /></a>
<div id="usercart" style="display: #{((userCartView.isEmpty())?'none':'block')}">
<h:outputText value="#{i18n['usercart.cartsize']}" />
<h:outputText value=" #{userCartView.userCartSize}" />
<h:commandButton action="#{userCartView.clearCart()}" value="#{i18n['usercart.clear']}" />
<br />
<a onclick="$('#pageform\\:usercart').show(); $(this).hide();"><h:outputText value="#{i18n['usercart.showCart']}" /></a>
<p:panelGrid columns="1" id="usercart" styleClass="noborderTable" style="display:none;">
<h:commandButton actionListener="#{userSearchView.addToCart}" value="#{i18n['usercart.addSearchedUsers']}" />
<h:panelGroup>
<h:outputText value="#{i18n['usercart.cartsize']} #{userCartView.userCartSize}" />
<h:commandButton action="#{userCartView.clearCart()}" value="#{i18n['usercart.clear']}" />
</h:panelGroup>
<h:commandButton action="#{userCartView.traverse}" value="#{i18n['usercart.traverse']}" />
<h:commandButton value="#{i18n['usercart.downloadCsv']}">
<p:fileDownload value="#{userCartView.downloadCsv}" />
</h:commandButton>
<h:commandButton value="#{i18n['usercart.downloadExport']}">
<p:fileDownload value="#{userCartView.userExport}" />
</h:commandButton>
<h:commandButton action="#{userCartView.showOverview}" value="#{i18n['usercart.showoverview']}" />
</div>
<h:commandButton rendered="#{creditTransferView.transferPermissions}" action="#{userCartView.transferCredits}" value="#{i18n['usercart.transferCredits']}" />
</p:panelGrid>
</h:panelGroup>
</h:panelGrid>
<h:outputText value="#{i18n['userlist.searchcount']}" />: <h:outputText value="#{userSearchView.resultcount}" />
</h:form>
<p>
<users:list rendered="#{!userSearchView.searchQuery.onlyThisEvent}" />
......
<!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:tools="http://java.sun.com/jsf/composite/cditools" xmlns:account="http://java.sun.com/jsf/composite/cditools/account" xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui">
<h:body>
<ui:composition template="#{sessionHandler.template}">
<f:metadata>
<!-- f:event type="preRenderView" listener="#{userCartView.initView}" />
-->
</f:metadata>
<ui:define name="title">
<h1>#{i18n['user.creditTransfer.title']}</h1>
</ui:define>
<ui:define name="content">
<h:form>
<h:outputText value="#{i18n['creditTransferView.selectEvent']}" />
<p:selectOneMenu value="#{creditTransferView.sourceEvent}" converter="#{lanEventConverter}">
<f:selectItem itemLabel="---" />
<f:selectItems value="#{creditTransferView.events}" var="ev" itemLabel="#{ev.name}" />
</p:selectOneMenu>
<h:commandButton action="#{creditTransferView.selectEvent}" value="#{i18n['creditTransfer.selectEvent']}" />
</h:form>
<h:outputText value="#{i18n['creditTransfer.totalCredits']} #{creditTransferView.totalCredits}" />
<h:form>
<h:commandButton value="#{i18n['creditTransferView.commitTransfer']}" action="#{creditTransferView.commitTransfer}" />
<p:dataTable value="#{creditTransferView.users}" var="wrap">
<p:column headerText="#{i18n['user.nick']}">
<h:outputText value="#{wrap.user.user.nick}" />
</p:column>
<p:column headerText="#{i18n['creditTransfer.dstEventuserId']}">
<h:outputText value="#{wrap.user.id}" />
</p:column>
<p:column headerText="#{i18n['creditTransfer.srcEventuserId']}">
<h:outputText value="#{wrap.sourceEventuser.id}" />
</p:column>
<p:column headerText="#{i18n['creditTransfer.credits']}">
<h:outputText value="#{wrap.credits}">
<f:convertNumber minFractionDigits="2" maxFractionDigits="2" />
</h:outputText>
</p:column>
</p:dataTable>
</h:form>
</ui:define>
</ui:composition>
</h:body>
</html>
\ No newline at end of file
......@@ -72,7 +72,7 @@ public class HostnameFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
logger.info("HostnameFilter called!");
// logger.info("HostnameFilter called!");
HttpServletRequest httpRequest = null;
if (request != null && request instanceof HttpServletRequest) {
......@@ -161,14 +161,14 @@ public class HostnameFilter implements Filter {
protected void parseHostname(HttpServletRequest httpRequest)
{
logger.info("Path info {}", httpRequest.getPathInfo());
logger.info("querystring {}", httpRequest.getQueryString());
logger.info("ctxpath {}", httpRequest.getContextPath());
logger.info("pathTranslated {}", httpRequest.getPathTranslated());
logger.info("requestUri {}", httpRequest.getRequestURI());
logger.info("URL {}", httpRequest.getRequestURL().toString());
logger.info("servletpath {}", httpRequest.getServletPath());
logger.info("servletCtx {}", httpRequest.getServletContext());
// logger.info("Path info {}", httpRequest.getPathInfo());
// logger.info("querystring {}", httpRequest.getQueryString());
// logger.info("ctxpath {}", httpRequest.getContextPath());
// logger.info("pathTranslated {}", httpRequest.getPathTranslated());
// logger.info("requestUri {}", httpRequest.getRequestURI());
// logger.info("URL {}", httpRequest.getRequestURL().toString());
// logger.info("servletpath {}", httpRequest.getServletPath());
// logger.info("servletCtx {}", httpRequest.getServletContext());
StringBuffer url = httpRequest.getRequestURL();
// logger.info("Original hostname {}", url);
// Subject subj = Subject.getSubject(AccessController.getContext());
......
......@@ -64,7 +64,6 @@ public class SessionHandler {
String retStr = "fi_FI";
if (ret != null) {
retStr = ret.toLanguageTag();
logger.info("Got langtag {}", retStr);
}
return retStr;
}
......
......@@ -231,12 +231,17 @@ resetMail.username = Username
resetmailSent.body = Email has been sent containing a link where you can change the password.
resetmailSent.header = Email sent
submenu.NotImplementedYet = Not implemented
submenu.frontpage = Frontpage
submenu.NotImplementedYet = Not implemented
submenu.admin.adduser = K\u00E4ytt\u00E4j\u00E4nlis\u00E4ys
submenu.admin.adduser.index = K\u00E4ytt\u00E4j\u00E4nlis\u00E4ys
submenu.frontpage = Frontpage
submenu.info.incoming = Incomingview
submenu.info.index = Infon\u00E4kym\u00E4
subnavi.cards = \u0009\u0009
subnavi.info = Info
topnavi.license = Lisenssikoodit
topnavi.license = Lisenssikoodit
user.cropImage = Crop
user.imageUpload.imageNotFound = Select image to upload
......
......@@ -910,6 +910,8 @@ sitepagelist.header = Site pages
submenu.NotImplementedYet = Not implemented
submenu.actionlog.messagelist = ActionLog
submenu.actionlog.taskview = View tasks
submenu.admin.adduser = Adduser
submenu.admin.adduser.index = Adduser
submenu.admin.adduser.login = Login
submenu.admin.adduser.start = Welcome
submenu.admin.adduser.update = Update profile picture
......@@ -936,6 +938,8 @@ submenu.foodmanager.listFoodwaves = List active foodwaves
submenu.foodwave.list = Foodwaves
submenu.foodwave.listTemplates = Food provides
submenu.index = Frontpage
submenu.info.incoming = Sis\u00E4\u00E4ntulo
submenu.info.index = Infoview
submenu.license.manageCodes = Manage codes
submenu.license.viewCodes = View codes
submenu.map.create = Create map
......@@ -994,6 +998,7 @@ submenu.voting.submitEntry = Submit entry
subnavi.billing = Billing
subnavi.cards = Cards
subnavi.info = Info
subnavi.products = Products
subnavi.readers = Readers
subnavi.roles = Roles
......@@ -1026,6 +1031,7 @@ topnavi.event = Event
topnavi.foodwave = Food
topnavi.frontpage = Front page
topnavi.game = Gamecodes
topnavi.infoviews = Infoviews
topnavi.license = Licensecodes
topnavi.log = Log
topnavi.login = Login
......@@ -1155,6 +1161,7 @@ tournaments.tournament_type = Tournament typ
user.accountBalance = Account balance
user.accountEventHeader = Account events
user.accountevents = Account events
user.addToEvent = Associate user to event
user.address = Address
user.age = Age
user.bank = Bank
......@@ -1164,6 +1171,7 @@ user.cardPower = Usertype
user.changePassword = Change password
user.changepassword.forUser = For user
user.changepassword.title = Change password
user.confirmUserToEventAdding = Are you sure you want to associate this user to this event?
user.create = Create user
user.createdmessage = User has been created successfully. You can now login.
user.cropImage = Crop image
......
......@@ -357,7 +357,7 @@ foodwavetemplate.actions = Toimet
foodwavetemplate.addproduct = Lis\u00E4\u00E4
foodwavetemplate.basicinfo = Tilauspohja
foodwavetemplate.createFoodwave = Luo ruokatilaus
foodwavetemplate.createwave = Luo tilauspohja
foodwavetemplate.createwave = Luo tilaus
foodwavetemplate.description = Kuvaus
foodwavetemplate.edit = Muokkaa tilauspohjaa
foodwavetemplate.editRow = Muokkaa
......@@ -891,6 +891,8 @@ sitepagelist.header = Sivuston sis\u00E4ll\u00F6t
submenu.NotImplementedYet = Toteuttamatta
submenu.actionlog.messagelist = ActionLog
submenu.actionlog.taskview = N\u00E4yt\u00E4 toiminnat
submenu.admin.adduser = K\u00E4ytt\u00E4j\u00E4nlis\u00E4ys
submenu.admin.adduser.index = K\u00E4ytt\u00E4j\u00E4nlis\u00E4ys
submenu.admin.adduser.login = Kirjaudu sis\u00E4\u00E4n
submenu.admin.adduser.start = Tervetuloa
submenu.admin.adduser.update = P\u00E4ivit\u00E4 profiilikuva
......@@ -917,6 +919,8 @@ submenu.foodmanager.listFoodwaves = Aktiiviset ruokatilaukset
submenu.foodwave.list = Ruokatilaukset
submenu.frontpage = Etusivu
submenu.index = Etusivu
submenu.info.incoming = Incomingview
submenu.info.index = Infon\u00E4kym\u00E4
submenu.license.manageCodes = Hallinnoi lisenssej\u00E4
submenu.license.viewCodes = N\u00E4yt\u00E4 koodit
submenu.map.create = Uusi kartta
......@@ -978,6 +982,7 @@ submenu.voting.submitEntry = L\u00E4het\u00E4 entry
subnavi.billing = Laskutus
subnavi.cards = Kortit
subnavi.info = Info
subnavi.products = Tuotteet
subnavi.readers = Lukijat
subnavi.roles = Roolit
......@@ -1010,6 +1015,7 @@ topnavi.event = Tapahtuma
topnavi.foodwave = Ruokatilaus
topnavi.frontpage = Etusivu
topnavi.game = Pelikoodit
topnavi.infoviews = Infon\u00E4kym\u00E4t
topnavi.license = Lisenssikoodit
topnavi.log = Logi
topnavi.login = Kirjaudu sis\u00E4\u00E4n
......@@ -1139,6 +1145,7 @@ tournaments.tournament_type = Turnauksen tyy
user.accountBalance = Tilin saldo
user.accountEventHeader = Tilitapahtumat
user.accountevents = Tilitapahtumat
user.addToEvent = Liit\u00E4 k\u00E4ytt\u00E4j\u00E4 tapahtumaan
user.address = Osoite
user.age = Ik\u00E4
user.bank = Pankki
......@@ -1148,6 +1155,7 @@ user.cardPower = K\u00E4ytt\u00E4j\u00E4tyyppi
user.changePassword = Vaihda salasana
user.changepassword.forUser = K\u00E4ytt\u00E4j\u00E4lle
user.changepassword.title = Vaihda salasana
user.confirmUserToEventAdding = Oletko varma ett\u00E4 haluat liitt\u00E4\u00E4 t\u00E4m\u00E4n k\u00E4ytt\u00E4j\u00E4n t\u00E4h\u00E4n tapahtumaan?
user.create = Luo k\u00E4ytt\u00E4j\u00E4
user.createdmessage = K\u00E4ytt\u00E4j\u00E4tunnus on luotu onnistuneesti. Voit nyt kirjautua sis\u00E4\u00E4n.
user.cropImage = Rajaa
......
......@@ -60,13 +60,15 @@ public class FileDownloadServlet extends GenericImageServlet {
private static final Logger logger = LoggerFactory.getLogger(FileDownloadServlet.class);
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
private static final Pattern URLPATTERN = Pattern.compile("([^./]+)");
/**
* Usage MoyaWeb/dydata/format/ possible formats logo userimage/<eventuserid>.jpg cardtemplate/<cardtemplateid>.png usercard/
* Usage MoyaWeb/dydata/format/ possible formats logo
* userimage/<eventuserid>.jpg cardtemplate/<cardtemplateid>.png usercard/
*/
@Override
protected ImageMover getImagedata() {
......@@ -132,7 +134,7 @@ public class FileDownloadServlet extends GenericImageServlet {
{
int userid = Integer.parseInt(urlparts.get(1));
EventUser usr = userbean.findByUserId(userid);
EventUser usr = userbean.findByUserId(userid, false);
logger.info("Trying to print usercard for user {}", usr);
if (usr != null) {
......
......@@ -265,7 +265,7 @@ public class PlaceMap extends HttpServlet {
color = RESERVED_COLOR;
// logger.debug("Setting place Reserved {}", p);
} else if (p.getProduct().getColor() != null && !p.getProduct().getColor().isEmpty()) {
} else if (p.getProduct() != null && p.getProduct() != null && p.getProduct().getColor() != null && !p.getProduct().getColor().isEmpty()) {
try {
color = Color.decode(p.getProduct().getColor());
......@@ -273,7 +273,8 @@ public class PlaceMap extends HttpServlet {
logger.error("Cannot convert string {} to color.", p.getProduct().getColor());
}
} else {
logger.debug("Nothing special for this place. Color should be default.");
// too much debugging -TKjne
// logger.debug("Nothing special for this place. Color should be default.");
}
......
......@@ -138,7 +138,7 @@ public class PlaceView extends GenericCDIView {
public String reserveForUser() {
try {
EventUser user = userbean.getEventUser(userlist.getRowData());
EventUser user = userbean.getEventUser(userlist.getRowData(), true);
if (placebean.reservePlace(place, user)) {
PlaceGroup newgroup = placebean.buySelectedPlaces(user);
for (Place p : newgroup.getPlaces()) {
......
......@@ -63,7 +63,8 @@ public class MenuView {
public List<PageContent> getPagecontent(String pagekey)
{
String key = new StringBuilder(layoutview.getPagepath()).append(":").append(pagekey).toString();
logger.debug("Getting pagecontent for key {}. Matches: {}", key, contents.containsKey(key));
// Removed by tkfftk, enought is enought
// logger.debug("Getting pagecontent for key {}. Matches: {}", key, contents.containsKey(key));
if (!contents.containsKey(key)) {
contents.put(key, pagebean.findContentsForUser(key, sessionstore.getLocale()));
......
......@@ -9,6 +9,7 @@ import java.util.Map;
import javax.ejb.EJB;
import javax.enterprise.context.ConversationScoped;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.ListDataModel;
import javax.inject.Inject;
import javax.inject.Named;
......
......@@ -19,7 +19,7 @@ public class UserCardWrapper implements Serializable {
private transient final ListDataModel<PrintedCard> printedCards;
public UserCardWrapper(User u, UserBeanLocal userbean) {
user = userbean.getEventUser(u);
user = userbean.getEventUser(u, false);
List<PrintedCard> cards = null;
if (user != null) {
cards = user.getPrintedCards();
......
package fi.codecrew.moya.web.cdiview.user;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Named;
import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.beans.UserBeanLocal;
import fi.codecrew.moya.enums.apps.EventPermission;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.web.cdiview.GenericCDIView;
@Named
@ConversationScoped
public class CreditTransferView extends GenericCDIView {
private static final long serialVersionUID = -4254396884077758765L;
private List<EventUserWrapper> users;
@EJB
private UserBeanLocal userbean;
@EJB
private EventBeanLocal eventbean;
private List<LanEvent> events;
private LanEvent sourceEvent;
private BigDecimal totalCredits;
private BigDecimal totalTransferred;
public void init(List<EventUser> users) {
ArrayList<EventUserWrapper> wrap = new ArrayList<EventUserWrapper>();
for (EventUser u : users) {
wrap.add(new EventUserWrapper(u));
}
this.users = wrap;
events = eventbean.getCurrentEvent().getOrganiser().getEvents();
}
public String selectEvent() {
BigDecimal total = BigDecimal.ZERO;
if (sourceEvent != null && !eventbean.getCurrentEvent().equals(sourceEvent))
{
for (EventUserWrapper u : users) {
u.setSourceEventuser(userbean.getOtherEventsEventuser(u.getUser().getUser(), sourceEvent));
if (u.getSourceEventuser() != null) {
u.setCredits(u.getSourceEventuser().getAccountBalance());
total = total.add(u.getCredits());
} else {
u.setCredits(BigDecimal.ZERO);
}
}
}
this.totalCredits = total;
return null;
}
public String commitTransfer() {
List<User> transfer = new ArrayList<User>();
for (EventUserWrapper u : users) {
transfer.add(u.getUser().getUser());
}
totalTransferred = userbean.transferAccountSaldoFromPreviousEvent(transfer, sourceEvent);
users = null;
return null;
}
public boolean isTransferPermissions() {
return super.hasPermission(EventPermission.MANAGE_EVENT);
}
public List<LanEvent> getEvents() {
return events;
}
public void setEvents(List<LanEvent> events) {
this.events = events;
}
public LanEvent getSourceEvent() {
return sourceEvent;
}
public void setSourceEvent(LanEvent sourceEvent) {
this.sourceEvent = sourceEvent;
}
public List<EventUserWrapper> getUsers() {
return users;
}
public void setUsers(List<EventUserWrapper> users) {
this.users = users;
}
public BigDecimal getTotalCredits() {
return totalCredits;
}
public void setTotalCredits(BigDecimal totalCredits) {
this.totalCredits = totalCredits;
}
public BigDecimal getTotalTransferred() {
return totalTransferred;
}
public void setTotalTransferred(BigDecimal totalTransferred) {
this.totalTransferred = totalTransferred;
}
public static class EventUserWrapper {
private final EventUser user;
private BigDecimal credits = BigDecimal.ZERO;
private EventUser sourceEventuser;
private EventUserWrapper(EventUser u) {
super();
this.user = u;
}
public EventUser getUser() {
return user;
}
public BigDecimal getCredits() {
return credits;
}
public void setCredits(BigDecimal credits) {
this.credits = credits;
}
public EventUser getSourceEventuser() {
return sourceEventuser;
}
public void setSourceEventuser(EventUser sourceEventuser) {
this.sourceEventuser = sourceEventuser;
}
}
}
package fi.codecrew.moya.web.cdiview.user;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import javax.ejb.EJB;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Named;
import org.primefaces.model.UploadedFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.beans.UserBeanLocal;
import fi.codecrew.moya.enums.apps.UserPermission;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.web.cdiview.GenericCDIView;
@Named
......@@ -10,23 +23,25 @@ import fi.codecrew.moya.web.cdiview.GenericCDIView;
public class ImportView extends GenericCDIView {
private static final long serialVersionUID = -6212627607244029512L;
//
// private static final long serialVersionUID = -6212627607244029512L;
//
// private String content;
//
// private static final Logger logger =
// LoggerFactory.getLogger(ImportView.class);
//
// @EJB
// private UserBeanLocal userbean;
@EJB
private UserBeanLocal userbean;
// @EJB
// private EventBeanLocal eventbean;
// @EJB
// private ProductBeanLocal prodbean;
//
// private UploadedFile file;
private UploadedFile file;
private ArrayList<ImportWrapper> users;
private Charset UTF8 = Charset.forName("UTF8");
private static final Logger logger = LoggerFactory.getLogger(ImportView.class);
//
// private ArrayList<ImportWrapper> wrapper;
//
......@@ -36,156 +51,77 @@ public class ImportView extends GenericCDIView {
//
// private List<CardTemplate> templates;
//
// public void initImport() {
// if (requirePermissions(UserPermission.MODIFY))
// {
// templates = templatebean.findAll();
// super.beginConversation();
// }
//
// }
//
// public String parse() throws IOException
// {
//
// setWrapper(new ArrayList<ImportWrapper>());
// logger.warn("Got file {} from upload", file);
//
// LanEvent event = eventbean.getCurrentEvent();
//
// if (file == null)
// {
// return null;
// }
//
// BufferedReader str = new BufferedReader(new
// InputStreamReader(file.getInputstream(), Charset.forName("ISO-8859-1")));
//
// for (String line = ""; line != null; line = str.readLine())
// {
//
// if (line == null || line.isEmpty() || line.matches("^id\\t"))
// {
// logger.info("skipping line {}", line);
// continue;
// }
// // logger.warn("Parsing line {}", line);
// User usr = new User();
//
// String[] limatch = line.split("\\|");
// if (limatch.length != 19)
// {
// logger.warn("SPlictcount != 19: {}", limatch.length);
// }
//
// for (int i = 0; limatch.length > i; ++i)
// {
// String field = limatch[i];
// // logger.info("Matched loop {}, val {}", i, field);
//
// switch (i)
// {
// case 5:
// usr.setEmail(field);
// break;
// case 9:
// usr.setPassword(field);
// break;
// case 10:
// String[] spl = field.split(" ", 2);
// if (spl.length != 2) {
// usr.setFirstnames(field);
// } else {
// usr.setFirstnames(spl[0]);
// usr.setLastname(spl[1]);
// }
//
// break;
//
// case 11:
// if (field != null && !field.isEmpty() && !field.equals("NULL"))
// {
// PrintedCard card = new PrintedCard(usr, template, Calendar.getInstance(),
// true);
// card.setRfidUid(field);
// usr.setPrintedCards(new ArrayList<PrintedCard>());
// usr.getPrintedCards().add(card);
// }
// break;
// case 12:
// usr.setPhone(field);
// break;
// case 13:
// usr.setNotes(new ArrayList<UserNote>());
// UserNote note = new UserNote();
// note.setContent(field);
// note.setEvent(event);
// note.setNotetype(UserNoteType.BANKACCOUNT);
// note.setUser(usr);
// usr.getNotes().add(note);
//
// break;
// case 14:
// usr.setNick(field);
// usr.setLogin(field);
// break;
// case 17:
// UserNote note2 = new UserNote();
// note2.setContent(field);
// note2.setEvent(event);
// note2.setNotetype(UserNoteType.ORGNOTE);
// note2.setUser(usr);
// usr.getNotes().add(note2);
// break;
//
// case 18:
// if (field == null || field.isEmpty() || field.equals("NULL")) {
// break;
// }
// if (usr.getAccountEvents() == null) {
// usr.setAccountEvents(new ArrayList<AccountEvent>());
// }
//
// try {
// AccountEvent ac = new AccountEvent(usr, prodbean.findCreditProduct(), new
// BigDecimal(field), BigDecimal.ONE, Calendar.getInstance());
// usr.getAccountEvents().add(ac);
// } catch (Throwable t) {
// logger.warn("Error parsing count: {}", t);
// }
//
// break;
// default:
// break;
// }
// if (i > 18)
// {
// logger.warn("cols not 18, {}", i);
// break;
// }
//
// }
//
// ImportWrapper wrap = new ImportWrapper(usr);
// getWrapper().add(wrap);
//
// SearchResult<User> srch = null;
// if (usr.getNick() != null && !usr.getNick().isEmpty())
// {
// srch = userbean.getUsers(0, 0, null, usr.getNick());
// wrap.add(srch.getResults());
// }
// if (usr.getEmail() != null && !usr.getEmail().isEmpty())
// {
// srch = userbean.getUsers(0, 0, null, usr.getEmail());
// wrap.add(srch.getResults());
// }
//
// } // end for split lines
// return "/user/commitImport";
//
// }
//
public void initImport() {
if (requirePermissions(UserPermission.MODIFY_ACCOUNTEVENTS)) {
super.beginConversation();
}
}
public String parse()
{
ArrayList<ImportWrapper> ret = new ArrayList<ImportWrapper>();
byte[] bytes = file.getContents();
if (bytes == null && file.getSize() > 0)
{
bytes = new byte[(int) file.getSize()];
try {
file.getInputstream().read(bytes);
} catch (IOException e) {
super.addFaceMessage("import.erroruploading");
return null;
}
}
String content = new String(bytes, UTF8);
String[] splittedIds = content.split(";");
for (String idstr : splittedIds) {
int id = 0;
if (idstr != null && !idstr.isEmpty() && (id = Integer.parseInt(idstr)) > 0)
{
User user = userbean.getUser(id);
if (user != null)
{
ret.add(new ImportWrapper(user, userbean.getEventUser(user, false)));
}
}
}
users = ret;
return "commitImport";
}
public String commitImport() {
for (ImportWrapper u : users) {
userbean.getEventUser(u.getUser(), true);
}
return "/useradmin/list?faces-redirect=true";
}
public static class ImportWrapper
{
private final EventUser eventuser;
private final User user;
public ImportWrapper(User user, EventUser eventUser) {
this.user = user;
this.eventuser = eventUser;
}
public EventUser getEventuser() {
return eventuser;
}
public User getUser() {
return user;
}
}
// public String commitImport()
// {
// for (ImportWrapper w : wrapper)
......@@ -239,44 +175,21 @@ public class ImportView extends GenericCDIView {
// return null;
// }
//
// public String getContent() {
// return content;
// }
//
// public void setContent(String content) {
// this.content = content;
// }
//
// public UploadedFile getFile() {
// return file;
// }
//
// public void setFile(UploadedFile file) {
// this.file = file;
// }
//
// public ArrayList<ImportWrapper> getWrapper() {
// return wrapper;
// }
//
// public void setWrapper(ArrayList<ImportWrapper> wrapper) {
// this.wrapper = wrapper;
// }
//
// public List<CardTemplate> getTemplates() {
// return templates;
// }
//
// public void setTemplates(List<CardTemplate> templates) {
// this.templates = templates;
// }
//
// public CardTemplate getTemplate() {
// return template;
// }
//
// public void setTemplate(CardTemplate template) {
// this.template = template;
// }
public ArrayList<ImportWrapper> getUsers() {
return users;
}
public void setUsers(ArrayList<ImportWrapper> users) {
this.users = users;
}
public UploadedFile getFile() {
return file;
}
public void setFile(UploadedFile file) {
this.file = file;
}
}
......@@ -70,7 +70,7 @@ public class RoleView extends GenericCDIView {
public void addUser()
{
EventUser eu = userbean.getEventUser(addableUser);
EventUser eu = userbean.getEventUser(addableUser, false);
role = rolebean.addRole(eu, role);
addableUser = null;
}
......
......@@ -17,6 +17,7 @@ import org.slf4j.LoggerFactory;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.GroupMembership;
import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.web.cdiview.GenericCDIView;
@Named
......@@ -33,6 +34,8 @@ public class UserCartView extends GenericCDIView {
@Inject
private UserView userview;
@Inject
private CreditTransferView credTransfer;
@Inject
private UserOverviewView userOverviewView;
......@@ -41,6 +44,23 @@ public class UserCartView extends GenericCDIView {
private SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
public StreamedContent getUserExport()
{
StringBuilder sb = new StringBuilder();
DefaultStreamedContent ret = null;
if (usercart.size() > 0) {
LanEvent event = usercart.get(0).getEvent();
for (EventUser uc : usercart) {
sb.append(uc.getUser().getId()).append(";");
}
ret = new DefaultStreamedContent(new ByteArrayInputStream(sb.toString().getBytes(UTF8)));
ret.setContentType("text/csv");
ret.setName(event.getName() + "userexport.dat");
}
return ret;
}
public StreamedContent getDownloadCsv() {
StringBuilder sb = new StringBuilder();
......@@ -56,7 +76,7 @@ public class UserCartView extends GenericCDIView {
sb.append("Zip").append(CSV_SEPARATOR);
sb.append("City").append(CSV_SEPARATOR);
sb.append("Places").append(CSV_SEPARATOR);
sb.append("\n");
for (EventUser uc : usercart)
{
......@@ -95,6 +115,11 @@ public class UserCartView extends GenericCDIView {
return null;
}
public String transferCredits() {
credTransfer.init(usercart);
return "/useradmin/transferCredits";
}
public String prev() {
--current;
updateCurrent();
......@@ -199,4 +224,12 @@ public class UserCartView extends GenericCDIView {
this.current = current;
}
public CreditTransferView getCredTransfer() {
return credTransfer;
}
public void setCredTransfer(CreditTransferView credTransfer) {
this.credTransfer = credTransfer;
}
}
package fi.codecrew.moya.web.cdiview.user;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
......@@ -10,6 +11,8 @@ import javax.inject.Named;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.beans.UserBeanLocal;
import fi.codecrew.moya.enums.apps.UserPermission;
......@@ -18,11 +21,45 @@ import fi.codecrew.moya.model.User;
import fi.codecrew.moya.util.UserSearchQuery;
import fi.codecrew.moya.utilities.SearchQuery.QuerySortOrder;
import fi.codecrew.moya.utilities.SearchResult;
import fi.codecrew.moya.utilities.jpa.ModelInterface;
import fi.codecrew.moya.web.cdiview.PaginationView;
import fi.codecrew.moya.web.cdiview.user.UserSearchView.UserWrapper;
@Named
@ConversationScoped
public class UserSearchView extends PaginationView<User> {
public class UserSearchView extends PaginationView<UserWrapper> {
public static class UserWrapper implements ModelInterface {
private static final long serialVersionUID = 8881170508994116964L;
private final User user;
private final EventUser eventuser;
public UserWrapper(User u, EventUser eventUser) {
this.user = u;
this.eventuser = eventUser;
}
public User getUser() {
return user;
}
public EventUser getEventuser() {
return eventuser;
}
@Override
public Integer getId() {
return user.getId();
}
@Override
public void setId(Integer id) {
user.setId(id);
}
}
/**
*
......@@ -38,6 +75,9 @@ public class UserSearchView extends PaginationView<User> {
private UserSearchQuery usersearch = new UserSearchQuery();
private LazyDataModel<EventUser> eventuserModel;
private LazyDataModel<UserWrapper> userModel;
private static final Logger logger = LoggerFactory.getLogger(UserSearchView.class);
public void addToCart()
{
......@@ -56,6 +96,7 @@ public class UserSearchView extends PaginationView<User> {
public void initView() {
if (requirePermissions(permbean.hasPermission(UserPermission.VIEW_ALL))) {
super.setSort("id");
eventuserModel = new LazyDataModel<EventUser>() {
private static final long serialVersionUID = 1L;
......@@ -65,15 +106,18 @@ public class UserSearchView extends PaginationView<User> {
SortOrder sortOrder, Map<String, String> filters) {
UserSearchQuery sq = getSearchQuery();
sq.setPagesize(pageSize);
if (pageSize > 0)
{
if (pageSize > 0) {
sq.setPage(first / pageSize);
}
sq.setSort(sortField);
sq.setSortDirection(SortOrder.ASCENDING.equals(sortOrder) ? QuerySortOrder.ASCENDING : (SortOrder.DESCENDING.equals(sortOrder) ? QuerySortOrder.DESCENDING : QuerySortOrder.UNSORTED));
SearchResult<EventUser> sr = userbean.getThisEventsUsers(sq);
logger.info("sortfield {}, order {}, querysort: {}", sortField, sortOrder, sq.getSortDirection());
this.setRowCount(new Long(sr.getResultcount()).intValue());
this.setWrappedData(sr.getResults());
setResultcount(sr.getResultcount());
setEventUserResults(sr.getResults());
......@@ -91,21 +135,67 @@ public class UserSearchView extends PaginationView<User> {
};
if (usersearch.isOnlyThisEvent() || usersearch.getSearch() == null || usersearch.getSearch().isEmpty())
{
usersearch.setOnlyThisEvent(true);
SearchResult<EventUser> eventusers = userbean.getThisEventsUsers(getSearchQuery());
this.setResultcount(eventusers.getResultcount());
this.setEventUserResults(eventusers.getResults());
}
else {
super.setResult(userbean.getUsers(getSearchQuery()));
}
userModel = new LazyDataModel<UserWrapper>() {
private static final long serialVersionUID = 1L;
@Override
public List<UserWrapper> load(int first, int pageSize, String sortField,
SortOrder sortOrder, Map<String, String> filters) {
UserSearchQuery sq = getSearchQuery();
sq.setPagesize(pageSize);
if (pageSize > 0) {
sq.setPage(first / pageSize);
}
if (sortField == null || sortField.isEmpty()) {
sortField = "id";
}
sq.setSort(sortField);
sq.setSortDirection(SortOrder.ASCENDING.equals(sortOrder) ? QuerySortOrder.ASCENDING : (SortOrder.DESCENDING.equals(sortOrder) ? QuerySortOrder.DESCENDING : QuerySortOrder.UNSORTED));
SearchResult<User> sr = userbean.getUsers(sq);
this.setRowCount(new Long(sr.getResultcount()).intValue());
setResultcount(sr.getResultcount());
List<UserWrapper> wrappers = getUserWrappers(sr.getResults());
setResults(wrappers);
this.setWrappedData(wrappers);
return wrappers;
}
@Override
public void setRowIndex(int rowIndex) {
if (getPageSize() == 0) {
rowIndex = -1;
}
super.setRowIndex(rowIndex);
}
};
super.beginConversation();
}
}
@Override
public String newSearch() {
String ret = super.newSearch();
return ret;
}
private List<UserWrapper> getUserWrappers(List<User> users)
{
ArrayList<UserWrapper> res = new ArrayList<UserWrapper>();
for (User u : users) {
res.add(new UserWrapper(u, userbean.getEventUser(u, false)));
}
return res;
}
@Override
public UserSearchQuery getSearchQuery()
{
return usersearch;
......@@ -127,4 +217,12 @@ public class UserSearchView extends PaginationView<User> {
this.eventuserModel = eventuserModel;
}
public LazyDataModel<UserWrapper> getUserModel() {
return userModel;
}
public void setUserModel(LazyDataModel<UserWrapper> userModel) {
this.userModel = userModel;
}
}
......@@ -39,7 +39,6 @@ import fi.codecrew.moya.model.Role;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.model.UserImage;
import fi.codecrew.moya.util.MassPrintResult;
import fi.codecrew.moya.utilities.jsf.MessageHelper;
import fi.codecrew.moya.web.annotations.LoggedIn;
import fi.codecrew.moya.web.annotations.SelectedUser;
import fi.codecrew.moya.web.cdiview.GenericCDIView;
......@@ -142,7 +141,7 @@ public class UserView extends GenericCDIView {
ByteArrayInputStream data = new ByteArrayInputStream(captureEvent.getData());
UserImage img = userbean.uploadImage(user, "image/png", data, "userimage.png", "Uploaded image");
user = userbean.getEventUser(img.getUser());
user = userbean.getEventUser(img.getUser(), false);
// super.navihandler.forward("/admin/adduser/capturesuccess");
if (getCaptureForwardUrl() != null && !getCaptureForwardUrl().isEmpty())
super.navihandler.forward(getCaptureForwardUrl());
......@@ -154,7 +153,7 @@ public class UserView extends GenericCDIView {
public EventUser getSelectedUser() {
if (user == null) {
if (userid != null && permbean.hasPermission(UserPermission.VIEW_ALL)) {
user = userbean.findByUserId(userid);
user = userbean.findByUserId(userid, true);
} else {
user = getCurrentUser();
}
......@@ -200,7 +199,7 @@ public class UserView extends GenericCDIView {
croppedImage.getLeft(), croppedImage.getTop(),
croppedImage.getWidth(), croppedImage.getHeight());
user = userbean.getEventUser(newImage.getUser());
user = userbean.getEventUser(newImage.getUser(), false);
} catch (IOException e) {
logger.info("Error converting image", e);
super.addFaceMessage("user.errorConvertingImage");
......@@ -247,7 +246,7 @@ public class UserView extends GenericCDIView {
InputStream istr = getImage().getInputstream();
UserImage userimage = userbean.uploadImage(user, getImage().getContentType(), getImage().getInputstream(), getImage().getFileName(), "");
user = userbean.getEventUser(userimage.getUser());
user = userbean.getEventUser(userimage.getUser(), false);
super.addFaceMessage("user.imageUploaded");
}
printedCard = null;
......@@ -277,7 +276,8 @@ public class UserView extends GenericCDIView {
canSave = getCurrentUser().equals(user) || permbean.hasPermission(UserPermission.MODIFY);
this.beginConversation();
logger.debug("Accountevents for user {}", user.getAccountEvents().size());
if (user.getAccountEvents() != null)
logger.debug("Accountevents for user {}", user.getAccountEvents().size());
}
......@@ -351,23 +351,22 @@ public class UserView extends GenericCDIView {
public String attachCodeToCard() {
return attachCodeToCard(readerView.getReaderEvent());
}
public String attachCodeToCard(ReaderEvent event ) {
if(event == null)
public String attachCodeToCard(ReaderEvent event) {
if (event == null)
return null;
// already attached
if (event.getPrintedCard() != null) {
super.addFaceMessage("usercard.alreadyassociated");
return null;
}
// still there, we can get real card and update it's barcodes
PrintedCard card = cardBean.checkPrintedCard(user);
readerbean.assocCodeToCard(event , card);
readerbean.assocCodeToCard(event, card);
return null;
}
......
package fi.codecrew.moya.web.converter;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.utilities.jsf.GenericIntegerEntityConverter;
@Named
@RequestScoped
public class LanEventConverter extends GenericIntegerEntityConverter<LanEvent> {
@EJB
private EventBeanLocal eventbean;
@Override
protected LanEvent find(Integer id) {
return eventbean.getEventById(id);
}
}
......@@ -187,6 +187,9 @@ public class IncomingView extends GenericCDIView {
ReaderEvent event = readerView.getReaderEvent();
if(event == null)
return null;
EventUser user = event.getUser();
memberlist = null;
......
......@@ -89,7 +89,7 @@ public class LayoutView implements Serializable {
return null;
while (selectedTop.getParent() != null) {
logger.info("Traversing to top {}, key {}", selectedTop, selectedTop.getKey());
logger.debug("Traversing to top {}, key {}", selectedTop, selectedTop.getKey());
selectedSet.add(selectedTop);
selectedTop = selectedTop.getParent();
}
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!