You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2015/10/01 09:22:50 UTC

svn commit: r1706188 - in /openmeetings: branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/ trunk/singlewebapp/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/ trunk/singlewebapp/openmeetings-web/src/main/java/org/apache...

Author: solomax
Date: Thu Oct  1 07:22:50 2015
New Revision: 1706188

URL: http://svn.apache.org/viewvc?rev=1706188&view=rev
Log:
[OPENMEETINGS-846] group invitations are added

Modified:
    openmeetings/branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/InvitationDialog.html
    openmeetings/branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/InvitationDialog.java
    openmeetings/trunk/singlewebapp/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/Invitation.java
    openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.html
    openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.java
    openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/util/UserChoiceProvider.java
    openmeetings/trunk/singlewebapp/openmeetings-web/src/main/webapp/css/theme.css

Modified: openmeetings/branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/InvitationDialog.html
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/InvitationDialog.html?rev=1706188&r1=1706187&r2=1706188&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/InvitationDialog.html (original)
+++ openmeetings/branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/InvitationDialog.html Thu Oct  1 07:22:50 2015
@@ -21,12 +21,16 @@
 <html xmlns:wicket="http://wicket.apache.org">
 <wicket:panel>
 	<form wicket:id="form">
-		<table>
+		<table wicket:id="inviteeType">
 			<tr>
-				<td><label wicket:for="recipients"><wicket:message key="216" /></label></td>
+				<td><input type="radio" wicket:id="user"/><label wicket:for="recipients"><wicket:message key="216" /></label></td>
 				<td><input type="hidden" wicket:id="recipients" class="input invitees" style="max-height: 80px"/></td>
 			</tr>
 			<tr>
+				<td><input type="radio" wicket:id="group"/><label wicket:for="groups"><wicket:message key="126" /></label></td>
+				<td><input type="hidden" wicket:id="groups" class="input invitees" style="max-height: 80px"/></td>
+			</tr>
+			<tr>
 				<td><label wicket:for="subject"><wicket:message key="215" /></label></td>
 				<td><input type="text" wicket:id="subject" class="input"/></td>
 			</tr>

Modified: openmeetings/branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/InvitationDialog.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/InvitationDialog.java?rev=1706188&r1=1706187&r2=1706188&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/InvitationDialog.java (original)
+++ openmeetings/branches/3.0.x/src/web/java/org/apache/openmeetings/web/room/InvitationDialog.java Thu Oct  1 07:22:50 2015
@@ -36,20 +36,26 @@ import org.apache.openmeetings.db.dao.ba
 import org.apache.openmeetings.db.dao.calendar.IInvitationManager.MessageType;
 import org.apache.openmeetings.db.dao.room.InvitationDao;
 import org.apache.openmeetings.db.dao.room.RoomDao;
+import org.apache.openmeetings.db.dao.user.OrganisationDao;
+import org.apache.openmeetings.db.dao.user.OrganisationUserDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.room.Invitation;
 import org.apache.openmeetings.db.entity.room.Invitation.Valid;
+import org.apache.openmeetings.db.entity.user.Organisation;
+import org.apache.openmeetings.db.entity.user.Organisation_Users;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.entity.user.User.Type;
 import org.apache.openmeetings.util.crypt.MD5;
 import org.apache.openmeetings.util.crypt.ManageCryptStyle;
 import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.WebSession;
 import org.apache.openmeetings.web.common.LanguageDropDown;
 import org.apache.openmeetings.web.util.UserMultiChoice;
-import org.apache.wicket.ajax.AjaxEventBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
 import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
+import org.apache.wicket.markup.html.form.ChoiceRenderer;
 import org.apache.wicket.markup.html.form.DropDownChoice;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.PasswordTextField;
@@ -65,6 +71,7 @@ import org.apache.wicket.model.util.Coll
 import org.apache.wicket.util.string.Strings;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
+import org.wicketstuff.select2.Select2MultiChoice;
 
 import com.googlecode.wicket.jquery.core.Options;
 import com.googlecode.wicket.jquery.ui.widget.dialog.AbstractFormDialog;
@@ -85,9 +92,18 @@ public class InvitationDialog extends Ab
 	private final IModel<String> subject = Model.of((String)null);
 	private final IModel<String> message = Model.of((String)null);
 	private final IModel<String> tzId = Model.of((String)null);
+	private final IModel<InviteeType> inviteeType = Model.of(InviteeType.user);
 	private Long lang;
