blob: 293a40c1dffdc071d07b5eb6eab177ec4f9e4be0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License") + you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openmeetings.web.room;
import static org.apache.openmeetings.util.LinkHelper.getInvitationLink;
import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
import static org.apache.openmeetings.web.app.Application.getBean;
import static org.apache.openmeetings.web.app.WebSession.AVAILABLE_TIMEZONES;
import static org.apache.openmeetings.web.app.WebSession.getUserId;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import org.apache.openmeetings.data.conference.InvitationManager;
import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
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.room.Room;
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.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;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.Radio;
import org.apache.wicket.markup.html.form.RadioGroup;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.util.CollectionModel;
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;
import com.googlecode.wicket.jquery.ui.widget.dialog.DialogButton;
import com.googlecode.wicket.kendo.ui.form.datetime.AjaxDateTimePicker;
import com.googlecode.wicket.kendo.ui.form.datetime.DateTimePicker;
import com.googlecode.wicket.kendo.ui.panel.KendoFeedbackPanel;
public class InvitationDialog extends AbstractFormDialog<Invitation> {
private static final long serialVersionUID = 1L;
private static final Logger log = Red5LoggerFactory.getLogger(InvitationDialog.class, webAppRootKey);
private final DialogButton generate = new DialogButton("generate", Application.getString(1526));
private final DialogButton send = new DialogButton("send", Application.getString(218));
private final DialogButton cancel = new DialogButton("cancel", Application.getString(219));
private final InvitationForm form;
private final KendoFeedbackPanel feedback = new KendoFeedbackPanel("feedback", new Options("button", true));
private final long roomId;
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 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 TextChoiceProvider<Organisation>() {
private static final long serialVersionUID = 1L;
@Override
public void query(String term, int page, Response<Organisation> response) {
if (WebSession.getRights().contains(User.Right.Admin)) {
List<Organisation> groups = getBean(OrganisationDao.class).get(0, Integer.MAX_VALUE);
for (Organisation g : groups) {
if (g.getName().toLowerCase().contains(term.toLowerCase())) {
response.add(g);
}
}
} else {
User u = getBean(UserDao.class).get(getUserId());
for (Organisation_Users ou : u.getOrganisation_users()) {
if (ou.getOrganisation().getName().toLowerCase().contains(term.toLowerCase())) {
response.add(ou.getOrganisation());
}
}
}
}
@Override
public Collection<Organisation> toChoices(Collection<String> ids) {
Collection<Organisation> c = new ArrayList<>();
for (String id : ids) {
c.add(getBean(OrganisationDao.class).get(Long.valueOf(id)));
}
return c;
}
@Override
protected String getDisplayText(Organisation choice) {
return choice.getName();
}
@Override
protected Object getId(Organisation choice) {
return choice.getOrganisation_id();
}
});
public InvitationDialog(String id, long roomId) {
super(id, Application.getString(214), new CompoundPropertyModel<Invitation>(new Invitation()));
this.roomId = roomId;
add(form = new InvitationForm("form", getModel()));
}
@Override
public int getWidth() {
return 500;
}
public void updateModel(AjaxRequestTarget target) {
Invitation i = new Invitation();
User u = getBean(UserDao.class).get(getUserId());
i.setInvitedBy(u);
Room r = getBean(RoomDao.class).get(roomId);
i.setRoom(r);
Calendar d = Calendar.getInstance();
i.setValidFrom(d.getTime());
d.add(Calendar.DATE, 1);
i.setValidTo(d.getTime());
i.setPassword("ASDDF");
String hashRaw = "HASH" + (System.currentTimeMillis());
try {
i.setHash(MD5.do_checksum(hashRaw));
} catch (NoSuchAlgorithmException e) {
log.error("Unexpected error while creating invitation", e);
throw new RuntimeException(e);
}
subject.setObject(null);
message.setObject(null);
recipients.setModelObject(new ArrayList<User>());
recipients.setEnabled(true);
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);
target.add(form);
}
@Override
protected Form<?> getForm(DialogButton button) {
if (button.equals(generate) || button.equals(send)) {
return form;
}
return super.getForm(button);
}
@Override
public InvitationForm getForm() {
return form;
}
@Override
protected DialogButton getSubmitButton() {
return send;
}
@Override
protected List<DialogButton> getButtons() {
return Arrays.asList(generate, send, cancel);
}
@Override
protected void onError(AjaxRequestTarget target) {
target.add(feedback);
}
@Override
public void onClick(AjaxRequestTarget target, DialogButton button) {
//TODO need to be reviewed
if (button.equals(cancel)) {
super.onClick(target, button);
} else if (button.equals(generate)) {
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())) {
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 {
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 by URL ", e);
}
}
super.onClick(target, button);
}
}
private Invitation create(User u) {
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
Calendar d = Calendar.getInstance();
d.setTime(i.getValidFrom());
d.add(Calendar.MINUTE, -5);
i.setValidFrom(d.getTime());
i.setInvitee(u);
if (Type.contact == u.getType()) {
//TODO not sure it is right
u.setLanguage_id(lang);
}
return getBean(InvitationDao.class).update(i);
}
@Override
protected void onSubmit(AjaxRequestTarget target) {
//designed to be empty because of multiple submit buttons
}
private class InvitationForm extends Form<Invitation> {
private static final long serialVersionUID = 1L;
private final PasswordTextField passwd;
private final DateTimePicker from;
private final DateTimePicker to;
private final DropDownChoice<String> timeZoneId;
public InvitationForm(String id, IModel<Invitation> model) {
super(id, model);
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
protected void onUpdate(AjaxRequestTarget target) {
InvitationForm.this.getModelObject().setPasswordProtected(getConvertedInput());
passwd.setEnabled(getConvertedInput());
target.add(passwd);
}
});
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());
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)
.add(new AjaxFormComponentUpdatingBehavior("change") {
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
//no-op added to preserve selection
}
});
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())) {
error(Application.getString(1592));
}
}
}
@Override
protected void onDetach() {
subject.detach();
message.detach();
tzId.detach();
inviteeType.detach();
super.onDetach();
}
}