| /* |
| * 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.user.calendar; |
| |
| import static org.apache.openmeetings.web.app.WebSession.getUserId; |
| import static org.apache.openmeetings.web.common.confirmation.ConfirmationHelper.newOkCancelDangerConfirm; |
| |
| import java.util.List; |
| |
| import org.apache.http.auth.UsernamePasswordCredentials; |
| import org.apache.http.client.HttpClient; |
| import org.apache.http.client.protocol.HttpClientContext; |
| import org.apache.openmeetings.db.dao.calendar.AppointmentDao; |
| import org.apache.openmeetings.db.dao.user.UserDao; |
| import org.apache.openmeetings.db.entity.calendar.Appointment; |
| import org.apache.openmeetings.db.entity.calendar.OmCalendar; |
| import org.apache.openmeetings.service.calendar.caldav.AppointmentManager; |
| import org.apache.openmeetings.web.common.OmModalCloseButton; |
| import org.apache.wicket.AttributeModifier; |
| import org.apache.wicket.ajax.AjaxRequestTarget; |
| import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox; |
| import org.apache.wicket.core.request.handler.IPartialPageRequestHandler; |
| import org.apache.wicket.markup.html.basic.Label; |
| import org.apache.wicket.markup.html.form.Form; |
| import org.apache.wicket.markup.html.form.PasswordTextField; |
| import org.apache.wicket.markup.html.form.RequiredTextField; |
| import org.apache.wicket.markup.html.form.TextField; |
| import org.apache.wicket.markup.html.form.UrlTextField; |
| import org.apache.wicket.model.CompoundPropertyModel; |
| import org.apache.wicket.model.IModel; |
| import org.apache.wicket.model.Model; |
| import org.apache.wicket.model.ResourceModel; |
| import org.apache.wicket.spring.injection.annot.SpringBean; |
| import org.apache.wicket.validation.IValidatable; |
| import org.apache.wicket.validation.validator.UrlValidator; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxButton; |
| import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxLink; |
| import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; |
| import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel; |
| import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; |
| |
| /** |
| * Multipurpose Calendar Dialog form. This provides the ability to ask for a user prompt, |
| * for Creating, and Syncing of Calendars. Along with that also, |
| * during the Creation and Deletion of Appointments. |
| */ |
| public class CalendarDialog extends Modal<OmCalendar> { |
| private static final long serialVersionUID = 1L; |
| private static final Logger log = LoggerFactory.getLogger(CalendarDialog.class); |
| private CalendarPanel calendarPanel; |
| |
| private final NotificationPanel feedback = new NotificationPanel("feedback"); |
| private BootstrapAjaxButton save; |
| private BootstrapAjaxLink<String> delete; |
| private UserCalendarForm form; |
| private List<OmCalendar> cals; //List of calendars for syncing |
| private int calIndex = 0; |
| @SpringBean |
| private UserDao userDao; |
| @SpringBean |
| private AppointmentDao apptDao; |
| @SpringBean |
| private AppointmentManager apptManager; |
| |
| public enum DIALOG_TYPE { |
| UPDATE_CALENDAR, |
| SYNC_CALENDAR, |
| UPDATE_APPOINTMENT, |
| DELETE_APPOINTMENT |
| } |
| |
| //Defines the current mode of in which the Dialog is functioning in |
| private DIALOG_TYPE type = DIALOG_TYPE.UPDATE_CALENDAR; |
| private Appointment appointment = null; |
| |
| public CalendarDialog(String id, final CalendarPanel calendarPanel, CompoundPropertyModel<OmCalendar> model) { |
| super(id, model); |
| this.calendarPanel = calendarPanel; |
| } |
| |
| @Override |
| protected void onInitialize() { |
| header(new ResourceModel("calendar.dialogTitle")); |
| |
| form = new UserCalendarForm("calform", getModel()); |
| add(form); |
| |
| addButton(save = new BootstrapAjaxButton(BUTTON_MARKUP_ID, new ResourceModel("144"), form, Buttons.Type.Outline_Primary) { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected void onSubmit(AjaxRequestTarget target) { |
| switch (type) { |
| case UPDATE_CALENDAR: |
| OmCalendar c = form.getModelObject(); |
| c.setHref(form.url.getModelObject()); |
| c.setOwner(userDao.get(c.getOwner().getId())); // owner might need to be refreshed |
| HttpClient client = calendarPanel.getHttpClient(); |
| HttpClientContext context = calendarPanel.getHttpClientContext(); |
| |
| if (form.gcal.getModelObject()) { |
| c.setSyncType(OmCalendar.SyncType.GOOGLE_CALENDAR); |
| c.setToken(form.username.getModelObject()); |
| if (c.getId() == null) { |
| calendarPanel.populateGoogleCalendar(c, target); |
| } |
| } else if (c.getId() == null && form.username.getModelObject() != null) { |
| apptManager.provideCredentials(context, c, new UsernamePasswordCredentials(form.username.getModelObject(), |
| form.pass.getModelObject())); |
| } |
| |
| apptManager.createCalendar(client, context, c); |
| calendarPanel.refreshCalendars(target); |
| calendarPanel.refresh(target); |
| break; |
| case SYNC_CALENDAR: |
| syncCalendar(form.getModelObject(), target); |
| if (setFormModelObject()) { |
| setButtons(target); |
| target.add(show(target)); |
| } |
| break; |
| case UPDATE_APPOINTMENT: |
| updateAppointment(appointment); |
| calendarPanel.refresh(target); |
| break; |
| case DELETE_APPOINTMENT: |
| deleteAppointment(appointment); |
| calendarPanel.refresh(target); |
| break; |
| } |
| clearFormModel(target); |
| target.add(feedback); |
| } |
| |
| @Override |
| protected void onError(AjaxRequestTarget target) { |
| target.add(feedback); |
| } |
| }); |
| save.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true); |
| delete = new BootstrapAjaxLink<>(BUTTON_MARKUP_ID, null, Buttons.Type.Outline_Danger, new ResourceModel("80")) { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public void onClick(AjaxRequestTarget handler) { |
| apptManager.deleteCalendar(form.getModelObject()); |
| calendarPanel.refresh(handler); |
| calendarPanel.refreshCalendars(handler); |
| } |
| }; |
| delete.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true); |
| addButton(delete.add(newOkCancelDangerConfirm(this, getString("833")))); |
| addButton(OmModalCloseButton.of()); |
| super.onInitialize(); |
| } |
| |
| /** |
| * Open the Dialog with a specific type of Appointment Based Prompts |
| * |
| * @param handler - the {@link IPartialPageRequestHandler} |
| * @param type - the {@link DIALOG_TYPE} being opened |
| * @param a - the {@link Appointment} |
| */ |
| public void show(IPartialPageRequestHandler handler, DIALOG_TYPE type, Appointment a) { |
| this.type = type; |
| appointment = a; |
| if (isOwner(a)) { |
| if (setFormModelObject(a, handler)) { |
| handler.add(show(handler)); |
| } else { |
| switch (type) { |
| case UPDATE_APPOINTMENT: |
| updateAppointment(a); |
| break; |
| case DELETE_APPOINTMENT: |
| deleteAppointment(a); |
| break; |
| case SYNC_CALENDAR, UPDATE_CALENDAR: |
| break; |
| default: |
| break; |
| } |
| |
| calendarPanel.refresh(handler); |
| } |
| } |
| |
| } |
| |
| /** |
| * Open the Dialog with a specific type of Calendar Based Prompts |
| * |
| * @param handler - the {@link IPartialPageRequestHandler} |
| * @param type - the {@link DIALOG_TYPE} being opened |
| * @param c - the {@link OmCalendar} |
| */ |
| public void show(IPartialPageRequestHandler handler, DIALOG_TYPE type, OmCalendar c) { |
| this.type = type; |
| switch (type) { |
| case UPDATE_CALENDAR: |
| setFormModelObject(c); |
| setButtons(handler); |
| show(handler); |
| break; |
| case SYNC_CALENDAR: |
| if (setCalendarList(handler)) { |
| show(handler); |
| handler.add(this); |
| } else { |
| calendarPanel.refresh(handler); |
| } |
| break; |
| case DELETE_APPOINTMENT, UPDATE_APPOINTMENT: |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /** |
| * Performs syncing of the Calendar. |
| * |
| * @param c Calendar to sync |
| * @param handler Handler used to update the CalendarPanel |
| */ |
| private void syncCalendar(OmCalendar c, IPartialPageRequestHandler handler) { |
| HttpClient client = calendarPanel.getHttpClient(); |
| HttpClientContext context = calendarPanel.getHttpClientContext(); |
| if (form.username.getModelObject() != null) { |
| apptManager.provideCredentials(context, c, new UsernamePasswordCredentials(form.username.getModelObject(), |
| form.pass.getModelObject())); |
| } |
| apptManager.syncItem(client, context, c); |
| calendarPanel.refresh(handler); |
| log.trace("Calendar {} Successfully synced.", c.getTitle()); |
| } |
| |
| /** |
| * Performs Deletion of Appointment on the Calendar. |
| * |
| * @param a Appointment to delete |
| */ |
| private void deleteAppointment(Appointment a) { |
| apptManager.deleteItem(calendarPanel.getHttpClient(), calendarPanel.getHttpClientContext(), a); |
| appointment = null; |
| } |
| |
| /** |
| * Performs updation of Appointment on the Calendar. |
| * |
| * @param a Appointment to update |
| */ |
| private void updateAppointment(Appointment a) { |
| apptManager.updateItem(calendarPanel.getHttpClient(), calendarPanel.getHttpClientContext(), a); |
| appointment = null; |
| } |
| |
| private static boolean isOwner(Appointment object) { |
| return object.getOwner() != null && getUserId().equals(object.getOwner().getId()); |
| } |
| |
| private static boolean isOwner(OmCalendar object) { |
| return object.getOwner() != null && getUserId().equals(object.getOwner().getId()); |
| } |
| |
| /** |
| * Sets the calendar list to sync and |
| * syncs all them until a calendar whose |
| * |
| * @param target Ajax target to update the buttons. |
| * @return <code>true</code> if a Calendar needs to be synced |
| * else all calendars should have gotten synced |
| */ |
| private boolean setCalendarList(IPartialPageRequestHandler target) { |
| type = DIALOG_TYPE.SYNC_CALENDAR; |
| cals = apptManager.getCalendars(getUserId()); |
| calendarPanel.getHttpClient(); |
| calIndex = 0; |
| setButtons(target); |
| return setFormModelObject(); |
| } |
| |
| // Sets the form object when in need of syncing. Returns true if model is set |
| private boolean setFormModelObject() { |
| if (cals != null && !cals.isEmpty() && calIndex < cals.size()) { |
| OmCalendar calendar = cals.get(calIndex++); |
| HttpClient client = calendarPanel.getHttpClient(); |
| HttpClientContext context = calendarPanel.getHttpClientContext(); |
| if (!apptManager.testConnection(client, context, calendar)) { |
| form.setModelObject(calendar); |
| form.url.setModelObject(calendar.getHref()); |
| return true; |
| } else { |
| apptManager.syncItem(client, context, calendar); |
| return setFormModelObject(); |
| } |
| } |
| |
| cals = null; |
| return false; |
| } |
| |
| // Sets the form model object if the calendar cannot be reached. Returns true if model is set |
| private boolean setFormModelObject(Appointment a, IPartialPageRequestHandler target) { |
| OmCalendar c = a.getCalendar(); |
| if (apptManager.testConnection(calendarPanel.getHttpClient(), calendarPanel.getHttpClientContext(), c)) { |
| return false; |
| } |
| |
| setFormModelObject(c); |
| setButtons(target); |
| return true; |
| } |
| |
| private void setFormModelObject(OmCalendar c) { |
| if (c != null) { |
| form.setModelObject(c); |
| form.url.setModelObject(c.getHref()); |
| if (c.getSyncType() == OmCalendar.SyncType.GOOGLE_CALENDAR) { |
| form.username.setDefaultModelObject(c.getToken()); |
| form.gcal.setDefaultModelObject(true); |
| } else { |
| form.gcal.setDefaultModelObject(false); |
| } |
| } |
| } |
| |
| public void setButtons(IPartialPageRequestHandler target) { |
| switch (type) { |
| case UPDATE_APPOINTMENT, DELETE_APPOINTMENT, SYNC_CALENDAR: |
| target.add(delete.setVisible(false), save.setVisible(true)); |
| break; |
| case UPDATE_CALENDAR: |
| OmCalendar c = form.getModelObject(); |
| if (c.getId() == null) { |
| target.add(delete.setVisible(false)); |
| } else { |
| target.add(delete.setVisible(isOwner(c))); |
| } |
| target.add(save.setVisible(isOwner(c))); |
| } |
| } |
| |
| private void clearFormModel(IPartialPageRequestHandler handler) { |
| form.clearInput(); |
| form.username.setModelObject(null); |
| handler.add(form); |
| } |
| |
| private class UserCalendarForm extends Form<OmCalendar> { |
| private static final long serialVersionUID = 1L; |
| private TextField<String> username = new TextField<>("login", Model.of("")); |
| private PasswordTextField pass = new PasswordTextField("password", Model.of("")); |
| RequiredTextField<String> title = new RequiredTextField<>("title"); |
| |
| // Fields required for adding Google Calendar |
| private Label urlLabel; |
| private Label userLabel; |
| private Label passLabel; |
| |
| AjaxCheckBox gcal; // Checkbox for Google Calendar |
| UrlTextField url = new UrlTextField("url", Model.of(""), new UrlValidator() { |
| private static final long serialVersionUID = 1L; |
| |
| //Custom UrlValidator |
| @Override |
| public void validate(IValidatable<String> validatable) { |
| //Only Validate when It's not a Google Calendar i.e a URL |
| if (!gcal.getModelObject()) { |
| super.validate(validatable); |
| } |
| } |
| }) { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected String[] getInputTypes() { |
| //Can be URL or a Text |
| return new String[]{"url", "text"}; |
| } |
| }; |
| |
| public UserCalendarForm(String id, IModel<OmCalendar> model) { |
| super(id, model); |
| setOutputMarkupId(true); |
| } |
| |
| @Override |
| protected void onInitialize() { |
| urlLabel = new Label("urlLabel", getString("calendar.url")); |
| userLabel = new Label("userLabel", getString("114")); |
| passLabel = new Label("passLabel", getString("110")); |
| add(title); |
| add(feedback.setOutputMarkupId(true)); |
| |
| add(url.setRequired(true).setOutputMarkupId(true)); |
| add(username.setOutputMarkupPlaceholderTag(true)); |
| add(urlLabel.setOutputMarkupId(true)); |
| |
| add(pass.setRequired(false).setOutputMarkupPlaceholderTag(true)); |
| |
| add(userLabel.setOutputMarkupPlaceholderTag(true)); |
| add(passLabel.setOutputMarkupPlaceholderTag(true)); |
| |
| gcal = new AjaxCheckBox("gcal", Model.of(false)) { |
| private static final long serialVersionUID = 1L; |
| |
| //Checkbox, which when in "true" state will be in |
| // the Google Calendar State, otherwise in the CalDAV state |
| @Override |
| protected void onUpdate(AjaxRequestTarget target) { |
| setGCalVisibility(getModelObject()); |
| target.add(UserCalendarForm.this); |
| } |
| }; |
| |
| add(gcal); |
| super.onInitialize(); |
| } |
| |
| @Override |
| protected void onModelChanged() { |
| OmCalendar calendar = getModelObject(); |
| switch (type) { |
| case UPDATE_CALENDAR: |
| title.setEnabled(true); |
| if (calendar.getId() != null) { |
| url.setEnabled(false); |
| pass.setEnabled(false); |
| username.setEnabled(false); |
| gcal.setEnabled(false); |
| } else { |
| gcal.setEnabled(true); |
| url.setEnabled(true); |
| pass.setEnabled(true); |
| username.setEnabled(true); |
| } |
| setGCalVisibility(calendar); |
| break; |
| case SYNC_CALENDAR, UPDATE_APPOINTMENT, DELETE_APPOINTMENT: |
| title.setEnabled(false); |
| url.setEnabled(false); |
| username.setEnabled(true); |
| pass.setEnabled(true); |
| gcal.setEnabled(false); |
| setGCalVisibility(calendar); |
| break; |
| } |
| } |
| |
| private void setGCalVisibility(OmCalendar calendar) { |
| setGCalVisibility(calendar.getSyncType() == OmCalendar.SyncType.GOOGLE_CALENDAR); |
| } |
| |
| //Sets the visibility of the Labels and the TextFields based on |
| // whether it's a Google calendar or not. |
| private void setGCalVisibility(boolean isGoogleCalendar) { |
| if (isGoogleCalendar) { |
| gcal.setModelObject(true); |
| pass.setVisible(false); |
| passLabel.setVisible(false); |
| |
| //Google Calendar ID |
| urlLabel.setDefaultModelObject(getString("calendar.googleID")); |
| url.setEnabled(true); |
| |
| //Google API Key |
| userLabel.setDefaultModelObject(getString("calendar.googleKey")); |
| username.setEnabled(true); |
| } else { |
| gcal.setModelObject(false); |
| pass.setVisible(true); |
| passLabel.setVisible(true); |
| |
| userLabel.setDefaultModelObject(getString("114")); |
| username.setModelObject(null); |
| |
| urlLabel.setDefaultModelObject(getString("calendar.url")); |
| } |
| url.setLabel(Model.of((String)urlLabel.getDefaultModelObject())); |
| |
| //Add new AttributeModifier to change the type of URLTextField, to text for |
| //Google Calendar and to URL for a normal CalDAV calendar |
| url.add(AttributeModifier.replace("type", gcal.getModelObject() ? "text" : "url")); |
| } |
| |
| |
| /** |
| * Validates the credentials and the server entered by the user by |
| * performing a HTTP Options Method. |
| * @see Form#onValidate() |
| */ |
| @Override |
| protected void onValidate() { |
| if (hasError()) { |
| return; |
| } |
| switch (type) { |
| case UPDATE_CALENDAR: |
| if (getModelObject().getId() != null || gcal.getModelObject()) { |
| return; |
| } |
| case UPDATE_APPOINTMENT, DELETE_APPOINTMENT, SYNC_CALENDAR: |
| try { |
| OmCalendar calendar = getModelObject(); |
| if (url.isEnabled()) { |
| calendar.setHref(url.getInput()); |
| } |
| HttpClient client = calendarPanel.getHttpClient(); |
| HttpClientContext context = calendarPanel.getHttpClientContext(); |
| |
| apptManager.provideCredentials(context, calendar, |
| new UsernamePasswordCredentials(username.getInput(), pass.getInput())); |
| if (apptManager.testConnection(client, context, calendar)) { |
| return; |
| } |
| } catch (Exception e) { |
| log.error("Error executing the TestConnection", e); |
| } |
| |
| error(getString("calendar.error")); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| } |