-	private final IModel<Collection<User>> modelTo = new CollectionModel<User>(new ArrayList<User>());
 	private final TextField<String> url = new TextField<String>("url", Model.of((String)null));
+	enum InviteeType {
+		user
+		, group
+	}
+	private final UserMultiChoice recipients = new UserMultiChoice("recipients", new CollectionModel<User>(new ArrayList<User>()));
+	private final Select2MultiChoice<Organisation> groups = new Select2MultiChoice<Organisation>("groups"
+			, new CollectionModel<Organisation>(new ArrayList<Organisation>())
+			, new ArrayList<Organisation>()
+			, new ChoiceRenderer<Organisation>("name", "organisation_id"));
 
 	public InvitationDialog(String id, long roomId) {
 		super(id, Application.getString(214), new CompoundPropertyModel<Invitation>(new Invitation()));
@@ -119,10 +135,22 @@ public class InvitationDialog extends Ab
 		}
 		subject.setObject(null);
 		message.setObject(null);
-		modelTo.setObject(new ArrayList<User>());
+		recipients.setModelObject(new ArrayList<User>());
+		recipients.setEnabled(true);
+		if (WebSession.getRights().contains(User.Right.Admin)) {
+			groups.setChoices(getBean(OrganisationDao.class).get(0, Integer.MAX_VALUE));
+		} else {
+			groups.setChoices(new ArrayList<Organisation>());
+			for (Organisation_Users ou : u.getOrganisation_users()) {
+				groups.getChoices().add(ou.getOrganisation());
+			}
+		}
+		groups.setModelObject(new ArrayList<Organisation>());
+		groups.setEnabled(false);
 		tzId.setObject(u.getTimeZoneId());
 		lang = u.getLanguage_id();
 		url.setModelObject(null);
+		inviteeType.setObject(InviteeType.user);
 		form.setModelObject(i);
 		send.setEnabled(false, target);
 		generate.setEnabled(false, target);
