diff options
author | Jonathan Bauer | 2017-09-06 13:48:33 +0200 |
---|---|---|
committer | Jonathan Bauer | 2017-09-06 13:48:33 +0200 |
commit | e310fa0738149f20b9de6b173d3d175857b0c748 (patch) | |
tree | 5857811d25cc53c51590cc0158ec84e049a3ed88 | |
parent | [client] Update apache httpclient, pass custom client to ecp-client-lean (diff) | |
download | tutor-module-e310fa0738149f20b9de6b173d3d175857b0c748.tar.gz tutor-module-e310fa0738149f20b9de6b173d3d175857b0c748.tar.xz tutor-module-e310fa0738149f20b9de6b173d3d175857b0c748.zip |
[client/server] network share feature [WIP]
10 files changed, 584 insertions, 15 deletions
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/NetshareConfigurator.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/NetshareConfigurator.java new file mode 100644 index 00000000..ac10e2bb --- /dev/null +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/NetshareConfigurator.java @@ -0,0 +1,330 @@ +package org.openslx.dozmod.gui.control; + +import java.awt.BorderLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EventListener; +import java.util.EventObject; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.event.EventListenerList; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import org.apache.log4j.Logger; +import org.openslx.bwlp.thrift.iface.NetShare; +import org.openslx.bwlp.thrift.iface.NetShareAuth; +import org.openslx.dozmod.gui.control.ComboBox.ComboBoxRenderer; +import org.openslx.dozmod.gui.control.table.NetshareTable; +import org.openslx.dozmod.gui.control.table.QScrollPane; +import org.openslx.dozmod.gui.helper.GridManager; +import org.openslx.dozmod.util.FormatHelper; + +/** + * Widget for netrules configuration of lectures + */ +public class NetshareConfigurator extends NetshareConfiguratorLayout { + + private static final long serialVersionUID = -3336605759245603655L; + private final static Logger LOGGER = Logger.getLogger(NetshareConfigurator.class); + + private List<NetShare> tblNetshareData = null; + + public NetshareConfigurator() { + super(); + tblNetshare.getModel().addTableModelListener(new TableModelListener() { + @Override + public void tableChanged(TableModelEvent e) { + fireNetshareConfigurationChangeEvent(new NetshareConfigurationChangeEvent(NetshareConfigurator.this)); + } + }); + + // combobox for share authentication types + cboNetshareAuth.setModel(new DefaultComboBoxModel<NetShareAuth>(NetShareAuth.values())); + cboNetshareAuth.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + NetShareAuth selectedAuth = cboNetshareAuth.getItemAt(cboNetshareAuth.getSelectedIndex()); + boolean activate = selectedAuth == NetShareAuth.SPECIAL_USER; + // username field is needed to either special or guest user + tfUsername.setEnabled(activate || selectedAuth == NetShareAuth.GUEST_USER); + lblUsername.setEnabled(activate || selectedAuth == NetShareAuth.GUEST_USER); + tfPassword.setEnabled(activate); + lblPassword.setEnabled(activate); + chkShowPass.setEnabled(activate); + } + }); + + tfUsername.setEnabled(false); + lblUsername.setEnabled(false); + tfPassword.setEnabled(false); + lblPassword.setEnabled(false); + chkShowPass.setEnabled(false); + btnAdd.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // check if we are editing an existing share entry or + // creating a new one, check for input either way + NetShare input = new NetShare(); + NetShareAuth inputNetShareAuth = cboNetshareAuth.getItemAt(cboNetshareAuth.getSelectedIndex()); + if (inputNetShareAuth == null) { + LOGGER.error("Could not get the network share auth type from the combobox!"); + return; + } + input.auth = inputNetShareAuth; + input.path = tfSharePath.getText(); + if (input.path == null || input.path.isEmpty()) { + LOGGER.error("Missing/empty network share URI!"); + return; + } + switch (inputNetShareAuth) { + case GUEST_USER: + // guest mode requires guest account but not password + input.username = tfUsername.getText(); + break; + case LOGIN_USER: + break; + case SPECIAL_USER: + // save given username/password + input.username = tfUsername.getText(); + char[] inputPassword = tfPassword.getPassword(); + input.password = new String(inputPassword); + Arrays.fill(inputPassword, '0'); + break; + default: + input = null; + break; + } + if (input == null) { + LOGGER.debug("Input bad, aborting."); + return; + } + + // now decide whether to create a new entry or update existing one + if (tblNetshare.getSelectedItem() != null) { + // editing existing one, delete it from the internal data + if (!tblNetshareData.remove(tblNetshare.getSelectedItem())) { + LOGGER.debug("Failed to remove selected share for replacement!"); + return; + } + } + // either we delete the existing share from the data or we are + // creating a new one, either way add it to the list and update + // the table, if its not present already + if (tblNetshareData.contains(input)) { + LOGGER.error("Network share already in the list, aborting."); + return; + } + tblNetshareData.add(input); + tblNetshare.getModel().setData(tblNetshareData); + } + } + ); + + btnDel.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // try to delete the selected share + NetShare selection = tblNetshare.getSelectedItem(); + if (selection == null) { + return; + } + try { + if (!tblNetshareData.remove(selection)) { + // false if it was not found + LOGGER.error("Could not remove non-existant network share '" + selection.toString() + + "' from the table data: " + tblNetshareData.toString()); + return; + } + // refresh table data + tblNetshare.getModel().setData(tblNetshareData); + } catch (Exception ex) { + LOGGER.debug("Failed to remove " + selection.toString() + " from the table data.", ex); + return; + } + } + }); + + chkShowPass.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() != ItemEvent.SELECTED) { + tfPassword.setEchoChar('*'); + } else { + tfPassword.setEchoChar((char) 0); + } + } + }); + + tblNetshare.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + NetShare item = tblNetshare.getSelectedItem(); + // ugly block-wise sets, but only one test needed compared to + // doing lots of item != null ? ... : ... + if (item != null) { + // share from the list is selected: fill bottom form and change "Add" to "Apply" + btnDel.setEnabled(true); + tfSharePath.setText(item.path); + tfUsername.setText(item.username); + tfPassword.setText(item.password); + cboNetshareAuth.setSelectedItem(item.auth); + btnAdd.setText("Ändern"); + } else { + btnDel.setEnabled(false); + tfSharePath.setText(null); + tfUsername.setText(null); + tfPassword.setText(null); + cboNetshareAuth.setSelectedItem(null); + btnAdd.setText("Hinzufügen"); + } + } + }); + } + + public List<NetShare> getState() { + return tblNetshareData; + } + + public boolean setState(List<NetShare> data) { + if (data == null) + return false; + if (tblNetshareData == null) { + tblNetshareData = new ArrayList<>(); + } + tblNetshareData = data; + tblNetshare.getModel().setData(tblNetshareData); + return true; + } + + protected EventListenerList listenerList = new EventListenerList(); + + public class NetshareConfigurationChangeEvent extends EventObject { + + private static final long serialVersionUID = -511509960878320591L; + + public NetshareConfigurationChangeEvent(Object source) { + super(source); + } + } + + public interface NetshareConfigurationChangeEventListener extends EventListener { + public void stateChanged(NetshareConfigurationChangeEvent event); + } + + public void addNetshareConfigurationChangeEventListener(NetshareConfigurationChangeEventListener listener) { + listenerList.add(NetshareConfigurationChangeEventListener.class, listener); + } + + public void removeNetshareConfigurationChangeEventListener(NetshareConfigurationChangeEventListener listener) { + listenerList.remove(NetshareConfigurationChangeEventListener.class, listener); + } + + void fireNetshareConfigurationChangeEvent(NetshareConfigurationChangeEvent evt) { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i++) { + if (listeners[i] == NetshareConfigurationChangeEventListener.class) { + ((NetshareConfigurationChangeEventListener) listeners[i + 1]).stateChanged(evt); + } + } + } +} + +/** + * Internal layout class for this widget + */ +class NetshareConfiguratorLayout extends JPanel { + + private static final long serialVersionUID = 6479525981542743622L; + + private final static String txtNetshareDesc = "Hier können Sie Netzlaufwerke angeben," + + " die automatisch beim Start der Veranstaltung eingebunden werden sollen."; + protected QLabel lblShareAuth, lblSharePath, lblUsername, lblPassword; + + protected NetshareTable tblNetshare = new NetshareTable(); + protected JTextField tfSharePath, tfUsername; + protected JPasswordField tfPassword; + protected JButton btnAdd, btnDel; + protected JCheckBox chkShowPass; + protected ComboBox<NetShareAuth> cboNetshareAuth = new ComboBox<>(new ComboBoxRenderer<NetShareAuth>() { + @Override + public String renderItem(NetShareAuth item) { + if (item == null) + return null; + return FormatHelper.netShareAuthName(item); + } + }); + + + + public NetshareConfiguratorLayout() { + GridManager grid = new GridManager(this, 5, true, new Insets(3, 3, 3, 3)); + // top info panel + grid.add(new WordWrapLabel(txtNetshareDesc), 5).fill(true, false).expand(true, false); + grid.nextRow(); + // middle netshare list + grid.add(new QScrollPane(tblNetshare), 5).fill(true, true).expand(true, true); + grid.nextRow(); + JPanel pnlButtonDelete = new JPanel(); + pnlButtonDelete.setLayout(new BoxLayout(pnlButtonDelete, BoxLayout.LINE_AXIS)); + btnDel = new JButton("Entfernen"); + pnlButtonDelete.add(Box.createGlue()); + pnlButtonDelete.add(btnDel, BorderLayout.LINE_END); + grid.add(pnlButtonDelete, 5).fill(true, false).expand(true, false); + grid.nextRow(); + JPanel pnlNewShare = new JPanel(); + GridManager gridNewShare = new GridManager(pnlNewShare, 5, true); + pnlNewShare.setBorder(BorderFactory.createTitledBorder("Neues Netzlaufwerk")); + // bottom form to add a new share + lblShareAuth = new QLabel("Authentifizierung"); + gridNewShare.add(lblShareAuth); + gridNewShare.add(cboNetshareAuth, 4).fill(true, false).expand(true, false); // User (optional) + gridNewShare.nextRow(); + lblSharePath = new QLabel("URI"); + gridNewShare.add(lblSharePath); + tfSharePath = new JTextField(); + gridNewShare.add(tfSharePath, 4).fill(true, false).expand(true, false); // User (optional) + gridNewShare.nextRow(); + lblUsername = new QLabel("Username"); + gridNewShare.add(lblUsername); + tfUsername = new JTextField(); + gridNewShare.add(tfUsername, 1).fill(true, false).expand(true, false); // Password (optional) + lblPassword = new QLabel("Passwort:"); + gridNewShare.add(lblPassword); + tfPassword = new JPasswordField(); + gridNewShare.add(tfPassword, 2).fill(true, false).expand(true, false); // Password (optional) + gridNewShare.nextRow(); + chkShowPass = new JCheckBox("Passwort anzeigen"); + JPanel pnlHidePass = new JPanel(); + pnlHidePass.setLayout(new BoxLayout(pnlHidePass, BoxLayout.LINE_AXIS)); + pnlHidePass.add(Box.createGlue()); + pnlHidePass.add(chkShowPass, BorderLayout.LINE_END); + gridNewShare.add(pnlHidePass, 5).fill(true, false).expand(true, false); + gridNewShare.nextRow(); + grid.add(pnlNewShare, 5).fill(true, false).expand(true, false); + grid.nextRow(); + // bottom panels for right-aligned button... + JPanel pnlButtonAdd = new JPanel(); + pnlButtonAdd.setLayout(new BoxLayout(pnlButtonAdd, BoxLayout.LINE_AXIS)); + btnAdd = new JButton("Hinzufügen"); + pnlButtonAdd.add(Box.createGlue()); + pnlButtonAdd.add(btnAdd, BorderLayout.LINE_END); + grid.add(pnlButtonAdd, 5).fill(true, false).expand(true, false); + grid.finish(false); + } +} diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/table/NetshareTable.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/table/NetshareTable.java new file mode 100644 index 00000000..7ebde4eb --- /dev/null +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/table/NetshareTable.java @@ -0,0 +1,47 @@ +package org.openslx.dozmod.gui.control.table; + +import org.openslx.bwlp.thrift.iface.NetShare; +import org.openslx.dozmod.thrift.Sorters; +import org.openslx.dozmod.util.FormatHelper; + +@SuppressWarnings("serial") +public class NetshareTable extends ListTable<NetShare> { + + public static final ListTableColumn COL_PATH = new ListTableColumn("Pfad"); + public static final ListTableColumn COL_TYPE = new ListTableColumn("Typ", Sorters.netShareAuth); + public static final ListTableColumn COL_USER = new ListTableColumn("Username"); + public static final ListTableColumn COL_PASSWORD = new ListTableColumn("Passwort"); + + public NetshareTable() { + super(COL_PATH, COL_TYPE, COL_USER, COL_PASSWORD); + } + + @Override + protected Object getValueAtInternal(NetShare item, ListTableColumn columnIndex) { + if (columnIndex == COL_PATH) + return item.path; + if (columnIndex == COL_TYPE) + return FormatHelper.netShareAuthName(item.auth); + if (columnIndex == COL_USER) + return item.username; + if (columnIndex == COL_PASSWORD) + return item.password; + //TODO others! + throw new IndexOutOfBoundsException(); + } + + @Override + public Object modelValueToDisplayFormat(Object object, ListTableColumn column) { + if (column == COL_PATH) + return (String) object; + if (column == COL_TYPE) + return object.toString(); + if (column == COL_USER) + return (String) object; + if (column == COL_PASSWORD) { + String pass = (String) object; + return pass != null ? pass.replaceAll(".", "*") : ""; + } + throw new IndexOutOfBoundsException(); + } +} diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java index 2918428f..be65ad04 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java @@ -37,6 +37,7 @@ import org.openslx.bwlp.thrift.iface.LecturePermissions; import org.openslx.bwlp.thrift.iface.LectureRead; import org.openslx.bwlp.thrift.iface.LectureWrite; import org.openslx.bwlp.thrift.iface.NetRule; +import org.openslx.bwlp.thrift.iface.NetShare; import org.openslx.bwlp.thrift.iface.UserInfo; import org.openslx.dozmod.gui.Gui; import org.openslx.dozmod.gui.MainWindow; @@ -44,6 +45,8 @@ import org.openslx.dozmod.gui.control.JCheckBoxTree.CheckChangeEvent; import org.openslx.dozmod.gui.control.JCheckBoxTree.CheckChangeEventListener; import org.openslx.dozmod.gui.control.LectureCustomPermissionManager.UserChangeEvent; import org.openslx.dozmod.gui.control.LectureCustomPermissionManager.UserChangeEventListener; +import org.openslx.dozmod.gui.control.NetshareConfigurator.NetshareConfigurationChangeEvent; +import org.openslx.dozmod.gui.control.NetshareConfigurator.NetshareConfigurationChangeEventListener; import org.openslx.dozmod.gui.control.RunscriptConfigurator.RunscriptConfigurationChangeEvent; import org.openslx.dozmod.gui.control.RunscriptConfigurator.RunscriptConfigurationChangeEventListener; import org.openslx.dozmod.gui.helper.DateTimeHelper; @@ -140,6 +143,8 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements private List<NetRule> originalNetrules = null; private String currentRunscript = null; private String originalRunscript = null; + private List<NetShare> currentNetshares = null; + private List<NetShare> originalNetshares = null; /** * Constructor @@ -287,6 +292,12 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements } }); + ctlNetshareConfigurator.addNetshareConfigurationChangeEventListener(new NetshareConfigurationChangeEventListener() { + @Override + public void stateChanged(NetshareConfigurationChangeEvent event) { + reactToChange(); + } + }); // Comboboxes final ItemListener comboItemListener = new ItemListener() { @Override @@ -381,12 +392,16 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements txtImageName.setText(image.getImageName()); lblImageNameInfo.setText(image.getImageName()); } + // remember original netrules and runscript originalNetrules = lecture.networkExceptions != null ? lecture.networkExceptions : new ArrayList<NetRule>(); originalRunscript = lecture.runscript != null ? lecture.runscript : new String(""); + originalNetshares = lecture.networkShares != null ? new ArrayList<NetShare>(lecture.networkShares) : new ArrayList<NetShare>(); currentNetrules = originalNetrules; currentRunscript = originalRunscript; + currentNetshares = originalNetshares; + // remember default permissions if (lecture.defaultPermissions != null) { @@ -415,7 +430,8 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements // init advanced info ctlRunscriptConfigurator.setState(lecture.runscript); - + ctlNetshareConfigurator.setState(lecture.networkShares); + txtTitle.setText(lecture.getLectureName()); lblTitleInfo.setText(lecture.getLectureName()); txtDescription.setText(lecture.getDescription()); @@ -602,17 +618,29 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements Date start = DateTimeHelper.getDateFrom(dtpStartDate, spnStartTime); Date end = DateTimeHelper.getDateFrom(dtpEndDate, spnEndTime); if (!isPeriodValid(start, end, false) && dateHasChanged()) { + pnlTabs.setSelectedIndex(pnlTabs.indexOfTab("Allgemein")); lblError.setText("Ungültiger Zeitraum!"); return false; } // runscript stuff String newState = ctlRunscriptConfigurator.getState(); if (newState == null) { - // marker for error, switch to tab + // script extension was missing from the user input. + // feedback happens in the configurator, just switch to the tab. + pnlTabs.setSelectedIndex(pnlTabs.indexOfTab("Startskript")); return false; } else { currentRunscript = newState; } + + // netshare stuff + List<NetShare> newNetshareList = ctlNetshareConfigurator.getState(); + if (newNetshareList == null) { + // the network share list was never queried if this returns null + return false; + } else { + currentNetshares = newNetshareList; + } // done with mandatory checks, remove error message lblError.setText(null); @@ -632,8 +660,8 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements || (locationInfo != null && lecture.limitToLocations != locationInfo.limitToLocations) || (currentNetrules != null && !currentNetrules.equals(originalNetrules)) || (currentRunscript != null && !currentRunscript.equals(originalRunscript)) + || (currentNetshares != null && !currentNetshares.equals(originalNetshares)) || imageLinkChanged; - return changed; } @@ -661,16 +689,10 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements lecture.imageVersionId = chkAutoUpdate.isSelected() ? image.latestVersionId : cboVersions.getItemAt(cboVersions.getSelectedIndex()).versionId; } - // goto to advanced tab and check (by getting) the state of the textAreas - currentRunscript = ctlRunscriptConfigurator.getState(); - if (currentRunscript == null) { - // getState() will return null only if it couldn't parse the rules - // which means that the user got informed about what was invalid - // So we just return here until the parsing works. - pnlTabs.setSelectedIndex(pnlTabs.indexOfTab("Startskript")); - return false; - } - metadataChanged |= (currentNetrules != lecture.networkExceptions || currentRunscript != lecture.runscript); + + metadataChanged |= (currentNetrules != lecture.networkExceptions + || currentRunscript != lecture.runscript + || currentNetshares != lecture.networkShares); // now check if we need to push a new LectureWrite if (metadataChanged) { // first build the LectureWrite from the GUI fields @@ -683,6 +705,8 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements // TODO: coming "false" is Location related false, chkHasUsbAccess.isSelected()); metadata.setNetworkExceptions(currentNetrules); + metadata.setNetworkShares(currentNetshares); + // now trigger the actual action try { ThriftManager.getSatClient().updateLecture(Session.getSatelliteToken(), @@ -770,6 +794,9 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements if (pnlTabs.indexOfTab("Startskript") != -1) { pnlTabs.setEnabledAt(pnlTabs.indexOfTab("Startskript"), editable); } + if (pnlTabs.indexOfTab("Netwerk-Shares") != -1) { + pnlTabs.setEnabledAt(pnlTabs.indexOfTab("Netzwerk-Shares"), true); + } btnChangeOwner.setEnabled(LecturePerms.canAdmin(lecture)); btnDownloadImage.setEnabled(ImagePerms.canDownload(image)); } diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/LectureDetailsWindowLayout.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/LectureDetailsWindowLayout.java index fbf04ad1..56c00db1 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/LectureDetailsWindowLayout.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/LectureDetailsWindowLayout.java @@ -35,6 +35,7 @@ import org.openslx.dozmod.gui.control.ComboBox; import org.openslx.dozmod.gui.control.ComboBox.ComboBoxRenderer; import org.openslx.dozmod.gui.control.LectureCustomPermissionManager; import org.openslx.dozmod.gui.control.LocationSelector; +import org.openslx.dozmod.gui.control.NetshareConfigurator; import org.openslx.dozmod.gui.control.PersonLabel; import org.openslx.dozmod.gui.control.QDatePickerImpl; import org.openslx.dozmod.gui.control.QLabel; @@ -45,6 +46,7 @@ import org.openslx.dozmod.thrift.Session; import org.openslx.dozmod.thrift.cache.MetaDataCache; import org.openslx.dozmod.util.DateLabelFormatter; import org.openslx.dozmod.util.FormatHelper; +import org.openslx.sat.thrift.version.Feature; import org.openslx.thrifthelper.Comparators; @SuppressWarnings("serial") @@ -94,6 +96,7 @@ public abstract class LectureDetailsWindowLayout extends JDialog { protected final LectureCustomPermissionManager ctlPermissionManager; protected final LocationSelector ctlLocationSelector; protected final RunscriptConfigurator ctlRunscriptConfigurator; + protected final NetshareConfigurator ctlNetshareConfigurator; private static final Properties pickerStrings = new Properties(); @@ -105,6 +108,7 @@ public abstract class LectureDetailsWindowLayout extends JDialog { protected JPanel pnlTabPermissions; protected JPanel pnlTabLocations; protected JPanel pnlTabRunscript; + private JPanel pnlTabNetshare; static { pickerStrings.put("text.today", "Heute"); @@ -367,6 +371,16 @@ public abstract class LectureDetailsWindowLayout extends JDialog { grdAdvanced.add(ctlRunscriptConfigurator).fill(true, true).expand(true, true); grdAdvanced.finish(false); + /* ******************************************************************************* + * + * Tab "Network-Shares" + * + ********************************************************************************/ + ctlNetshareConfigurator = new NetshareConfigurator(); + pnlTabNetshare = new JPanel(); + GridManager grdNetshare = new GridManager(pnlTabNetshare, 1, false); + grdNetshare.add(ctlNetshareConfigurator).fill(true, true).expand(true, true); + grdNetshare.finish(false); /* ******************************************************************************* * * Main panel containing the tabs @@ -386,6 +400,9 @@ public abstract class LectureDetailsWindowLayout extends JDialog { pnlTabs.addTab("Startskript", pnlTabRunscript); } pnlTabs.addTab("Berechtigungen", pnlTabPermissions); + if (Session.hasFeature(Feature.NETWORK_SHARES)) { + pnlTabs.addTab("Netzwerk-Shares", pnlTabNetshare); + } add(pnlTabs, BorderLayout.CENTER); // usage counter + button panel on the bottom JPanel buttonPanel = new JPanel(); diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/Sorters.java b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/Sorters.java index 291bf381..e1a6d877 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/Sorters.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/Sorters.java @@ -3,6 +3,7 @@ package org.openslx.dozmod.thrift; import java.util.Comparator; import org.openslx.bwlp.thrift.iface.Location; +import org.openslx.bwlp.thrift.iface.NetShareAuth; import org.openslx.bwlp.thrift.iface.OperatingSystem; import org.openslx.bwlp.thrift.iface.Organization; import org.openslx.bwlp.thrift.iface.UserInfo; @@ -83,4 +84,19 @@ public class Sorters { } }; + public static final Comparator<NetShareAuth> netShareAuth = new Comparator<NetShareAuth>() { + @Override + public int compare(NetShareAuth o1, NetShareAuth o2) { + // just need a sorter, doesn't really matter how to sort them + if (o1 == null) { + if (o2 == null) + return 0; + return -1; + } else if (o2 == null) { + return 1; + } + return o1.compareTo(o2); + } + }; + } diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/util/FormatHelper.java b/dozentenmodul/src/main/java/org/openslx/dozmod/util/FormatHelper.java index 6f129931..11ad277a 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/util/FormatHelper.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/util/FormatHelper.java @@ -3,6 +3,7 @@ package org.openslx.dozmod.util; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.openslx.bwlp.thrift.iface.Location; +import org.openslx.bwlp.thrift.iface.NetShareAuth; import org.openslx.bwlp.thrift.iface.OperatingSystem; import org.openslx.bwlp.thrift.iface.Organization; import org.openslx.bwlp.thrift.iface.UserInfo; @@ -165,4 +166,25 @@ public class FormatHelper { return "Unknown"; return org.getDisplayName(); } + + /** + * Format the given network share authentication type. + * + * @param NetShareAuth a {@link NetShareAuth} instance + * @return Display name for that authentication type, string "unknown" otherwise + */ + public static String netShareAuthName(NetShareAuth auth) { + if (auth == null) + return "Unknown"; + switch (auth) { + case LOGIN_USER: + return "Angemeldeter Nutzer"; + case GUEST_USER: + return "Gast Nutzer"; + case SPECIAL_USER: + return "Spezifischer Nutzer"; + default: + return auth.toString(); + } + } } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/SupportedFeatures.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/SupportedFeatures.java index 73d1a788..203f3de1 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/SupportedFeatures.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/SupportedFeatures.java @@ -8,6 +8,7 @@ public class SupportedFeatures { static { registerFeature(Feature.EXTEND_EXPIRED_VM); + registerFeature(Feature.NETWORK_SHARES); } public static String getFeatureString() { diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java index ff160917..58c7bdb2 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java @@ -24,6 +24,7 @@ import org.openslx.bwlp.thrift.iface.LectureRead; import org.openslx.bwlp.thrift.iface.LectureSummary; import org.openslx.bwlp.thrift.iface.LectureWrite; import org.openslx.bwlp.thrift.iface.NetRule; +import org.openslx.bwlp.thrift.iface.NetShare; import org.openslx.bwlp.thrift.iface.TNotFoundException; import org.openslx.bwlp.thrift.iface.UserInfo; import org.openslx.util.Json; @@ -39,6 +40,7 @@ public class DbLecture { static { Json.registerThriftClass(NetRule.class); + Json.registerThriftClass(NetShare.class); } private static void setWriteFields(MysqlStatement stmt, String lectureId, LectureWrite lecture, @@ -117,6 +119,7 @@ public class DbLecture { stmt.setString("ownerid", user.userId); stmt.executeUpdate(); writeLocations(connection, lectureId, lecture.locationIds); + DbNetshare.writeNetworkShares(connection, lectureId, lecture.networkShares); connection.commit(); return lectureId; } catch (SQLException e) { @@ -138,6 +141,7 @@ public class DbLecture { + " WHERE lectureid = :lectureid"); setWriteFields(stmt, lectureId, lecture, user); writeLocations(connection, lectureId, lecture.locationIds); + DbNetshare.writeNetworkShares(connection, lectureId, lecture.networkShares); stmt.executeUpdate(); } @@ -274,10 +278,11 @@ public class DbLecture { + " l.autoupdate, l.isenabled, l.starttime, l.endtime, l.lastused, l.usecount, l.createtime," + " l.updatetime, l.ownerid, l.updaterid, l.runscript, l.nics, l.netrules, l.isexam," + " l.isprivate, l.islocationprivate, l.hasinternetaccess, l.hasusbaccess," - + " l.caneditdefault, l.canadmindefault, p.canedit, p.canadmin" + + " l.caneditdefault, l.canadmindefault, p.canedit, p.canadmin, n.sharedata" + " FROM lecture l " + " LEFT JOIN imageversion i USING (imageversionid)" + " LEFT JOIN lecturepermission p ON (l.lectureid = p.lectureid AND p.userid = :userid)" + + " LEFT JOIN networkshare n ON (l.lectureid = n.lectureid)" + " WHERE l.lectureid = :lectureid LIMIT 1"); stmt.setString("userid", user == null ? "" : user.userId); stmt.setString("lectureid", lectureId); @@ -323,6 +328,7 @@ public class DbLecture { lecture.setUserPermissions(DbLecturePermissions.fromResultSetUser(rs)); User.setCombinedUserPermissions(lecture, user); lecture.setLocationIds(DbLocation.getLectureLocations(connection, lectureId)); + lecture.setNetworkShares(DbNetshare.getLectureNetshares(connection, lectureId)); return lecture; } catch (SQLException e) { LOGGER.error("Query failed in DbLecture.getLectureDetails()", e); diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbNetshare.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbNetshare.java new file mode 100644 index 00000000..af8b3fdc --- /dev/null +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbNetshare.java @@ -0,0 +1,61 @@ +package org.openslx.bwlp.sat.database.mappers; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.openslx.bwlp.sat.database.Database; +import org.openslx.bwlp.sat.database.MysqlConnection; +import org.openslx.bwlp.sat.database.MysqlStatement; +import org.openslx.bwlp.thrift.iface.NetShare; +import org.openslx.util.Json; + +public class DbNetshare { + + private static final Logger LOGGER = Logger.getLogger(DbNetshare.class); + + public static void writeNetworkShares(MysqlConnection connection, String lectureId, List<NetShare> shares) + throws SQLException { + if (shares == null || shares.isEmpty() || lectureId == null || lectureId.isEmpty()) { + return; + } + MysqlStatement delStmt = connection.prepareStatement("DELETE FROM networkshare WHERE lectureid = :lectureid"); + delStmt.setString("lectureid", lectureId); + delStmt.executeUpdate(); + + MysqlStatement addStmt = connection + .prepareStatement("INSERT IGNORE INTO networkshare (shareid, lectureid, shareuid, sharedata)" + + " VALUES (DEFAULT, :lectureid, NULL, :sharedata)"); + addStmt.setString("lectureid", lectureId); + for (NetShare share : shares) { + String netshareJson = Json.serialize(share); + addStmt.setString("sharedata", netshareJson); + addStmt.executeUpdate(); + } + } + + public static List<NetShare> getLectureNetshares(String lectureId) throws SQLException { + try (MysqlConnection connection = Database.getConnection()) { + return getLectureNetshares(connection, lectureId); + } catch (SQLException e) { + LOGGER.error("Query failed in DbLecture.getLectureDetails()", e); + throw e; + } + } + + public static List<NetShare> getLectureNetshares(MysqlConnection connection, String lectureId) throws SQLException { + List<NetShare> list = new ArrayList<>(); + MysqlStatement netsharestmt = connection + .prepareStatement("SELECT sharedata FROM networkshare WHERE lectureid = :lectureid"); + netsharestmt.setString("lectureid", lectureId); + ResultSet rs = netsharestmt.executeQuery(); + while (rs.next()) { + // TODO get the shares saved on slx-admin, if any shareuid aren't null + list.add(Json.deserializeThrift(rs.getString("sharedata"), NetShare.class)); + } + return list; + } + +} diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebServer.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebServer.java index e369f162..111578d3 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebServer.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebServer.java @@ -3,14 +3,18 @@ package org.openslx.bwlp.sat.web; import java.io.ByteArrayInputStream; import java.io.IOException; import java.sql.SQLException; +import java.util.List; import java.util.Map; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.log4j.Logger; import org.openslx.bwlp.sat.database.mappers.DbLecture; +import org.openslx.bwlp.sat.database.mappers.DbNetshare; import org.openslx.bwlp.sat.fileserv.FileServer; import org.openslx.bwlp.thrift.iface.LectureRead; import org.openslx.bwlp.thrift.iface.NetRule; +import org.openslx.bwlp.thrift.iface.NetShare; +import org.openslx.bwlp.thrift.iface.NetShareAuth; import org.openslx.bwlp.thrift.iface.TNotFoundException; import org.openslx.util.Json; import org.openslx.util.vm.VmMetaData; @@ -94,6 +98,8 @@ public class WebServer extends NanoHTTPD { return serveLectureStart(parts[2]); if (parts[3].equals("netrules")) return serveLectureNetRules(parts[2]); + if (parts[3].equals("netshares")) + return serveLectureNetshares(parts[2]); if (parts[3].equals("runscript")) return serveLectureScript(parts[2]); } @@ -188,6 +194,43 @@ public class WebServer extends NanoHTTPD { lecture.runscript); } + private Response serveLectureNetshares(String lectureId) { + List<NetShare> list = null; + try { + list = DbNetshare.getLectureNetshares(lectureId); + // TODO handling not found necessary? + } catch (SQLException e) { + return internalServerError(); + } + // TODO format expected from the client-side to + // handle different types of login. Currently: + // * no username nor password => use credentials of logged in user + // * username set, no password => guest mode + // * username and password set => user-specificed credentials + StringBuilder sb = new StringBuilder(); + if (!list.isEmpty()) { + for (NetShare share : list) { + sb.append(share.path); + if (share.auth == NetShareAuth.LOGIN_USER) { + // nothing to do + } + if (share.auth == NetShareAuth.GUEST_USER) { + sb.append(' '); + sb.append(share.username); + } + if (share.auth == NetShareAuth.SPECIAL_USER) { + sb.append(' '); + sb.append(share.username); + sb.append(' '); + sb.append(share.password); // TODO fixme + } + sb.append("\n"); + } + } + return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "text/plain; charset=utf-8", + sb.toString()); + } + /** * Return full list of lectures matching given location(s). * @@ -229,5 +272,4 @@ public class WebServer extends NanoHTTPD { } return new NanoHTTPD.Response(NanoHTTPD.Response.Status.BAD_REQUEST, "text/plain", message); } - } |