Commit 375a2580 authored by Staiger, Christine's avatar Staiger, Christine
Browse files

Merge branch 'anonymousAccess' into 'master'

- Adding ticket creation to irodsConnector and irodsConnectorIcommands

See merge request rdm-infrastructure/irods-clients!9
parents ab067979 88ba1fe1
......@@ -105,7 +105,7 @@ The client works on Mac, Windows and Linux distributions. On Mac and Windows it
## Usage
```
./irods-basicGui.py
./irods-iBridgesGui.py
```
## Remarks
......
......@@ -44,7 +44,6 @@ class dataTransfer(QDialog):
self.confirmBtn.setEnabled(False)
self.loading_movie = QMovie("gui/icons/loading_circle.gif")
#loading_movie.setScaledSize(size)
self.loadingLbl.setMovie(self.loading_movie)
self.loading_movie.start()
......@@ -63,7 +62,12 @@ class dataTransfer(QDialog):
def cancel(self):
print("Thread stopped")
self.finished.emit(False, None)
try: # if thread is still running
self.thread.exit(1)
except:
pass
self.close()
......@@ -84,7 +88,7 @@ class dataTransfer(QDialog):
else:
self.statusLbl.setText(
"Downloading... this might take a while. \nStarted "+\
str(now.date())+" "+str(now.time().hour)+":"+str(now.time().minute))
now.strftime('%Y-%m-%d %H:%M'))
self.thread = QThread()
if len(self.diff)+len(self.addFiles) == 0:
self.statusLbl.setText("Nothing to update.")
......@@ -112,13 +116,14 @@ class dataTransfer(QDialog):
# Callback for the getDataSize worker
def updateUiWithDataState(self, addFiles, diff, addSize, updateSize):
self.updateSize = updateSize
print(int(addSize), int(updateSize))
#checksumSizeStr = self.bytesToStr(updateSize)
self.ChecksumSizeLbl.setText(self.bytesToStr(updateSize))
self.ChecksumSizeLbl.setText(self.bytesToStr(int(updateSize)))
self.diff = diff
self.addSize = addSize
#newSizeStr = self.bytesToStr(addSize)
self.newFSizeLbl.setText(self.bytesToStr(addSize))
self.newFSizeLbl.setText(self.bytesToStr(int(addSize)))
self.addFiles = addFiles
self.loading_movie.stop()
......@@ -128,7 +133,7 @@ class dataTransfer(QDialog):
def bytesToStr(self, bytes):
bytes = bytes / (1024**3)
bytes = bytes / (1000**3)
if bytes < 1000:
bytesStr = f"{round(bytes, 3)} GB"
else:
......@@ -154,7 +159,7 @@ class dataTransfer(QDialog):
class getDataState(QObject):
# Signals
updLabels = pyqtSignal(int, int) # Num files
finished = pyqtSignal(list, list, int, int) # Lists with size in bytes
finished = pyqtSignal(list, list, str, str) # Lists with size in bytes
def __init__(self, ic, localFsPath, coll, upload):
super(getDataState, self).__init__()
......@@ -163,6 +168,7 @@ class getDataState(QObject):
self.coll = coll
self.upload = upload
def run(self):
# Diff
diff, onlyFS, onlyIrods, same = [], [], [], []
......@@ -192,24 +198,34 @@ class getDataState(QObject):
FsPath = newPath
(diff, onlyFS, onlyIrods, same) = self.ic.diffIrodsLocalfs(
self.coll, FsPath, scope="checksum")
elif self.ic.session.data_objects.exists(self.coll.path):
#elif self.ic.session.data_objects.exists(self.coll.path):
else:
(diff, onlyFS, onlyIrods, same) = self.ic.diffObjFile(
self.coll.path, newPath, scope="checksum")
self.updLabels.emit(len(onlyIrods), len(diff))
except:
logging.exception("dataTransfer.py: Error in getDataState")
# Get size
if self.upload == True:
fsDiffFiles = [d[1] for d in diff]
updateSize = getSize(fsDiffFiles)
addSize = getSize(onlyFS)
self.finished.emit(onlyFS, diff, addSize, updateSize)
fullOnlyFsPaths = [self.localFsPath+os.sep+d for d in onlyFS
if not d.startswith('/') or ':' not in d]
fullOnlyFsPaths.extend([d for d in onlyFS
if d.startswith('/') or ':' in d])
addSize = getSize(fullOnlyFsPaths)
print(str(fsDiffFiles)+" "+str(updateSize))
print(str(onlyFS)+" "+str(addSize))
self.finished.emit(onlyFS, diff, str(addSize), str(updateSize))
else:
irodsDiffFiles = [d[0] for d in diff]
updateSize = self.ic.getSize(irodsDiffFiles)
addSize = self.ic.getSize(onlyIrods)
self.finished.emit(onlyIrods, diff, addSize, updateSize)
onlyIrodsFullPath = onlyIrods.copy()
for i in range(len(onlyIrodsFullPath)):
if not onlyIrods[i].startswith(self.coll.path):
onlyIrodsFullPath[i] = self.coll.path+'/'+ onlyIrods[i]
addSize = self.ic.getSize(onlyIrodsFullPath)
self.finished.emit(onlyIrods, diff, str(addSize), str(updateSize))
# Background worker for the up/download
......
......@@ -217,7 +217,7 @@ class elabUpload():
self.elnUploadButton.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
except Exception as e:
logging.info("ElabUpload UploadData: "+repr(error))
logging.info("ElabUpload UploadData: "+repr(e))
self.errorLabel.setText(repr(e))
self.elnUploadButton.setEnabled(True)
self.elnUploadButton.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
......@@ -261,7 +261,7 @@ class Worker(QObject):
self.progress.emit(3)
self.finished.emit()
except Exception as e:
logging.info("ElabUpload data upload and annotation worker: "+repr(error))
logging.info("ElabUpload data upload and annotation worker: "+repr(e))
print(repr(e))
self.annotateElab()
......
......@@ -284,10 +284,10 @@ class irodsBrowser():
self.__clearErrorLabel()
self.__clearViewTabs()
self.widget.metadataTable.setRowCount(0);
self.widget.aclTable.setRowCount(0);
self.widget.resourceTable.setRowCount(0);
self.widget.metadataTable.setRowCount(0)
self.widget.aclTable.setRowCount(0)
self.widget.resourceTable.setRowCount(0)
col = index.column()
row = index.row()
self.currentBrowserRow = row
......@@ -413,7 +413,7 @@ class irodsBrowser():
self.widget.errorLabel.setText(
"IRODS NETWORK ERROR: No Connection, please check network")
except Exception as error:
print("ERROR upload :", fileSelect[0], "failed; \n\t", repr(error))
print("ERROR download :", parent+'/'+objName, "failed; \n\t", repr(error))
self.widget.errorLabel.setText(repr(error))
......
from PyQt5 import QtGui, QtCore
from gui.irodsTreeView import IrodsModel
class irodsCreateTicket():
def __init__(self, widget, ic, ienv):
self.ic = ic
self.widget = widget
self.irodsmodel = IrodsModel(ic, self.widget.irodsFsTreeView)
self.widget.irodsFsTreeView.setModel(self.irodsmodel)
self.irodsRootColl = '/'+ic.session.zone
self.irodsmodel.setHorizontalHeaderLabels([self.irodsRootColl,
'Level', 'iRODS ID',
'parent ID', 'type'])
self.widget.irodsFsTreeView.expanded.connect(self.irodsmodel.refreshSubTree)
self.widget.irodsFsTreeView.clicked.connect(self.irodsmodel.refreshSubTree)
self.irodsmodel.initTree()
self.widget.irodsFsTreeView.setHeaderHidden(True)
self.widget.irodsFsTreeView.header().setDefaultSectionSize(180)
self.widget.irodsFsTreeView.setColumnHidden(1, True)
self.widget.irodsFsTreeView.setColumnHidden(2, True)
self.widget.irodsFsTreeView.setColumnHidden(3, True)
self.widget.irodsFsTreeView.setColumnHidden(4, True)
self.widget.createTicketButton.clicked.connect(self.createTicket)
def createTicket(self):
self.widget.infoLabel.clear()
self.widget.ticketInfoBrowser.clear()
self.widget.setCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
self.widget.createTicketButton.setEnabled(False)
#gather info
idx, path = self.irodsmodel.get_checked()
if path == None or self.ic.session.data_objects.exists(path):
self.widget.infoLabel.setText("ERROR: Please select a collection.")
self.widget.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.widget.createTicketButton.setEnabled(True)
return
acls = [(acl.user_name, acl.access_name) for acl in self.ic.getPermissions(path)]
if (self.ic.session.username, "own") in acls:
date = self.widget.calendar.selectedDate()
#format of time string for irods: 2012-05-07.23:00:00
expiryString = str(date.toPyDate())+'.23:59:59'
ticket, expiryDate = self.ic.createTicket(path, expiryString)
self.widget.ticketInfoBrowser.append("iRODS server: \t"+self.ic.session.host)
self.widget.ticketInfoBrowser.append("iRODS path:\t"+path)
self.widget.ticketInfoBrowser.append("iRODS Ticket:\t"+ticket)
if self.ic.__name__ == "irodsConnector":
self.widget.ticketInfoBrowser.append("Expiry date:\tNot set (linux only)")
else:
self.widget.ticketInfoBrowser.append("Expiry date:\t"+expiryDate)
else:
self.widget.infoLabel.setText("ERROR: Insufficient rights, you need to be owner.")
self.widget.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.widget.createTicketButton.setEnabled(True)
return
self.widget.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.widget.createTicketButton.setEnabled(True)
......@@ -142,9 +142,9 @@ class irodsDataCompression():
def dataCreateExtractFinished(self, success, message, operation):
self.widget.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.enableButtons(True)
stdout, stderr = message
if success and operation == "create":
idx, source = self.collectionTreeModel.get_checked()
stdout, stderr = message
self.widget.createStatusLabel.setText("STATUS: Created " + str(stdout))
parentIdx = self.collectionTreeModel.getParentIdx(idx)
self.collectionTreeModel.refreshSubTree(parentIdx)
......@@ -163,7 +163,8 @@ class irodsDataCompression():
def unpackDataBundle(self):
self.widget.setCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
idx, source = self.compressionTreeModel.get_checked()
if not source.endswith(".irods.tar") and not source.endswith(".irods.zip"):
if not idx or (not source.endswith(".irods.tar") and not source.endswith(".irods.zip")):
self.widget.unpackStatusLabel.setText("ERROR: No *.irods.tar or *.irods.zip selected")
self.widget.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
return
......
......@@ -3,6 +3,7 @@ from PyQt5.QtWidgets import QDialog, QMessageBox
from PyQt5.uic import loadUi
import os
from utils.utils import getDownloadDir
import logging
class irodsSearch(QDialog):
def __init__(self, ic, collTable):
......
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QHeaderView, QMessageBox
from PyQt5 import QtCore
from PyQt5.uic import loadUi
from utils.irodsConnectorAnonymous import irodsConnectorAnonymous
from gui.checkableFsTree import checkableFsTreeModel
from gui.popupWidgets import createDirectory
from gui.dataTransfer import dataTransfer
import os
class irodsTicketLogin():
def __init__(self, widget):
self.ic = None
self.coll = None
self.widget = widget
# QTreeViews
self.dirmodel = checkableFsTreeModel(self.widget.localFsTreeView)
self.widget.localFsTreeView.setModel(self.dirmodel)
# Hide all columns except the Name
self.widget.localFsTreeView.setColumnHidden(1, True)
self.widget.localFsTreeView.setColumnHidden(2, True)
self.widget.localFsTreeView.setColumnHidden(3, True)
self.widget.localFsTreeView.header().setSectionResizeMode(QHeaderView.ResizeToContents)
home_location = QtCore.QStandardPaths.standardLocations(
QtCore.QStandardPaths.HomeLocation)[0]
index = self.dirmodel.setRootPath(home_location)
self.widget.localFsTreeView.setCurrentIndex(index)
self.dirmodel.initial_expand()
self.widget.connectButton.clicked.connect(self.irodsSession)
self.widget.homeButton.clicked.connect(self.loadTable)
self.widget.createDirectoryButton.clicked.connect(self.createFolder)
self.widget.downloadButton.clicked.connect(self.download)
self.widget.downloadAllButton.clicked.connect(self.downloadAll)
self.widget.collTable.doubleClicked.connect(self.browse)
self.widget.collTable.clicked.connect(self.fillInfo)
self.enableButtons(False)
self.widget.connectButton.setEnabled(True)
def irodsSession(self):
self.widget.infoLabel.clear()
host = self.widget.serverEdit.text().strip()
path = self.widget.pathEdit.text().strip()
token = self.widget.ticketEdit.text().strip()
try:
self.ic = irodsConnectorAnonymous(host, token, path)
self.coll = self.ic.getData()
self.loadTable()
self.enableButtons(True)
except Exception as e:
self.widget.infoLabel.setText("LOGIN ERROR: Check ticket and iRODS path.\n"+repr(e))
def enableButtons(self, enable):
self.widget.connectButton.setEnabled(enable)
self.widget.homeButton.setEnabled(enable)
self.widget.createDirectoryButton.setEnabled(enable)
self.widget.downloadButton.setEnabled(enable)
self.widget.downloadAllButton.setEnabled(enable)
self.widget.localFsTreeView.setEnabled(enable)
def loadTable(self, update = None):
self.widget.infoLabel.clear()
if self.coll == None:
self.widget.infoLabel.setText("No data avalaible. Check ticket and iRODS path.")
return
if update == None or update == False:
update = self.coll
self.widget.collTable.setRowCount(0)
self.widget.collTable.setRowCount(len(update.subcollections)+len(update.data_objects))
row = 0
for subcoll in update.subcollections:
self.widget.collTable.setItem(row, 0,
QtWidgets.QTableWidgetItem(os.path.dirname(subcoll.path)))
self.widget.collTable.setItem(row, 1,
QtWidgets.QTableWidgetItem(subcoll.name+"/"))
self.widget.collTable.setItem(1, 2, QtWidgets.QTableWidgetItem(""))
self.widget.collTable.setItem(1, 3, QtWidgets.QTableWidgetItem(""))
row = row + 1
for obj in update.data_objects:
self.widget.collTable.setItem(row, 0,
QtWidgets.QTableWidgetItem(os.path.dirname(obj.path)))
self.widget.collTable.setItem(row, 1, QtWidgets.QTableWidgetItem(obj.name))
self.widget.collTable.setItem(row, 2, QtWidgets.QTableWidgetItem(str(obj.size)))
self.widget.collTable.setItem(row, 3, QtWidgets.QTableWidgetItem(str(obj.checksum)))
self.widget.collTable.setItem(row, 4,
QtWidgets.QTableWidgetItem(str(obj.modify_time)))
row = row+1
self.widget.collTable.resizeColumnsToContents()
def browse(self, index):
self.widget.infoLabel.clear()
col = index.column()
row = index.row()
if self.widget.collTable.item(row, 0).text() != '':
path = self.widget.collTable.item(row, 0).text()
item = self.widget.collTable.item(row, 1).text()
if item.endswith('/'):
item = item[:-1]
if self.ic.session.collections.exists(path+'/'+item):
coll = self.ic.session.collections.get(path+'/'+item)
self.loadTable(update = coll)
def fillInfo(self, index):
self.widget.previewBrowser.clear()
self.widget.metadataTable.setRowCount(0)
row = index.row()
value = self.widget.collTable.item(row, 1).text()
path = self.widget.collTable.item(row, 0).text()
try:
self.__fillPreview(value, path)
self.__fillMetadata(value, path)
except Exception as e:
self.widget.infoLabel.setText(repr(e))
raise
def __fillPreview(self, value, path):
newPath = "/"+path.strip("/")+"/"+value.strip("/")
if self.ic.session.collections.exists(newPath): # collection
coll = self.ic.session.collections.get(newPath)
content = ['Collections:', '-----------------'] +\
[c.name+'/' for c in coll.subcollections] + \
['\n', 'Data:', '-----------------']+\
[o.name for o in coll.data_objects]
previewString = '\n'.join(content)
self.widget.previewBrowser.append(previewString)
else: # object
subcoll = self.ic.session.collections.get(path)
obj = [o for o in subcoll.data_objects if o.name == value][0]
# get mimetype
mimetype = value.split(".")[len(value.split("."))-1]
if mimetype in ['txt', 'json', 'csv']:
try:
out = []
with obj.open('r') as readObj:
for i in range(20):
out.append(readObj.read(50))
previewString = ''.join([line.decode('utf-8') for line in out])
self.widget.previewBrowser.append(previewString)
except Exception as e:
self.widget.previewBrowser.append(obj.path)
self.widget.previewBrowser.append(repr(e))
self.widget.previewBrowser.append("Storage resource might be down.")
else:
self.widget.previewBrowser.append("No preview for "+obj.path)
def __fillMetadata(self, value, path):
newPath = "/"+path.strip("/")+"/"+value.strip("/")
metadata = []
if value.endswith("/") and self.ic.session.collections.exists(newPath):
coll = self.ic.session.collections.get(
"/"+path.strip("/")+"/"+value.strip("/")
)
metadata = coll.metadata.items()
else:
subcoll = self.ic.session.collections.get(path)
obj = [o for o in subcoll.data_objects if o.name == value][0]
metadata = obj.metadata.items()
self.widget.metadataTable.setRowCount(len(metadata))
row = 0
for item in metadata:
self.widget.metadataTable.setItem(row, 0,
QtWidgets.QTableWidgetItem(item.name))
self.widget.metadataTable.setItem(row, 1,
QtWidgets.QTableWidgetItem(item.value))
self.widget.metadataTable.setItem(row, 2,
QtWidgets.QTableWidgetItem(item.units))
row = row+1
self.widget.metadataTable.resizeColumnsToContents()
def createFolder(self):
self.widget.infoLabel.clear()
parent = self.dirmodel.get_checked()
if parent == None:
self.widget.infoLabel.setText("No parent folder selected.")
else:
createDirWidget = createDirectory(parent)
createDirWidget.exec_()
#self.dirmodel.initial_expand(previous_item = parent)
def downloadAll(self):
self.download(allData = True)
def download(self, allData = False):
#irods data
self.enableButtons(False)
self.widget.infoLabel.clear()
if allData:
collPath = os.path.dirname(self.coll.path)
dataName = self.coll.name.strip('/')
elif self.widget.collTable.selectedIndexes():
row = self.widget.collTable.selectedIndexes()[0].row()
if row == -1:
self.widget.infoLabel.setText("No iRODS data selected.")
self.enableButtons(True)
return
else:
collPath = self.widget.collTable.item(row, 0).text()
dataName = self.widget.collTable.item(row, 1).text().strip('/')
else:
self.widget.infoLabel.setText("No iRODS data selected.")
self.enableButtons(True)
return
#fielsystem data
destination = self.dirmodel.get_checked()
if destination == None or os.path.isfile(destination):
self.widget.infoLabel.setText("No download folder selected.")
self.enableButtons(True)
return
if self.ic.session.collections.exists(collPath+'/'+dataName):
item = self.ic.session.collections.get(collPath+'/'+dataName)
else: #data object with workaround for bug
parent = self.ic.session.collections.get(collPath)
item = [obj for obj in parent.data_objects if obj.name == dataName][0]
self.downloadWindow = dataTransfer(self.ic, False, destination, item)
self.downloadWindow.finished.connect(self.finishedTransfer)
def finishedTransfer(self, succes, irodsIdx):
#Refreshes iRODS sub tree ad irodsIdx (set "None" if to skip)
#Saves upload parameters if check box is set
if succes == True:
self.widget.infoLabel.setText("INFO UPLOAD/DOWLOAD: completed.")
self.uploadWindow = None # Release
self.enableButtons(True)
......@@ -63,6 +63,8 @@ class IrodsModel(QStandardItemModel):
reqAcls = [('own', path, group, self.ic.session.zone) for group in self.userGroups]
reqAcls.extend([('write', path, group, self.ic.session.zone) \
for group in self.userGroups])
reqAcls.extend([('read object', path, group, self.ic.session.zone) \
for group in self.userGroups])
acls = set([(acl.access_name, acl.path, acl.user_name, acl.user_zone)
for acl in self.ic.getPermissions(path)])
......
......@@ -18,11 +18,6 @@ class irodsUpDownload():
self.syncing = False # syncing or not
rescs = self.ic.listResources()
#if ic.defaultResc not in rescs:
# self.infoPopup('ERROR resource config: "default_resource_name" invalid:\n'\
# +ic.defaultResc \
# +'\nData Up and Download view not setup.')
# return
# QTreeViews
self.dirmodel = checkableFsTreeModel(self.widget.localFsTreeView)
......@@ -100,6 +95,17 @@ class irodsUpDownload():
self.widget.ContUplBut.hide()
def enableButtons(self, enable):
self.widget.UploadButton.setEnabled(enable)
self.widget.DownloadButton.setEnabled(enable)
self.widget.ContUplBut.setEnabled(enable)
self.widget.uplSetGB_2.setEnabled(enable)
self.widget.createFolderButton.setEnabled(enable)
self.widget.createCollButton.setEnabled(enable)
self.widget.localFsTreeView.setEnabled(enable)
self.widget.localFsTreeView.setEnabled(enable)
def infoPopup(self, message):
QMessageBox.information(self.widget, 'Information', message)
......@@ -148,15 +154,18 @@ class irodsUpDownload():
# Upload a file/folder to IRODS and refresh the TreeView
def upload(self):
self.enableButtons(False)
self.widget.errorLabel.clear()
(fsSource, irodsDestIdx, irodsDestPath) = self.getPathsFromTrees()
if fsSource == None or irodsDestPath == None:
self.widget.errorLabel.setText(
"ERROR Up/Download: Please select source and destination.")
self.enableButtons(True)
return
if not self.ic.session.collections.exists(irodsDestPath):
self.widget.errorLabel.setText(
"ERROR UPLOAD: iRODS destination is file, must be collection.")
self.enableButtons(True)
return
destColl = self.ic.session.collections.get(irodsDestPath)
#if os.path.isdir(fsSource):
......@@ -176,18 +185,22 @@ class irodsUpDownload():
self.saveUIset()
self.widget.errorLabel.setText("INFO UPLOAD/DOWLOAD: completed.")
self.uploadWindow = None # Release
self.enableButtons(True)
def download(self):
self.enableButtons(False)
self.widget.errorLabel.clear()
(fsDest, irodsSourceIdx, irodsSourcePath) = self.getPathsFromTrees()
if fsDest == None or irodsSourcePath == None:
self.widget.errorLabel.setText(
"ERROR Up/Download: Please select source and destination.")
self.enableButtons(True)
return
if os.path.isfile(fsDest):
self.widget.errorLabel.setText(
"ERROR DOWNLOAD: Local Destination is file, must be folder.")
self.enableButtons(True)
return
# File
if self.ic.session.data_objects.exists(irodsSourcePath):
......
......@@ -11,6 +11,8 @@ from gui.irodsSearch import irodsSearch
from gui.irodsUpDownload import irodsUpDownload
from gui.irodsDataCompression import irodsDataCompression
from gui.irodsInfo import irodsInfo
from gui.irodsCreateTicket import irodsCreateTicket
from gui.irodsTicketLogin import irodsTicketLogin
from utils.utils import saveIenv