@@ -163,27 +191,39 @@ public class InvitationDialog extends Ab
 		if (button.equals(cancel)) {
 			super.onClick(target, button);
 		} else if (button.equals(generate)) {
-			Invitation i = create(modelTo.getObject().iterator().next());
+			Invitation i = create(recipients.getModelObject().iterator().next());
 			form.setModelObject(i);
 			url.setModelObject(getInvitationLink(getBean(ConfigurationDao.class).getBaseUrl(), i));
 			target.add(url);
 		} else if (button.equals(send)) {
 			if (Strings.isEmpty(url.getModelObject())) {
-				for (User u : modelTo.getObject()) {
-					Invitation i = create(u);
-					try {
-						getBean(InvitationManager.class).sendInvitionLink(i, MessageType.Create, subject.getObject(), message.getObject(), false);
-					} catch (Exception e) {
-						log.error("error while sending invitation ", e);
+				if (inviteeType.getObject() == InviteeType.user) {
+					for (User u : recipients.getModelObject()) {
+						Invitation i = create(u);
+						try {
+							getBean(InvitationManager.class).sendInvitionLink(i, MessageType.Create, subject.getObject(), message.getObject(), false);
+						} catch (Exception e) {
+							log.error("error while sending invitation by User ", e);
+						}
+					}
+				} else {
+					for (Organisation g : groups.getModelObject()) {
+						for (Organisation_Users ou : getBean(OrganisationUserDao.class).get(g.getOrganisation_id(), 0, Integer.MAX_VALUE)) {
+							Invitation i = create(ou.getUser());
+							try {
+								getBean(InvitationManager.class).sendInvitionLink(i, MessageType.Create, subject.getObject(), message.getObject(), false);
+							} catch (Exception e) {
+								log.error("error while sending invitation by Group ", e);
+							}
+						}
 					}
 				}
 			} else {
-				//FIXME To might be changed and it would'n be reflected, might lead to misunderstandings
 				Invitation i = form.getModelObject();
 				try {
 					getBean(InvitationManager.class).sendInvitionLink(i, MessageType.Create, subject.getObject(), message.getObject(), false);
 				} catch (Exception e) {
-					log.error("error while sending invitation ", e);
+					log.error("error while sending invitation by URL ", e);
 				}
 			}
 			super.onClick(target, button);
@@ -225,20 +265,41 @@ public class InvitationDialog extends Ab
 		
 		public InvitationForm(String id, IModel<Invitation> model) {
 			super(id, model);
-			add(new UserMultiChoice("recipients", modelTo).setLabel(Model.of(Application.getString(216))).setRequired(true)
-					.add(new AjaxFormComponentUpdatingBehavior("change") {
-						private static final long serialVersionUID = 1L;
-		
-						@Override
-						protected void onUpdate(AjaxRequestTarget target) {
-							Collection<User> to = modelTo.getObject();
-							send.setEnabled(to.size() > 0, target);
-							generate.setEnabled(to.size() == 1, target);
-						}
-					}));
-			add(new TextField<String>("subject", subject));
-			add(new TextArea<String>("message", message));
-			add(new AjaxCheckBox("passwordProtected") {
+			RadioGroup<InviteeType> rdi = new RadioGroup<>("inviteeType", inviteeType);
+			add(rdi.add(new AjaxFormChoiceComponentUpdatingBehavior() {
+				private static final long serialVersionUID = 1L;
+
+				@Override
+				protected void onUpdate(AjaxRequestTarget target) {
+					boolean groupsEnabled = InviteeType.group == inviteeType.getObject();
+					updateButtons(target);
+					target.add(groups.setEnabled(groupsEnabled), recipients.setEnabled(!groupsEnabled));
+				}
+			}));
+			//TODO list should be updated on open
+			rdi.add(recipients.setLabel(Model.of(Application.getString(216))).setRequired(true).add(new AjaxFormComponentUpdatingBehavior("change") {
+				private static final long serialVersionUID = 1L;
+				
+				@Override
+				protected void onUpdate(AjaxRequestTarget target) {
+					url.setModelObject(null);
+					updateButtons(target);
+				}
+			}).setOutputMarkupId(true));
+			rdi.add(groups.setLabel(Model.of(Application.getString(126))).setRequired(true).add(new AjaxFormComponentUpdatingBehavior("change") {
+				private static final long serialVersionUID = 1L;
+				
+				@Override
+				protected void onUpdate(AjaxRequestTarget target) {
+					url.setModelObject(null);
+					updateButtons(target);
+				}
+			}).setOutputMarkupId(true));
+			rdi.add(new Radio<InviteeType>("user", Model.of(InviteeType.user)), new Radio<InviteeType>("group", Model.of(InviteeType.group)));
+
+			rdi.add(new TextField<String>("subject", subject));
+			rdi.add(new TextArea<String>("message", message));
+			rdi.add(new AjaxCheckBox("passwordProtected") {
 				private static final long serialVersionUID = 1L;
 
 				@Override
@@ -248,38 +309,25 @@ public class InvitationDialog extends Ab
 					target.add(passwd);
 				}
 			});
-			add(new RadioGroup<Valid>("valid").add(
-					new Radio<Valid>("one", Model.of(Valid.OneTime)).add(new AjaxEventBehavior("click") {
-						private static final long serialVersionUID = 1L;
-
-						@Override
-						protected void onEvent(AjaxRequestTarget target) {
-							target.add(from.setEnabled(false), to.setEnabled(false), timeZoneId.setEnabled(false));
-						}
-					})
-					, new Radio<Valid>("period", Model.of(Valid.Period)).add(new AjaxEventBehavior("click") {
-						private static final long serialVersionUID = 1L;
-
-						@Override
-						protected void onEvent(AjaxRequestTarget target) {
-							target.add(from.setEnabled(true), to.setEnabled(true), timeZoneId.setEnabled(true));
-						}
-					})
-					, new Radio<Valid>("endless", Model.of(Valid.Endless)).add(new AjaxEventBehavior("click") {
-						private static final long serialVersionUID = 1L;
-
-						@Override
-						protected void onEvent(AjaxRequestTarget target) {
-							target.add(from.setEnabled(false), to.setEnabled(false), timeZoneId.setEnabled(false));
-						}
-					})
-					));
-			add(passwd = new PasswordTextField("password"));
+			RadioGroup<Valid> valid = new RadioGroup<Valid>("valid");
+			valid.add(new AjaxFormChoiceComponentUpdatingBehavior() {
+				private static final long serialVersionUID = 1L;
+
+				@Override
+				protected void onUpdate(AjaxRequestTarget target) {
+					boolean dateEnabled = InvitationForm.this.getModelObject().getValid() == Valid.Period;
+					target.add(from.setEnabled(dateEnabled), to.setEnabled(dateEnabled), timeZoneId.setEnabled(dateEnabled));
+				}
+			});
+			rdi.add(valid.add(new Radio<Valid>("one", Model.of(Valid.OneTime))
+					, new Radio<Valid>("period", Model.of(Valid.Period))
+					, new Radio<Valid>("endless", Model.of(Valid.Endless))));
+			rdi.add(passwd = new PasswordTextField("password"));
 			Invitation i = getModelObject();
 			passwd.setLabel(Model.of(Application.getString(525))).setOutputMarkupId(true).setEnabled(i.isPasswordProtected());
-			add(from = new AjaxDateTimePicker("validFrom", "yyyy/MM/dd", "HH:mm:ss")); //FIXME use user locale
-			add(to = new AjaxDateTimePicker("validTo", "yyyy/MM/dd", "HH:mm:ss")); //FIXME use user locale
-			add(timeZoneId = new DropDownChoice<String>("timeZoneId", tzId, AVAILABLE_TIMEZONES));
+			rdi.add(from = new AjaxDateTimePicker("validFrom", "yyyy/MM/dd", "HH:mm:ss")); //FIXME use user locale
+			rdi.add(to = new AjaxDateTimePicker("validTo", "yyyy/MM/dd", "HH:mm:ss")); //FIXME use user locale
+			rdi.add(timeZoneId = new DropDownChoice<String>("timeZoneId", tzId, AVAILABLE_TIMEZONES));
 			from.setEnabled(i.getValid() == Valid.Period).setOutputMarkupId(true);
 			to.setEnabled(i.getValid() == Valid.Period).setOutputMarkupId(true);
 			timeZoneId.setEnabled(i.getValid() == Valid.Period).setOutputMarkupId(true)
@@ -291,11 +339,23 @@ public class InvitationDialog extends Ab
 						//no-op added to preserve selection
 					}
 				});
-			add(new LanguageDropDown("language", new PropertyModel<Long>(InvitationDialog.this, "lang")));
-			add(url.setOutputMarkupId(true));
+			rdi.add(new LanguageDropDown("language", new PropertyModel<Long>(InvitationDialog.this, "lang")));
+			rdi.add(url.setOutputMarkupId(true));
 			add(feedback);
 		}
 		
+		private void updateButtons(AjaxRequestTarget target) {
+			if (inviteeType.getObject() == InviteeType.user) {
+				Collection<User> to = recipients.getModelObject();
+				send.setEnabled(to.size() > 0, target);
+				generate.setEnabled(to.size() == 1, target);
+			} else {
+				Collection<Organisation> to = groups.getModelObject();
+				send.setEnabled(to.size() > 0, target);
+				generate.setEnabled(false, target);
+			}
+		}
+		
 		@Override
 		protected void onValidate() {
 			if (from.getConvertedInput() != null && to.getConvertedInput() != null && from.getConvertedInput().after(to.getConvertedInput())) {
@@ -309,7 +369,7 @@ public class InvitationDialog extends Ab
 		subject.detach();
 		message.detach();
 		tzId.detach();
-		modelTo.detach();
+		inviteeType.detach();
 		super.onDetach();
 	}
 }

Modified: openmeetings/trunk/singlewebapp/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/Invitation.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/Invitation.java?rev=1706188&r1=1706187&r2=1706188&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/Invitation.java (original)
+++ openmeetings/trunk/singlewebapp/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/Invitation.java Thu Oct  1 07:22:50 2015
@@ -34,6 +34,7 @@ import javax.persistence.ManyToOne;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
 import javax.persistence.Table;
+import javax.persistence.Transient;
 
 import org.apache.openjpa.persistence.jdbc.ForeignKey;
 import org.apache.openmeetings.db.entity.IDataProviderEntity;
@@ -126,8 +127,29 @@ public class Invitation implements IData
 	private Appointment appointment;
 
 	//variable used in Flash
+	@Transient
 	private boolean allowEntry = true;
 	
+	public Invitation() {}
+	
+	public Invitation(Invitation i) {
+		id = i.id;
+		invitedBy = i.invitedBy;
+		inserted = i.inserted;
+		updated = i.updated;
+		deleted = i.deleted;
+		room = i.room;
+		hash = i.hash;
+		invitee = i.invitee;
+		passwordProtected = i.passwordProtected;
+		password = i.password;
+		valid = i.valid;
+		validFrom = i.validFrom;
+		validTo = i.validTo;
+		used = i.used;
+		appointment = i.appointment;
+	}
+	
 	public Long getId() {
 		return id;
 	}

Modified: openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.html
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.html?rev=1706188&r1=1706187&r2=1706188&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.html (original)
+++ openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.html Thu Oct  1 07:22:50 2015
@@ -21,10 +21,14 @@
 <html xmlns:wicket="http://wicket.apache.org">
 <wicket:panel>
 	<form wicket:id="form">
-		<table>
+		<table wicket:id="inviteeType">
 			<tr>
-				<td><label wicket:for="recipients"><wicket:message key="216" /></label></td>
-				<td><input type="hidden" wicket:id="recipients" class="input"/></td>
+				<td><input type="radio" wicket:id="user"/><label wicket:for="recipients"><wicket:message key="216" /></label></td>
+				<td><input type="hidden" wicket:id="recipients" class="input invitees" style="max-height: 80px"/></td>
+			</tr>
+			<tr>
+				<td><input type="radio" wicket:id="group"/><label wicket:for="groups"><wicket:message key="126" /></label></td>
+				<td><input type="hidden" wicket:id="groups" class="input invitees" style="max-height: 80px"/></td>
 			</tr>
 			<tr>
 				<td><label wicket:for="subject"><wicket:message key="215" /></label></td>

Modified: openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.java?rev=1706188&r1=1706187&r2=1706188&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.java (original)
+++ openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.java Thu Oct  1 07:22:50 2015
@@ -29,25 +29,31 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
 import org.apache.openmeetings.db.dao.room.InvitationDao;
 import org.apache.openmeetings.db.dao.room.RoomDao;
+import org.apache.openmeetings.db.dao.user.GroupDao;
+import org.apache.openmeetings.db.dao.user.GroupUserDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.room.Invitation;
 import org.apache.openmeetings.db.entity.room.Invitation.MessageType;
 import org.apache.openmeetings.db.entity.room.Invitation.Valid;
+import org.apache.openmeetings.db.entity.user.Group;
+import org.apache.openmeetings.db.entity.user.GroupUser;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.entity.user.User.Type;
 import org.apache.openmeetings.service.room.InvitationManager;
 import org.apache.openmeetings.util.crypt.MD5;
 import org.apache.openmeetings.util.crypt.ManageCryptStyle;
 import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.WebSession;
 import org.apache.openmeetings.web.common.LanguageDropDown;
 import org.apache.openmeetings.web.util.UserMultiChoice;
-import org.apache.wicket.ajax.AjaxEventBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
 import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
 import org.apache.wicket.markup.html.form.DropDownChoice;
@@ -65,6 +71,9 @@ import org.apache.wicket.model.util.Coll
 import org.apache.wicket.util.string.Strings;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
+import org.wicketstuff.select2.Response;
+import org.wicketstuff.select2.Select2MultiChoice;
+import org.wicketstuff.select2.TextChoiceProvider;
 
 import com.googlecode.wicket.jquery.core.Options;
 import com.googlecode.wicket.jquery.ui.widget.dialog.AbstractFormDialog;
@@ -85,9 +94,58 @@ public class InvitationDialog extends Ab
 	private final IModel<String> subject = Model.of((String)null);
 	private final IModel<String> message = Model.of((String)null);
 	private final IModel<String> tzId = Model.of((String)null);
+	private final IModel<InviteeType> inviteeType = Model.of(InviteeType.user);
 	private Long lang;
-	private final IModel<Collection<User>> modelTo = new CollectionModel<User>(new ArrayList<User>());
 	private final TextField<String> url = new TextField<String>("url", Model.of((String)null));
+	enum InviteeType {
+		user
+		, group
+	}
+	private final UserMultiChoice recipients = new UserMultiChoice("recipients", new CollectionModel<User>(new ArrayList<User>()));
+	private final Select2MultiChoice<Group> groups = new Select2MultiChoice<Group>("groups"
+			, new CollectionModel<Group>(new ArrayList<Group>())
+			, new TextChoiceProvider<Group>() {
+				private static final long serialVersionUID = 1L;
+
+				@Override
+				public void query(String term, int page, Response<Group> response) {
+					if (WebSession.getRights().contains(User.Right.Admin)) {
+						List<Group> groups = getBean(GroupDao.class).get(0, Integer.MAX_VALUE);
+						for (Iterator<Group> i = groups.iterator(); i.hasNext();) {
+							Group g = i.next();
+							if (g.getName().toLowerCase().contains(term.toLowerCase())) {
+								response.add(g);
+							}
+						}
+					} else {
+						User u = getBean(UserDao.class).get(getUserId());
+						for (GroupUser ou : u.getGroupUsers()) {
+							if (ou.getGroup().getName().toLowerCase().contains(term.toLowerCase())) {
+								response.add(ou.getGroup());
+							}
+						}
+					}
+				}
+
+				@Override
+				public Collection<Group> toChoices(Collection<String> ids) {
+					Collection<Group> c = new ArrayList<>();
+					for (String id : ids) {
+						c.add(getBean(GroupDao.class).get(Long.valueOf(id)));
+					}
+					return c;
+				}
+
+				@Override
+				protected String getDisplayText(Group choice) {
+					return choice.getName();
+				}
+
+				@Override
+				protected Object getId(Group choice) {
+					return choice.getId();
+				}
+			});
 
 	public InvitationDialog(String id, long roomId) {
 		super(id, Application.getString(214), new CompoundPropertyModel<Invitation>(new Invitation()));
@@ -119,10 +177,14 @@ public class InvitationDialog extends Ab
 		}
 		subject.setObject(null);
 		message.setObject(null);
-		modelTo.setObject(new ArrayList<User>());
+		recipients.setModelObject(new ArrayList<User>());
+		recipients.setEnabled(true);
+		groups.setModelObject(new ArrayList<Group>());
+		groups.setEnabled(false);
 		tzId.setObject(u.getTimeZoneId());
 		lang = u.getLanguageId();
 		url.setModelObject(null);
+		inviteeType.setObject(InviteeType.user);
 		form.setModelObject(i);
 		send.setEnabled(false, target);
 		generate.setEnabled(false, target);
@@ -163,27 +225,39 @@ public class InvitationDialog extends Ab
 		if (button.equals(cancel)) {
 			super.onClick(target, button);
 		} else if (button.equals(generate)) {
-			Invitation i = create(modelTo.getObject().iterator().next());
+			Invitation i = create(recipients.getModelObject().iterator().next());
 			form.setModelObject(i);
 			url.setModelObject(getInvitationLink(getBean(ConfigurationDao.class).getBaseUrl(), i));
 			target.add(url);
 		} else if (button.equals(send)) {
 			if (Strings.isEmpty(url.getModelObject())) {
-				for (User u : modelTo.getObject()) {
-					Invitation i = create(u);
-					try {
-						getBean(InvitationManager.class).sendInvitionLink(i, MessageType.Create, subject.getObject(), message.getObject(), false);
-					} catch (Exception e) {
-						log.error("error while sending invitation ", e);
+				if (inviteeType.getObject() == InviteeType.user) {
+					for (User u : recipients.getModelObject()) {
+						Invitation i = create(u);
+						try {
+							getBean(InvitationManager.class).sendInvitionLink(i, MessageType.Create, subject.getObject(), message.getObject(), false);
+						} catch (Exception e) {
+							log.error("error while sending invitation by User ", e);
+						}
+					}
+				} else {
+					for (Group g : groups.getModelObject()) {
+						for (GroupUser ou : getBean(GroupUserDao.class).get(g.getId(), 0, Integer.MAX_VALUE)) {
+							Invitation i = create(ou.getUser());
+							try {
+								getBean(InvitationManager.class).sendInvitionLink(i, MessageType.Create, subject.getObject(), message.getObject(), false);
+							} catch (Exception e) {
+								log.error("error while sending invitation by Group ", e);
+							}
+						}
 					}
 				}
 			} else {
-				//FIXME To might be changed and it would'n be reflected, might lead to misunderstandings
 				Invitation i = form.getModelObject();
 				try {
 					getBean(InvitationManager.class).sendInvitionLink(i, MessageType.Create, subject.getObject(), message.getObject(), false);
 				} catch (Exception e) {
-					log.error("error while sending invitation ", e);
+					log.error("error while sending invitation by URL ", e);
 				}
 			}
 			super.onClick(target, button);
@@ -191,7 +265,10 @@ public class InvitationDialog extends Ab
 	}
 	
 	private Invitation create(User u) {
-		Invitation i = form.getModelObject();
+		Invitation i = new Invitation(form.getModelObject());
+		i.setId(null);
+		i.setUpdated(null);
+		i.setUsed(false);
 		
 		i.setPassword(ManageCryptStyle.getInstanceOfCrypt().createPassPhrase(i.getPassword())); //FIXME should be hidden
 		//FIXME another HACK
@@ -222,20 +299,41 @@ public class InvitationDialog extends Ab
 		
 		public InvitationForm(String id, IModel<Invitation> model) {
 			super(id, model);
-			add(new UserMultiChoice("recipients", modelTo).setLabel(Model.of(Application.getString(216))).setRequired(true)
-					.add(new AjaxFormComponentUpdatingBehavior("change") {
-						private static final long serialVersionUID = 1L;
-		
-						@Override
-						protected void onUpdate(AjaxRequestTarget target) {
-							Collection<User> to = modelTo.getObject();
-							send.setEnabled(to.size() > 0, target);
-							generate.setEnabled(to.size() == 1, target);
-						}
-					}));
-			add(new TextField<String>("subject", subject));
-			add(new TextArea<String>("message", message));
-			add(new AjaxCheckBox("passwordProtected") {
+			RadioGroup<InviteeType> rdi = new RadioGroup<>("inviteeType", inviteeType);
+			add(rdi.add(new AjaxFormChoiceComponentUpdatingBehavior() {
+				private static final long serialVersionUID = 1L;
+
+				@Override
+				protected void onUpdate(AjaxRequestTarget target) {
+					boolean groupsEnabled = InviteeType.group == inviteeType.getObject();
+					updateButtons(target);
+					target.add(groups.setEnabled(groupsEnabled), recipients.setEnabled(!groupsEnabled));
+				}
+			}));
+			//TODO list should be updated on open
+			rdi.add(recipients.setLabel(Model.of(Application.getString(216))).setRequired(true).add(new AjaxFormComponentUpdatingBehavior("change") {
+				private static final long serialVersionUID = 1L;
+				
+				@Override
+				protected void onUpdate(AjaxRequestTarget target) {
+					url.setModelObject(null);
+					updateButtons(target);
+				}
+			}).setOutputMarkupId(true));
+			rdi.add(groups.setLabel(Model.of(Application.getString(126))).setRequired(true).add(new AjaxFormComponentUpdatingBehavior("change") {
+				private static final long serialVersionUID = 1L;
+				
+				@Override
+				protected void onUpdate(AjaxRequestTarget target) {
+					url.setModelObject(null);
+					updateButtons(target);
+				}
+			}).setOutputMarkupId(true));
+			rdi.add(new Radio<InviteeType>("user", Model.of(InviteeType.user)), new Radio<InviteeType>("group", Model.of(InviteeType.group)));
+
+			rdi.add(new TextField<String>("subject", subject));
+			rdi.add(new TextArea<String>("message", message));
+			rdi.add(new AjaxCheckBox("passwordProtected") {
 				private static final long serialVersionUID = 1L;
 
 				@Override
@@ -245,38 +343,25 @@ public class InvitationDialog extends Ab
 					target.add(passwd);
 				}
 			});
-			add(new RadioGroup<Valid>("valid").add(
-					new Radio<Valid>("one", Model.of(Valid.OneTime)).add(new AjaxEventBehavior("click") {
-						private static final long serialVersionUID = 1L;
-
-						@Override
-						protected void onEvent(AjaxRequestTarget target) {
-							target.add(from.setEnabled(false), to.setEnabled(false), timeZoneId.setEnabled(false));
-						}
-					})
-					, new Radio<Valid>("period", Model.of(Valid.Period)).add(new AjaxEventBehavior("click") {
-						private static final long serialVersionUID = 1L;
-
-						@Override
-						protected void onEvent(AjaxRequestTarget target) {
-							target.add(from.setEnabled(true), to.setEnabled(true), timeZoneId.setEnabled(true));
-						}
-					})
-					, new Radio<Valid>("endless", Model.of(Valid.Endless)).add(new AjaxEventBehavior("click") {
-						private static final long serialVersionUID = 1L;
-
-						@Override
-						protected void onEvent(AjaxRequestTarget target) {
-							target.add(from.setEnabled(false), to.setEnabled(false), timeZoneId.setEnabled(false));
-						}
-					})
-					));
-			add(passwd = new PasswordTextField("password"));
+			RadioGroup<Valid> valid = new RadioGroup<Valid>("valid");
+			valid.add(new AjaxFormChoiceComponentUpdatingBehavior() {
+				private static final long serialVersionUID = 1L;
+
+				@Override
+				protected void onUpdate(AjaxRequestTarget target) {
+					boolean dateEnabled = InvitationForm.this.getModelObject().getValid() == Valid.Period;
+					target.add(from.setEnabled(dateEnabled), to.setEnabled(dateEnabled), timeZoneId.setEnabled(dateEnabled));
+				}
+			});
+			rdi.add(valid.add(new Radio<Valid>("one", Model.of(Valid.OneTime))
+					, new Radio<Valid>("period", Model.of(Valid.Period))
+					, new Radio<Valid>("endless", Model.of(Valid.Endless))));
+			rdi.add(passwd = new PasswordTextField("password"));
 			Invitation i = getModelObject();
 			passwd.setLabel(Model.of(Application.getString(525))).setOutputMarkupId(true).setEnabled(i.isPasswordProtected());
-			add(from = new AjaxDateTimePicker("validFrom", "yyyy/MM/dd", "HH:mm:ss")); //FIXME use user locale
-			add(to = new AjaxDateTimePicker("validTo", "yyyy/MM/dd", "HH:mm:ss")); //FIXME use user locale
-			add(timeZoneId = new DropDownChoice<String>("timeZoneId", tzId, AVAILABLE_TIMEZONES));
+			rdi.add(from = new AjaxDateTimePicker("validFrom", "yyyy/MM/dd", "HH:mm:ss")); //FIXME use user locale
+			rdi.add(to = new AjaxDateTimePicker("validTo", "yyyy/MM/dd", "HH:mm:ss")); //FIXME use user locale
+			rdi.add(timeZoneId = new DropDownChoice<String>("timeZoneId", tzId, AVAILABLE_TIMEZONES));
 			from.setEnabled(i.getValid() == Valid.Period).setOutputMarkupId(true);
 			to.setEnabled(i.getValid() == Valid.Period).setOutputMarkupId(true);
 			timeZoneId.setEnabled(i.getValid() == Valid.Period).setOutputMarkupId(true)
@@ -288,11 +373,23 @@ public class InvitationDialog extends Ab
 						//no-op added to preserve selection
 					}
 				});
-			add(new LanguageDropDown("language", new PropertyModel<Long>(InvitationDialog.this, "lang")));
-			add(url.setOutputMarkupId(true));
+			rdi.add(new LanguageDropDown("language", new PropertyModel<Long>(InvitationDialog.this, "lang")));
+			rdi.add(url.setOutputMarkupId(true));
 			add(feedback);
 		}
 		
+		private void updateButtons(AjaxRequestTarget target) {
+			if (inviteeType.getObject() == InviteeType.user) {
+				Collection<User> to = recipients.getModelObject();
+				send.setEnabled(to.size() > 0, target);
+				generate.setEnabled(to.size() == 1, target);
+			} else {
+				Collection<Group> to = groups.getModelObject();
+				send.setEnabled(to.size() > 0, target);
+				generate.setEnabled(false, target);
+			}
+		}
+		
 		@Override
 		protected void onValidate() {
 			if (from.getConvertedInput() != null && to.getConvertedInput() != null && from.getConvertedInput().after(to.getConvertedInput())) {
@@ -306,7 +403,7 @@ public class InvitationDialog extends Ab
 		subject.detach();
 		message.detach();
 		tzId.detach();
-		modelTo.detach();
+		inviteeType.detach();
 		super.onDetach();
 	}
 }

Modified: openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/util/UserChoiceProvider.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/util/UserChoiceProvider.java?rev=1706188&r1=1706187&r2=1706188&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/util/UserChoiceProvider.java (original)
+++ openmeetings/trunk/singlewebapp/openmeetings-web/src/main/java/org/apache/openmeetings/web/util/UserChoiceProvider.java Thu Oct  1 07:22:50 2015
@@ -99,7 +99,7 @@ public class UserChoiceProvider implemen
 
 	@Override
 	public Collection<User> toChoices(Collection<String> ids) {
-		Collection<User> c = new ArrayList<User>();
+		Collection<User> c = new ArrayList<>();
 		for (String id : ids) {
 			if (newContacts.containsKey(id)) {
 				c.add(newContacts.get(id));

Modified: openmeetings/trunk/singlewebapp/openmeetings-web/src/main/webapp/css/theme.css
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/openmeetings-web/src/main/webapp/css/theme.css?rev=1706188&r1=1706187&r2=1706188&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/openmeetings-web/src/main/webapp/css/theme.css (original)
+++ openmeetings/trunk/singlewebapp/openmeetings-web/src/main/webapp/css/theme.css Thu Oct  1 07:22:50 2015
@@ -621,3 +621,7 @@ form .input {
 	padding-right: 0.2em;
 	padding-left: 0.2em;
 }
+.invitees.select2-container-multi .select2-choices {
+	max-height: 80px;
+	overflow-y: auto;
+}