diff options
-rw-r--r-- | module/Api.py | 181 | ||||
-rw-r--r-- | module/database/DatabaseBackend.py | 34 | ||||
-rw-r--r-- | module/database/FileDatabase.py | 38 | ||||
-rw-r--r-- | module/remote/socketbackend/ttypes.py | 41 | ||||
-rw-r--r-- | module/remote/thriftbackend/pyload.thrift | 83 | ||||
-rwxr-xr-x | module/remote/thriftbackend/thriftgen/pyload/Pyload-remote | 44 | ||||
-rw-r--r-- | module/remote/thriftbackend/thriftgen/pyload/Pyload.py | 364 | ||||
-rw-r--r-- | module/remote/thriftbackend/thriftgen/pyload/ttypes.py | 108 | ||||
-rw-r--r-- | module/web/utils.py | 14 |
9 files changed, 675 insertions, 232 deletions
diff --git a/module/Api.py b/module/Api.py index c969045f8..bab039ea1 100644 --- a/module/Api.py +++ b/module/Api.py @@ -52,7 +52,7 @@ perm_map = {} user_context = {} # decorator only called on init, never initialized, so has no effect on runtime -def permission(bits): +def RequirePerm(bits): class _Dec(object): def __new__(cls, func, *args, **kwargs): perm_map[func.__name__] = bits @@ -100,27 +100,9 @@ class UserContext(object): urlmatcher = re.compile(r"((https?|ftps?|xdcc|sftp):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-=\\\.&]*)", re.IGNORECASE) -class PERMS: - ALL = 0 # requires no permission, but login - ADD = 1 # can add packages - DELETE = 2 # can delete packages - STATUS = 4 # see and change server status - LIST = 16 # see listed downloads - MODIFY = 32 # moddify some attribute of downloads - DOWNLOAD = 64 # can download from webinterface - SETTINGS = 128 # can access settings - ACCOUNTS = 256 # can access accounts - LOGS = 512 # can see server logs - INTERACTION = 1024 # can interact with plugins - -class ROLE: - ADMIN = 0 #admin has all permissions implicit - USER = 1 - - -def has_permission(userperms, perms): - return bits_set(perms, userperms) +def has_permission(userPermission, Permission): + return bits_set(Permission, userPermission) class UserApi(object): @@ -157,13 +139,13 @@ class Api(Iface): def __init__(self, core): self.core = core - self.t = self.inUserContext("TestUser") + self.t = self.withUserContext("TestUser") print self.t.getServerVersion() # TODO, create user instance, work - def inUserContext(self, user): + def withUserContext(self, user): """ Returns a proxy version of the api, to call method in user context :param user: user id @@ -177,13 +159,13 @@ class Api(Iface): ########################## @UserContext #TODO: only for testing - @permission(PERMS.ALL) + @RequirePerm(Permission.All) def getServerVersion(self): """pyLoad Core version """ print user return self.core.version - @permission(PERMS.LIST) + @RequirePerm(Permission.List) def statusServer(self): """Some general information about the current status of pyLoad. @@ -199,17 +181,17 @@ class Api(Iface): return serverStatus - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def pauseServer(self): """Pause server: It won't start any new downloads, but nothing gets aborted.""" self.core.threadManager.pause = True - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def unpauseServer(self): """Unpause server: New Downloads will be started.""" self.core.threadManager.pause = False - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def togglePause(self): """Toggle pause state. @@ -218,7 +200,7 @@ class Api(Iface): self.core.threadManager.pause ^= True return self.core.threadManager.pause - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def toggleReconnect(self): """Toggle reconnect activation. @@ -227,7 +209,7 @@ class Api(Iface): self.core.config["reconnect"]["activated"] ^= True return self.core.config["reconnect"]["activated"] - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def freeSpace(self): """Available free space at download directory in bytes""" return free_space(self.core.config["general"]["download_folder"]) @@ -241,7 +223,6 @@ class Api(Iface): """Restart pyload core""" self.core.do_restart = True - @permission(PERMS.LOGS) def getLog(self, offset=0): """Returns most recent log entries. @@ -259,7 +240,7 @@ class Api(Iface): except: return ['No log available'] - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def isTimeDownload(self): """Checks if pyload will start new downloads according to time in config. @@ -269,7 +250,7 @@ class Api(Iface): end = self.core.config['downloadTime']['end'].split(":") return compare_time(start, end) - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def isTimeReconnect(self): """Checks if pyload will try to make a reconnect @@ -283,7 +264,7 @@ class Api(Iface): def scanDownloadFolder(self): pass - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def getProgressInfo(self): """ Status of all currently running tasks @@ -306,7 +287,6 @@ class Api(Iface): # Configuration ########################## - @permission(PERMS.SETTINGS) def getConfigValue(self, section, option): """Retrieve config value. @@ -317,7 +297,6 @@ class Api(Iface): value = self.core.config.get(section, option) return to_string(value) - @permission(PERMS.SETTINGS) def setConfigValue(self, section, option, value): """Set new config value. @@ -330,7 +309,6 @@ class Api(Iface): self.core.config.set(section, option, value) - @permission(PERMS.SETTINGS) def getConfig(self): """Retrieves complete config of core. @@ -343,7 +321,6 @@ class Api(Iface): section, data in self.core.config.getBaseSections()]) - @permission(PERMS.SETTINGS) def getPluginConfig(self): """Retrieves complete config for all plugins. @@ -353,7 +330,6 @@ class Api(Iface): data.name, data.description, data.long_desc)) for section, data in self.core.config.getPluginSections()]) - @permission(PERMS.SETTINGS) def configureSection(self, section): data = self.core.config.config[section] sec = ConfigSection(section, data.name, data.description, data.long_desc) @@ -367,7 +343,6 @@ class Api(Iface): return sec - @permission(PERMS.SETTINGS) def setConfigHandler(self, plugin, iid, value): pass @@ -379,7 +354,7 @@ class Api(Iface): # Download Preparing ########################## - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def parseURLs(self, html=None, url=None): """Parses html content or any arbitrary text for links and returns result of `checkURLs` @@ -399,7 +374,7 @@ class Api(Iface): return self.checkURLs(set(urls)) - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def checkURLs(self, urls): """ Gets urls and returns pluginname mapped to list of matching urls. @@ -417,7 +392,7 @@ class Api(Iface): return plugins - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def checkOnlineStatus(self, urls): """ initiates online status check, will also decrypt files. @@ -441,7 +416,7 @@ class Api(Iface): return OnlineCheck(rid, result) - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def checkOnlineStatusContainer(self, urls, container, data): """ checks online status of urls and a submitted container file @@ -456,7 +431,7 @@ class Api(Iface): urls.append(th.name) return self.checkOnlineStatus(urls) - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def pollResults(self, rid): """ Polls the result available for ResultID @@ -472,7 +447,7 @@ class Api(Iface): return OnlineCheck(rid, result) - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def generatePackages(self, links): """ Parses links, generates packages names from urls @@ -486,7 +461,7 @@ class Api(Iface): # Adding/Deleting ########################## - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def generateAndAddPackages(self, links, paused=False): """Generates and add packages @@ -497,11 +472,11 @@ class Api(Iface): return [self.addPackageP(name, urls, "", paused) for name, urls in self.generatePackages(links).iteritems()] - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def autoAddLinks(self, links): pass - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def createPackage(self, name, folder, root, password="", site="", comment="", paused=False): """Create a new package. @@ -526,7 +501,7 @@ class Api(Iface): return pid - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def addPackage(self, name, links, password=""): """Convenient method to add a package to the top-level and for adding links. @@ -534,12 +509,12 @@ class Api(Iface): """ self.addPackageChild(name, links, password, -1, False) - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def addPackageP(self, name, links, password, paused): """ Same as above with additional paused attribute. """ self.addPackageChild(name, links, password, -1, paused) - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def addPackageChild(self, name, links, password, root, paused): """Adds a package, with links to desired package. @@ -556,7 +531,7 @@ class Api(Iface): return pid - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def addLinks(self, pid, links): """Adds links to specific package. Initiates online status fetching. @@ -574,7 +549,7 @@ class Api(Iface): self.core.log.info((_("Added %d links to package") + " #%d" % pid) % len(hoster)) self.core.files.save() - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def uploadContainer(self, filename, data): """Uploads and adds a container file to pyLoad. @@ -587,7 +562,7 @@ class Api(Iface): return self.addPackage(th.name, [th.name]) - @permission(PERMS.DELETE) + @RequirePerm(Permission.Delete) def deleteFiles(self, fids): """Deletes several file entries from pyload. @@ -598,7 +573,7 @@ class Api(Iface): self.core.files.save() - @permission(PERMS.DELETE) + @RequirePerm(Permission.Delete) def deletePackages(self, pids): """Deletes packages and containing links. @@ -613,27 +588,27 @@ class Api(Iface): # Collector ########################## - @permission(PERMS.LIST) + @RequirePerm(Permission.List) def getCollector(self): pass - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def addToCollector(self, links): pass - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def addFromCollector(self, name, paused): pass - @permission(PERMS.DELETE) + @RequirePerm(Permission.Delete) def deleteCollPack(self, name): pass - @permission(PERMS.DELETE) + @RequirePerm(Permission.Delete) def deleteCollLink(self, url): pass - @permission(PERMS.ADD) + @RequirePerm(Permission.Add) def renameCollPack(self, name, new_name): pass @@ -641,17 +616,17 @@ class Api(Iface): # File Information retrival ############################# - @permission(PERMS.LIST) + @RequirePerm(Permission.List) def getAllFiles(self): """ same as `getFileTree` for toplevel root and full tree""" return self.getFileTree(-1, True) - @permission(PERMS.LIST) + @RequirePerm(Permission.List) def getAllUnfinishedFiles(self): """ same as `getUnfinishedFileTree for toplevel root and full tree""" return self.getUnfinishedFileTree(-1, True) - @permission(PERMS.LIST) + @RequirePerm(Permission.List) def getFileTree(self, pid, full): """ Retrieve data for specific package. full=True will retrieve all data available and can result in greater delays. @@ -662,7 +637,7 @@ class Api(Iface): """ return self.core.files.getView(pid, full, False) - @permission(PERMS.LIST) + @RequirePerm(Permission.List) def getUnfinishedFileTree(self, pid, full): """ Same as `getFileTree` but only contains unfinished files. @@ -672,12 +647,12 @@ class Api(Iface): """ return self.core.files.getView(pid, full, False) - @permission(PERMS.LIST) + @RequirePerm(Permission.List) def getPackageContent(self, pid): """ Only retrieve content of a specific package. see `getFileTree`""" return self.getFileTree(pid, False) - @permission(PERMS.LIST) + @RequirePerm(Permission.List) def getPackageInfo(self, pid): """Returns information about package, without detailed information about containing files @@ -690,7 +665,7 @@ class Api(Iface): raise PackageDoesNotExists(pid) return info - @permission(PERMS.LIST) + @RequirePerm(Permission.List) def getFileInfo(self, fid): """ Info for specific file @@ -704,7 +679,7 @@ class Api(Iface): raise FileDoesNotExists(fid) return info - @permission(PERMS.LIST) + @RequirePerm(Permission.List) def findFiles(self, pattern): pass @@ -712,7 +687,7 @@ class Api(Iface): # Modify Downloads ############################# - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def restartPackage(self, pid): """Restarts a package, resets every containing files. @@ -720,7 +695,7 @@ class Api(Iface): """ self.core.files.restartPackage(pid) - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def restartFile(self, fid): """Resets file status, so it will be downloaded again. @@ -728,12 +703,12 @@ class Api(Iface): """ self.core.files.restartFile(fid) - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def recheckPackage(self, pid): """Check online status of all files in a package, also a default action when package is added. """ self.core.files.reCheckPackage(pid) - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def stopAllDownloads(self): """Aborts all running downloads.""" @@ -741,7 +716,7 @@ class Api(Iface): for pyfile in pyfiles: pyfile.abortDownload() - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def stopDownloads(self, fids): """Aborts specific downloads. @@ -753,7 +728,7 @@ class Api(Iface): if pyfile.id in fids: pyfile.abortDownload() - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def restartFailed(self): """Restarts all failed failes.""" self.core.files.restartFailed() @@ -762,19 +737,19 @@ class Api(Iface): # Modify Files/Packages ############################# - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def setFilePaused(self, fid, paused): pass - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def setPackagePaused(self, pid, paused): pass - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def setPackageFolder(self, pid, path): pass - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def movePackage(self, pid, root): """ Set a new root for specific package. This will also moves the files on disk\ and will only work when no file is currently downloading. @@ -786,7 +761,7 @@ class Api(Iface): """ return self.core.files.movePackage(pid, root) - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def moveFiles(self, fids, pid): """Move multiple files to another package. This will move the files on disk and\ only work when files are not downloading. All files needs to be continuous ordered @@ -798,7 +773,7 @@ class Api(Iface): """ return self.core.files.moveFiles(fids, pid) - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def orderPackage(self, pid, position): """Set new position for a package. @@ -807,7 +782,7 @@ class Api(Iface): """ self.core.files.orderPackage(pid, position) - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def orderFiles(self, fids, pid, position): """ Set a new position for a bunch of files within a package. All files have to be in the same package and must be **continuous**\ @@ -819,7 +794,7 @@ class Api(Iface): """ self.core.files.orderFiles(fids, pid, position) - @permission(PERMS.MODIFY) + @RequirePerm(Permission.Modify) def setPackageData(self, pid, data): """Allows to modify several package attributes. @@ -840,7 +815,7 @@ class Api(Iface): # User Interaction ############################# - @permission(PERMS.INTERACTION) + @RequirePerm(Permission.Interaction) def isInteractionWaiting(self, mode): """ Check if task is waiting. @@ -849,7 +824,7 @@ class Api(Iface): """ return self.core.interactionManager.isTaskWaiting(mode) - @permission(PERMS.INTERACTION) + @RequirePerm(Permission.Interaction) def getInteractionTask(self, mode): """Retrieve task for specific mode. @@ -860,7 +835,7 @@ class Api(Iface): return InteractionTask(-1) if not task else task - @permission(PERMS.INTERACTION) + @RequirePerm(Permission.Interaction) def setInteractionResult(self, iid, result): """Set Result for a interaction task. It will be immediately removed from task queue afterwards @@ -871,7 +846,7 @@ class Api(Iface): if task: task.setResult(result) - @permission(PERMS.INTERACTION) + @RequirePerm(Permission.Interaction) def getNotifications(self): """List of all available notifcations. They stay in queue for some time, client should\ save which notifications it already has seen. @@ -880,15 +855,15 @@ class Api(Iface): """ return self.core.interactionManager.getNotifications() - @permission(PERMS.INTERACTION) + @RequirePerm(Permission.Interaction) def getAddonHandler(self): pass - @permission(PERMS.INTERACTION) + @RequirePerm(Permission.Interaction) def callAddonHandler(self, plugin, func, pid_or_fid): pass - @permission(PERMS.DOWNLOAD) + @RequirePerm(Permission.Download) def generateDownloadLink(self, fid, timeout): pass @@ -896,7 +871,7 @@ class Api(Iface): # Event Handling ############################# - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def getEvents(self, uuid): """Lists occured events, may be affected to changes in future. @@ -910,7 +885,7 @@ class Api(Iface): # Account Methods ############################# - @permission(PERMS.ACCOUNTS) + @RequirePerm(Permission.Accounts) def getAccounts(self, refresh): """Get information about all entered accounts. @@ -924,7 +899,7 @@ class Api(Iface): return accounts - @permission(PERMS.ALL) + @RequirePerm(Permission.All) def getAccountTypes(self): """All available account types. @@ -932,12 +907,12 @@ class Api(Iface): """ return self.core.pluginManager.getPlugins("accounts").keys() - @permission(PERMS.ACCOUNTS) + @RequirePerm(Permission.Accounts) def updateAccount(self, plugin, account, password=None, options={}): """Changes pw/options for specific account.""" self.core.accountManager.updateAccount(plugin, account, password, options) - @permission(PERMS.ACCOUNTS) + @RequirePerm(Permission.Accounts) def removeAccount(self, plugin, account): """Remove account from pyload. @@ -950,7 +925,7 @@ class Api(Iface): # Auth+User Information ############################# - @permission(PERMS.ALL) + @RequirePerm(Permission.All) def login(self, username, password, remoteip=None): """Login into pyLoad, this **must** be called when using rpc before any methods can be used. @@ -993,7 +968,7 @@ class Api(Iface): return False - @permission(PERMS.ALL) + @RequirePerm(Permission.All) def getUserData(self, username, password): """similar to `checkAuth` but returns UserData thrift type """ user = self.checkAuth(username, password) @@ -1022,7 +997,7 @@ class Api(Iface): # RPC Plugin Methods ############################# - @permission(PERMS.INTERACTION) + @RequirePerm(Permission.Interaction) def getServices(self): """ A dict of available services, these can be defined by addon plugins. @@ -1034,11 +1009,11 @@ class Api(Iface): return data - @permission(PERMS.INTERACTION) + @RequirePerm(Permission.Interaction) def hasService(self, plugin, func): pass - @permission(PERMS.INTERACTION) + @RequirePerm(Permission.Interaction) def call(self, plugin, func, arguments): """Calls a service (a method in addon plugin). @@ -1054,7 +1029,7 @@ class Api(Iface): except Exception, e: raise ServiceException(e.message) - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def getAllInfo(self): """Returns all information stored by addon plugins. Values are always strings @@ -1062,7 +1037,7 @@ class Api(Iface): """ return self.core.addonManager.getAllInfo() - @permission(PERMS.STATUS) + @RequirePerm(Permission.Status) def getInfoByPlugin(self, plugin): """Returns information stored by a specific plugin. diff --git a/module/database/DatabaseBackend.py b/module/database/DatabaseBackend.py index 6373120ff..516aa981f 100644 --- a/module/database/DatabaseBackend.py +++ b/module/database/DatabaseBackend.py @@ -301,13 +301,10 @@ class DatabaseBackend(Thread): self.c.execute( 'CREATE TABLE IF NOT EXISTS "collector" (' - '"url" TEXT NOT NULL, ' - '"name" TEXT NOT NULL, ' - '"plugin" TEXT DEFAULT "BasePlugin" NOT NULL, ' - '"size" INTEGER DEFAULT 0 NOT NULL, ' - '"status" INTEGER DEFAULT 3 NOT NULL, ' - '"packagename" TEXT DEFAULT "" NOT NULL, ' - 'PRIMARY KEY (url, packagename) ON CONFLICT REPLACE' + '"owner" INTEGER NOT NULL, ' + '"data" TEXT NOT NULL, ' + 'FOREIGN KEY(owner) REFERENCES users(uid)' + 'PRIMARY KEY(owner) ON CONFLICT REPLACE' ') ' ) @@ -322,25 +319,27 @@ class DatabaseBackend(Thread): self.c.execute( 'CREATE TABLE IF NOT EXISTS "users" (' - '"id" INTEGER PRIMARY KEY AUTOINCREMENT, ' + '"uid" INTEGER PRIMARY KEY AUTOINCREMENT, ' '"name" TEXT NOT NULL, ' '"email" TEXT DEFAULT "" NOT NULL, ' '"password" TEXT NOT NULL, ' '"role" INTEGER DEFAULT 0 NOT NULL, ' '"permission" INTEGER DEFAULT 0 NOT NULL, ' '"folder" TEXT DEFAULT "" NOT NULL, ' - '"ratio" INTEGER DEFAULT -1 NOT NULL, ' - '"limit" INTEGER DEFAULT -1 NOT NULL, ' + '"traffic" INTEGER DEFAULT -1 NOT NULL, ' + '"dllimit" INTEGER DEFAULT -1 NOT NULL, ' '"template" TEXT DEFAULT "default" NOT NULL, ' - '"user" INTEGER DEFAULT -1 NOT NULL, ' - 'FOREIGN KEY(user) REFERENCES users(id)' + '"user" INTEGER DEFAULT -1 NOT NULL, ' # set by trigger to self + 'FOREIGN KEY(user) REFERENCES users(uid)' ')' ) + self.c.execute('CREATE INDEX IF NOT EXISTS "username_index" ON users(name)') + self.c.execute( 'CREATE TRIGGER IF NOT EXISTS "insert_user" AFTER INSERT ON "users"' 'BEGIN ' - 'UPDATE users SET user = new.id ' + 'UPDATE users SET user = new.uid, folder=new.name ' 'WHERE rowid = new.rowid;' 'END' ) @@ -350,7 +349,7 @@ class DatabaseBackend(Thread): '"plugin" TEXT NOT NULL, ' '"owner" INTEGER NOT NULL, ' '"configuration" TEXT NOT NULL, ' - 'FOREIGN KEY(owner) REFERENCES users(id), ' + 'FOREIGN KEY(owner) REFERENCES users(uid), ' 'PRIMARY KEY (plugin, owner) ON CONFLICT REPLACE' ')' ) @@ -359,12 +358,13 @@ class DatabaseBackend(Thread): 'CREATE TABLE IF NOT EXISTS "accounts" (' '"plugin" TEXT NOT NULL, ' '"loginname" TEXT NOT NULL, ' + '"owner", INTEGER NOT NULL, ' '"activated" INTEGER DEFAULT 1, ' '"password" TEXT DEFAULT "", ' + '"shared" INTEGER DEFAULT 0, ' '"options" TEXT DEFAULT "", ' -# '"owner" INTEGER NOT NULL, ' TODO: shared, owner attribute -# 'FOREIGN KEY(owner) REFERENCES users(id)' - 'PRIMARY KEY (plugin, loginname) ON CONFLICT REPLACE' + 'FOREIGN KEY(owner) REFERENCES users(uid)' + 'PRIMARY KEY (plugin, loginname, owner) ON CONFLICT REPLACE' ')' ) diff --git a/module/database/FileDatabase.py b/module/database/FileDatabase.py index 19dca84c7..b783d15d9 100644 --- a/module/database/FileDatabase.py +++ b/module/database/FileDatabase.py @@ -85,36 +85,20 @@ class FileMethods(DatabaseMethods): (order, package)) @async - def addCollector(self, plugin, package, data): - """ fill collector, data as (name, size, status,[ hash,] url) list """ - if data and len(data[0]) == 4: - data = [(r[0], r[1], r[2], r[3], plugin, package) for r in data] - else: - data = [(r[0], r[1], r[2], r[4], plugin, package) for r in data] - - self.c.executemany("INSERT INTO collector(name, size, status, url, plugin, packagename) VALUES (?,?,?,?,?,?)", - data) - - @async - def deleteCollector(self, package=None, url=None): - qry = 'DELETE FROM collector' - if package: - self.c.execute(qry + " WHERE packagename=?", (package,)) - elif url: - self.c.execute(qry + " WHERE url=?", (url,)) - else: - self.c.execute(qry) + def saveCollector(self, owner, data): + """ simply save the json string to database """ + self.c.execute("INSERT INTO collector(owner, data) VALUES (?,?)", (owner, data)) @queue - def getCollector(self, package=None): - """ get collector data, optionally filtered by package """ - qry = 'SELECT url, name, plugin, size, status, packagename FROM collector' - if package: - self.c.execute(qry + " WHERE packagename=?", (package,)) - else: - self.c.execute(qry) + def retrieveCollector(self, owner): + """ retrieve the saved string """ + self.c.execute('SELECT data FROM collector owner=?', (owner,)) + return self.c.fetchone()[0] - return [LinkStatus(*r) for r in self.c] + @async + def deleteCollector(self, owner): + """ drop saved user collector """ + self.c.execute('DELETE FROM collector WHERE owner=?', (owner,)) @queue def getAllFiles(self, package=None, search=None, unfinished=False): diff --git a/module/remote/socketbackend/ttypes.py b/module/remote/socketbackend/ttypes.py index 1fd61ae72..36f2b01ef 100644 --- a/module/remote/socketbackend/ttypes.py +++ b/module/remote/socketbackend/ttypes.py @@ -62,18 +62,36 @@ class PackageStatus: Paused = 1 Remote = 2 +class Permission: + Accounts = 128 + Add = 1 + Addons = 512 + All = 0 + Delete = 2 + Download = 64 + Interaction = 256 + List = 16 + Modify = 32 + Status = 4 + +class Role: + Admin = 0 + User = 1 + class AccountInfo(BaseObject): - __slots__ = ['plugin', 'loginname', 'valid', 'validuntil', 'trafficleft', 'maxtraffic', 'premium', 'activated', 'options'] + __slots__ = ['plugin', 'loginname', 'owner', 'valid', 'validuntil', 'trafficleft', 'maxtraffic', 'premium', 'activated', 'shared', 'options'] - def __init__(self, plugin=None, loginname=None, valid=None, validuntil=None, trafficleft=None, maxtraffic=None, premium=None, activated=None, options=None): + def __init__(self, plugin=None, loginname=None, owner=None, valid=None, validuntil=None, trafficleft=None, maxtraffic=None, premium=None, activated=None, shared=None, options=None): self.plugin = plugin self.loginname = loginname + self.owner = owner self.valid = valid self.validuntil = validuntil self.trafficleft = trafficleft self.maxtraffic = maxtraffic self.premium = premium self.activated = activated + self.shared = shared self.options = options class AddonInfo(BaseObject): @@ -273,13 +291,18 @@ class ServiceException(Exception): self.msg = msg class UserData(BaseObject): - __slots__ = ['name', 'email', 'role', 'permission', 'templateName'] + __slots__ = ['uid', 'name', 'email', 'role', 'permission', 'folder', 'traffic', 'limit', 'user', 'templateName'] - def __init__(self, name=None, email=None, role=None, permission=None, templateName=None): + def __init__(self, uid=None, name=None, email=None, role=None, permission=None, folder=None, traffic=None, limit=None, user=None, templateName=None): + self.uid = uid self.name = name self.email = email self.role = role self.permission = permission + self.folder = folder + self.traffic = traffic + self.limit = limit + self.user = user self.templateName = templateName class UserDoesNotExists(Exception): @@ -301,6 +324,8 @@ class Iface: pass def addToCollector(self, links): pass + def addUser(self, username, password): + pass def autoAddLinks(self, links): pass def call(self, plugin, func, arguments): @@ -383,7 +408,7 @@ class Iface: pass def getUnfinishedFileTree(self, pid, full): pass - def getUserData(self, username, password): + def getUserData(self): pass def hasService(self, plugin, func): pass @@ -415,6 +440,8 @@ class Iface: pass def removeAccount(self, plugin, account): pass + def removeUser(self, uid): + pass def renameCollPack(self, name, new_name): pass def restart(self): @@ -441,6 +468,8 @@ class Iface: pass def setPackagePaused(self, pid, paused): pass + def setPassword(self, username, old_password, new_password): + pass def statusServer(self): pass def stopAllDownloads(self): @@ -455,6 +484,8 @@ class Iface: pass def updateAccount(self, plugin, account, password, options): pass + def updateUserData(self, data): + pass def uploadContainer(self, filename, data): pass diff --git a/module/remote/thriftbackend/pyload.thrift b/module/remote/thriftbackend/pyload.thrift index df82dae2d..254f41068 100644 --- a/module/remote/thriftbackend/pyload.thrift +++ b/module/remote/thriftbackend/pyload.thrift @@ -4,12 +4,12 @@ typedef i32 FileID typedef i32 PackageID typedef i32 ResultID typedef i32 InteractionID +typedef i32 UserID typedef i64 UTCDate typedef i64 ByteCount typedef list<string> LinkList -// a string that can represent multiple types int, bool, time, etc.. -typedef string ValueString typedef string PluginName +typedef string JSONString // NA - Not Available enum DownloadStatus { @@ -80,6 +80,24 @@ enum Output { Query = 4, } +enum Permission { + All = 0, // requires no permission, but login + Add = 1, // can add packages + Delete = 2, // can delete packages + Status = 4, // see and change server status + List = 16, // see listed downloads + Modify = 32, // modify some attribute of downloads + Download = 64, // can download from webinterface + Accounts = 128, // can access accounts + Interaction = 256, // can interact with plugins + Addons = 512 // user can activate addons +} + +enum Role { + Admin = 0, //admin has all permissions implicit + User = 1 +} + struct ProgressInfo { 1: FileID fid, 2: string name, @@ -176,7 +194,7 @@ struct InteractionTask { 2: Input input, 3: list<string> data, 4: Output output, - 5: optional ValueString default_value, + 5: optional JSONString default_value, 6: string title, 7: string description, 8: PluginName plugin, @@ -185,7 +203,7 @@ struct InteractionTask { struct AddonInfo { 1: string func_name, 2: string description, - 3: ValueString value, + 3: JSONString value, } struct ConfigItem { @@ -193,8 +211,8 @@ struct ConfigItem { 2: string display_name, 3: string description, 4: string type, - 5: ValueString default_value, - 6: ValueString value, + 5: JSONString default_value, + 6: JSONString value, } struct ConfigSection { @@ -213,23 +231,30 @@ struct EventInfo { } struct UserData { - 1: string name, - 2: string email, - 3: i32 role, - 4: i32 permission, - 5: string templateName + 1: UserID uid, + 2: string name, + 3: string email, + 4: i16 role, + 5: i16 permission, + 6: string folder, + 7: ByteCount traffic + 8: i16 dllimit + 9: UserID user + 10: string templateName } struct AccountInfo { 1: PluginName plugin, 2: string loginname, - 3: bool valid, - 4: UTCDate validuntil, - 5: ByteCount trafficleft, - 6: ByteCount maxtraffic, - 7: bool premium, - 8: bool activated, - 9: map<string, string> options, + 3: UserID owner, + 4: bool valid, + 5: UTCDate validuntil, + 6: ByteCount trafficleft, + 7: ByteCount maxtraffic, + 8: bool premium, + 9: bool activated, + 10: bool shared, + 11: map<string, string> options, } struct AddonService { @@ -300,7 +325,7 @@ service Pyload { map<string, ConfigSection> getConfig(), map<PluginName, ConfigSection> getPluginConfig(), ConfigSection configureSection(1: string section), - void setConfigHandler(1: PluginName plugin, 2: InteractionID iid, 3: ValueString value), + void setConfigHandler(1: PluginName plugin, 2: InteractionID iid, 3: JSONString value), /////////////////////// // Download Preparing @@ -410,7 +435,7 @@ service Pyload { // mode = Output types binary ORed bool isInteractionWaiting(1: i16 mode), InteractionTask getInteractionTask(1: i16 mode), - void setInteractionResult(1: InteractionID iid, 2: ValueString result), + void setInteractionResult(1: InteractionID iid, 2: JSONString result), // generate a download link, everybody can download the file until timeout reached string generateDownloadLink(1: FileID fid, 2: i16 timeout), @@ -440,8 +465,20 @@ service Pyload { ///////////////////////// bool login(1: string username, 2: string password), - UserData getUserData(1: string username, 2: string password) throws (1: UserDoesNotExists ex), - map<string, UserData> getAllUserData(), + // returns own user data + UserData getUserData(), + + // all user, for admins only + map<UserID, UserData> getAllUserData(), + + UserData addUser(1: string username, 2:string password), + + // normal user can only update their own userdata and not all attributes + void updateUserData(1: UserData data), + void removeUser(1: UserID uid), + + // works contextual, admin can change every password + bool setPassword(1: string username, 2: string old_password, 3: string new_password), /////////////////////// // Addon Methods @@ -451,7 +488,7 @@ service Pyload { bool hasService(1: PluginName plugin, 2: string func), // empty string or json encoded list as args - string call(1: PluginName plugin, 2: string func, 3: string arguments) throws (1: ServiceDoesNotExists ex, 2: ServiceException e), + string call(1: PluginName plugin, 2: string func, 3: JSONString arguments) throws (1: ServiceDoesNotExists ex, 2: ServiceException e), map<PluginName, list<AddonInfo>> getAllInfo(), list<AddonInfo> getInfoByPlugin(1: PluginName plugin), diff --git a/module/remote/thriftbackend/thriftgen/pyload/Pyload-remote b/module/remote/thriftbackend/thriftgen/pyload/Pyload-remote index 55f9a1823..c2c13d8ed 100755 --- a/module/remote/thriftbackend/thriftgen/pyload/Pyload-remote +++ b/module/remote/thriftbackend/thriftgen/pyload/Pyload-remote @@ -42,7 +42,7 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help': print ' getConfig()' print ' getPluginConfig()' print ' ConfigSection configureSection(string section)' - print ' void setConfigHandler(PluginName plugin, InteractionID iid, ValueString value)' + print ' void setConfigHandler(PluginName plugin, InteractionID iid, JSONString value)' print ' checkURLs(LinkList urls)' print ' parseURLs(string html, string url)' print ' OnlineCheck checkOnlineStatus(LinkList urls)' @@ -89,7 +89,7 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help': print ' void orderFiles( fids, PackageID pid, i16 position)' print ' bool isInteractionWaiting(i16 mode)' print ' InteractionTask getInteractionTask(i16 mode)' - print ' void setInteractionResult(InteractionID iid, ValueString result)' + print ' void setInteractionResult(InteractionID iid, JSONString result)' print ' string generateDownloadLink(FileID fid, i16 timeout)' print ' getNotifications()' print ' getAddonHandler()' @@ -100,11 +100,15 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help': print ' void updateAccount(PluginName plugin, string account, string password, options)' print ' void removeAccount(PluginName plugin, string account)' print ' bool login(string username, string password)' - print ' UserData getUserData(string username, string password)' + print ' UserData getUserData()' print ' getAllUserData()' + print ' UserData addUser(string username, string password)' + print ' void updateUserData(UserData data)' + print ' void removeUser(UserID uid)' + print ' bool setPassword(string username, string old_password, string new_password)' print ' getServices()' print ' bool hasService(PluginName plugin, string func)' - print ' string call(PluginName plugin, string func, string arguments)' + print ' string call(PluginName plugin, string func, JSONString arguments)' print ' getAllInfo()' print ' getInfoByPlugin(PluginName plugin)' print '' @@ -621,10 +625,10 @@ elif cmd == 'login': pp.pprint(client.login(args[0],args[1],)) elif cmd == 'getUserData': - if len(args) != 2: - print 'getUserData requires 2 args' + if len(args) != 0: + print 'getUserData requires 0 args' sys.exit(1) - pp.pprint(client.getUserData(args[0],args[1],)) + pp.pprint(client.getUserData()) elif cmd == 'getAllUserData': if len(args) != 0: @@ -632,6 +636,30 @@ elif cmd == 'getAllUserData': sys.exit(1) pp.pprint(client.getAllUserData()) +elif cmd == 'addUser': + if len(args) != 2: + print 'addUser requires 2 args' + sys.exit(1) + pp.pprint(client.addUser(args[0],args[1],)) + +elif cmd == 'updateUserData': + if len(args) != 1: + print 'updateUserData requires 1 args' + sys.exit(1) + pp.pprint(client.updateUserData(eval(args[0]),)) + +elif cmd == 'removeUser': + if len(args) != 1: + print 'removeUser requires 1 args' + sys.exit(1) + pp.pprint(client.removeUser(eval(args[0]),)) + +elif cmd == 'setPassword': + if len(args) != 3: + print 'setPassword requires 3 args' + sys.exit(1) + pp.pprint(client.setPassword(args[0],args[1],args[2],)) + elif cmd == 'getServices': if len(args) != 0: print 'getServices requires 0 args' @@ -648,7 +676,7 @@ elif cmd == 'call': if len(args) != 3: print 'call requires 3 args' sys.exit(1) - pp.pprint(client.call(eval(args[0]),args[1],args[2],)) + pp.pprint(client.call(eval(args[0]),args[1],eval(args[2]),)) elif cmd == 'getAllInfo': if len(args) != 0: diff --git a/module/remote/thriftbackend/thriftgen/pyload/Pyload.py b/module/remote/thriftbackend/thriftgen/pyload/Pyload.py index 51c8621ba..c45663d25 100644 --- a/module/remote/thriftbackend/thriftgen/pyload/Pyload.py +++ b/module/remote/thriftbackend/thriftgen/pyload/Pyload.py @@ -9,7 +9,7 @@ from thrift.Thrift import TType, TMessageType, TException from ttypes import * from thrift.Thrift import TProcessor -from thrift.protocol.TBase import TBase, TExceptionBase +from thrift.protocol.TBase import TBase, TExceptionBase, TApplicationException class Iface(object): @@ -508,7 +508,13 @@ class Iface(object): """ pass - def getUserData(self, username, password): + def getUserData(self, ): + pass + + def getAllUserData(self, ): + pass + + def addUser(self, username, password): """ Parameters: - username @@ -516,7 +522,27 @@ class Iface(object): """ pass - def getAllUserData(self, ): + def updateUserData(self, data): + """ + Parameters: + - data + """ + pass + + def removeUser(self, uid): + """ + Parameters: + - uid + """ + pass + + def setPassword(self, username, old_password, new_password): + """ + Parameters: + - username + - old_password + - new_password + """ pass def getServices(self, ): @@ -2808,20 +2834,13 @@ class Client(Iface): return result.success raise TApplicationException(TApplicationException.MISSING_RESULT, "login failed: unknown result"); - def getUserData(self, username, password): - """ - Parameters: - - username - - password - """ - self.send_getUserData(username, password) + def getUserData(self, ): + self.send_getUserData() return self.recv_getUserData() - def send_getUserData(self, username, password): + def send_getUserData(self, ): self._oprot.writeMessageBegin('getUserData', TMessageType.CALL, self._seqid) args = getUserData_args() - args.username = username - args.password = password args.write(self._oprot) self._oprot.writeMessageEnd() self._oprot.trans.flush() @@ -2838,8 +2857,6 @@ class Client(Iface): self._iprot.readMessageEnd() if result.success is not None: return result.success - if result.ex is not None: - raise result.ex raise TApplicationException(TApplicationException.MISSING_RESULT, "getUserData failed: unknown result"); def getAllUserData(self, ): @@ -2867,6 +2884,128 @@ class Client(Iface): return result.success raise TApplicationException(TApplicationException.MISSING_RESULT, "getAllUserData failed: unknown result"); + def addUser(self, username, password): + """ + Parameters: + - username + - password + """ + self.send_addUser(username, password) + return self.recv_addUser() + + def send_addUser(self, username, password): + self._oprot.writeMessageBegin('addUser', TMessageType.CALL, self._seqid) + args = addUser_args() + args.username = username + args.password = password + args.write(self._oprot) + self._oprot.writeMessageEnd() + self._oprot.trans.flush() + + def recv_addUser(self, ): + (fname, mtype, rseqid) = self._iprot.readMessageBegin() + if mtype == TMessageType.EXCEPTION: + x = TApplicationException() + x.read(self._iprot) + self._iprot.readMessageEnd() + raise x + result = addUser_result() + result.read(self._iprot) + self._iprot.readMessageEnd() + if result.success is not None: + return result.success + raise TApplicationException(TApplicationException.MISSING_RESULT, "addUser failed: unknown result"); + + def updateUserData(self, data): + """ + Parameters: + - data + """ + self.send_updateUserData(data) + self.recv_updateUserData() + + def send_updateUserData(self, data): + self._oprot.writeMessageBegin('updateUserData', TMessageType.CALL, self._seqid) + args = updateUserData_args() + args.data = data + args.write(self._oprot) + self._oprot.writeMessageEnd() + self._oprot.trans.flush() + + def recv_updateUserData(self, ): + (fname, mtype, rseqid) = self._iprot.readMessageBegin() + if mtype == TMessageType.EXCEPTION: + x = TApplicationException() + x.read(self._iprot) + self._iprot.readMessageEnd() + raise x + result = updateUserData_result() + result.read(self._iprot) + self._iprot.readMessageEnd() + return + + def removeUser(self, uid): + """ + Parameters: + - uid + """ + self.send_removeUser(uid) + self.recv_removeUser() + + def send_removeUser(self, uid): + self._oprot.writeMessageBegin('removeUser', TMessageType.CALL, self._seqid) + args = removeUser_args() + args.uid = uid + args.write(self._oprot) + self._oprot.writeMessageEnd() + self._oprot.trans.flush() + + def recv_removeUser(self, ): + (fname, mtype, rseqid) = self._iprot.readMessageBegin() + if mtype == TMessageType.EXCEPTION: + x = TApplicationException() + x.read(self._iprot) + self._iprot.readMessageEnd() + raise x + result = removeUser_result() + result.read(self._iprot) + self._iprot.readMessageEnd() + return + + def setPassword(self, username, old_password, new_password): + """ + Parameters: + - username + - old_password + - new_password + """ + self.send_setPassword(username, old_password, new_password) + return self.recv_setPassword() + + def send_setPassword(self, username, old_password, new_password): + self._oprot.writeMessageBegin('setPassword', TMessageType.CALL, self._seqid) + args = setPassword_args() + args.username = username + args.old_password = old_password + args.new_password = new_password + args.write(self._oprot) + self._oprot.writeMessageEnd() + self._oprot.trans.flush() + + def recv_setPassword(self, ): + (fname, mtype, rseqid) = self._iprot.readMessageBegin() + if mtype == TMessageType.EXCEPTION: + x = TApplicationException() + x.read(self._iprot) + self._iprot.readMessageEnd() + raise x + result = setPassword_result() + result.read(self._iprot) + self._iprot.readMessageEnd() + if result.success is not None: + return result.success + raise TApplicationException(TApplicationException.MISSING_RESULT, "setPassword failed: unknown result"); + def getServices(self, ): self.send_getServices() return self.recv_getServices() @@ -3101,6 +3240,10 @@ class Processor(Iface, TProcessor): self._processMap["login"] = Processor.process_login self._processMap["getUserData"] = Processor.process_getUserData self._processMap["getAllUserData"] = Processor.process_getAllUserData + self._processMap["addUser"] = Processor.process_addUser + self._processMap["updateUserData"] = Processor.process_updateUserData + self._processMap["removeUser"] = Processor.process_removeUser + self._processMap["setPassword"] = Processor.process_setPassword self._processMap["getServices"] = Processor.process_getServices self._processMap["hasService"] = Processor.process_hasService self._processMap["call"] = Processor.process_call @@ -4001,10 +4144,7 @@ class Processor(Iface, TProcessor): args.read(iprot) iprot.readMessageEnd() result = getUserData_result() - try: - result.success = self._handler.getUserData(args.username, args.password) - except UserDoesNotExists, ex: - result.ex = ex + result.success = self._handler.getUserData() oprot.writeMessageBegin("getUserData", TMessageType.REPLY, seqid) result.write(oprot) oprot.writeMessageEnd() @@ -4021,6 +4161,50 @@ class Processor(Iface, TProcessor): oprot.writeMessageEnd() oprot.trans.flush() + def process_addUser(self, seqid, iprot, oprot): + args = addUser_args() + args.read(iprot) + iprot.readMessageEnd() + result = addUser_result() + result.success = self._handler.addUser(args.username, args.password) + oprot.writeMessageBegin("addUser", TMessageType.REPLY, seqid) + result.write(oprot) + oprot.writeMessageEnd() + oprot.trans.flush() + + def process_updateUserData(self, seqid, iprot, oprot): + args = updateUserData_args() + args.read(iprot) + iprot.readMessageEnd() + result = updateUserData_result() + self._handler.updateUserData(args.data) + oprot.writeMessageBegin("updateUserData", TMessageType.REPLY, seqid) + result.write(oprot) + oprot.writeMessageEnd() + oprot.trans.flush() + + def process_removeUser(self, seqid, iprot, oprot): + args = removeUser_args() + args.read(iprot) + iprot.readMessageEnd() + result = removeUser_result() + self._handler.removeUser(args.uid) + oprot.writeMessageBegin("removeUser", TMessageType.REPLY, seqid) + result.write(oprot) + oprot.writeMessageEnd() + oprot.trans.flush() + + def process_setPassword(self, seqid, iprot, oprot): + args = setPassword_args() + args.read(iprot) + iprot.readMessageEnd() + result = setPassword_result() + result.success = self._handler.setPassword(args.username, args.old_password, args.new_password) + oprot.writeMessageBegin("setPassword", TMessageType.REPLY, seqid) + result.write(oprot) + oprot.writeMessageEnd() + oprot.trans.flush() + def process_getServices(self, seqid, iprot, oprot): args = getServices_args() args.read(iprot) @@ -6695,6 +6879,60 @@ class login_result(TBase): class getUserData_args(TBase): + + __slots__ = [ + ] + + thrift_spec = ( + ) + + +class getUserData_result(TBase): + """ + Attributes: + - success + """ + + __slots__ = [ + 'success', + ] + + thrift_spec = ( + (0, TType.STRUCT, 'success', (UserData, UserData.thrift_spec), None, ), # 0 + ) + + def __init__(self, success=None,): + self.success = success + + +class getAllUserData_args(TBase): + + __slots__ = [ + ] + + thrift_spec = ( + ) + + +class getAllUserData_result(TBase): + """ + Attributes: + - success + """ + + __slots__ = [ + 'success', + ] + + thrift_spec = ( + (0, TType.MAP, 'success', (TType.I32,None,TType.STRUCT,(UserData, UserData.thrift_spec)), None, ), # 0 + ) + + def __init__(self, success=None,): + self.success = success + + +class addUser_args(TBase): """ Attributes: - username @@ -6717,38 +6955,108 @@ class getUserData_args(TBase): self.password = password -class getUserData_result(TBase): +class addUser_result(TBase): """ Attributes: - success - - ex """ __slots__ = [ 'success', - 'ex', ] thrift_spec = ( (0, TType.STRUCT, 'success', (UserData, UserData.thrift_spec), None, ), # 0 - (1, TType.STRUCT, 'ex', (UserDoesNotExists, UserDoesNotExists.thrift_spec), None, ), # 1 ) - def __init__(self, success=None, ex=None,): + def __init__(self, success=None,): self.success = success - self.ex = ex -class getAllUserData_args(TBase): +class updateUserData_args(TBase): + """ + Attributes: + - data + """ __slots__ = [ + 'data', ] thrift_spec = ( + None, # 0 + (1, TType.STRUCT, 'data', (UserData, UserData.thrift_spec), None, ), # 1 ) + def __init__(self, data=None,): + self.data = data + -class getAllUserData_result(TBase): +class updateUserData_result(TBase): + + __slots__ = [ + ] + + thrift_spec = ( + ) + + +class removeUser_args(TBase): + """ + Attributes: + - uid + """ + + __slots__ = [ + 'uid', + ] + + thrift_spec = ( + None, # 0 + (1, TType.I32, 'uid', None, None, ), # 1 + ) + + def __init__(self, uid=None,): + self.uid = uid + + +class removeUser_result(TBase): + + __slots__ = [ + ] + + thrift_spec = ( + ) + + +class setPassword_args(TBase): + """ + Attributes: + - username + - old_password + - new_password + """ + + __slots__ = [ + 'username', + 'old_password', + 'new_password', + ] + + thrift_spec = ( + None, # 0 + (1, TType.STRING, 'username', None, None, ), # 1 + (2, TType.STRING, 'old_password', None, None, ), # 2 + (3, TType.STRING, 'new_password', None, None, ), # 3 + ) + + def __init__(self, username=None, old_password=None, new_password=None,): + self.username = username + self.old_password = old_password + self.new_password = new_password + + +class setPassword_result(TBase): """ Attributes: - success @@ -6759,7 +7067,7 @@ class getAllUserData_result(TBase): ] thrift_spec = ( - (0, TType.MAP, 'success', (TType.STRING,None,TType.STRUCT,(UserData, UserData.thrift_spec)), None, ), # 0 + (0, TType.BOOL, 'success', None, None, ), # 0 ) def __init__(self, success=None,): diff --git a/module/remote/thriftbackend/thriftgen/pyload/ttypes.py b/module/remote/thriftbackend/thriftgen/pyload/ttypes.py index fbbc599a8..c177a9dd2 100644 --- a/module/remote/thriftbackend/thriftgen/pyload/ttypes.py +++ b/module/remote/thriftbackend/thriftgen/pyload/ttypes.py @@ -191,6 +191,58 @@ class Output(TBase): "Query": 4, } +class Permission(TBase): + All = 0 + Add = 1 + Delete = 2 + Status = 4 + List = 16 + Modify = 32 + Download = 64 + Accounts = 128 + Interaction = 256 + Addons = 512 + + _VALUES_TO_NAMES = { + 0: "All", + 1: "Add", + 2: "Delete", + 4: "Status", + 16: "List", + 32: "Modify", + 64: "Download", + 128: "Accounts", + 256: "Interaction", + 512: "Addons", + } + + _NAMES_TO_VALUES = { + "All": 0, + "Add": 1, + "Delete": 2, + "Status": 4, + "List": 16, + "Modify": 32, + "Download": 64, + "Accounts": 128, + "Interaction": 256, + "Addons": 512, + } + +class Role(TBase): + Admin = 0 + User = 1 + + _VALUES_TO_NAMES = { + 0: "Admin", + 1: "User", + } + + _NAMES_TO_VALUES = { + "Admin": 0, + "User": 1, + } + class ProgressInfo(TBase): """ @@ -750,35 +802,55 @@ class EventInfo(TBase): class UserData(TBase): """ Attributes: + - uid - name - email - role - permission + - folder + - traffic + - limit + - user - templateName """ __slots__ = [ + 'uid', 'name', 'email', 'role', 'permission', + 'folder', + 'traffic', + 'limit', + 'user', 'templateName', ] thrift_spec = ( None, # 0 - (1, TType.STRING, 'name', None, None, ), # 1 - (2, TType.STRING, 'email', None, None, ), # 2 - (3, TType.I32, 'role', None, None, ), # 3 - (4, TType.I32, 'permission', None, None, ), # 4 - (5, TType.STRING, 'templateName', None, None, ), # 5 + (1, TType.I32, 'uid', None, None, ), # 1 + (2, TType.STRING, 'name', None, None, ), # 2 + (3, TType.STRING, 'email', None, None, ), # 3 + (4, TType.I16, 'role', None, None, ), # 4 + (5, TType.I16, 'permission', None, None, ), # 5 + (6, TType.STRING, 'folder', None, None, ), # 6 + (7, TType.I64, 'traffic', None, None, ), # 7 + (8, TType.I16, 'limit', None, None, ), # 8 + (9, TType.I32, 'user', None, None, ), # 9 + (10, TType.STRING, 'templateName', None, None, ), # 10 ) - def __init__(self, name=None, email=None, role=None, permission=None, templateName=None,): + def __init__(self, uid=None, name=None, email=None, role=None, permission=None, folder=None, traffic=None, limit=None, user=None, templateName=None,): + self.uid = uid self.name = name self.email = email self.role = role self.permission = permission + self.folder = folder + self.traffic = traffic + self.limit = limit + self.user = user self.templateName = templateName @@ -787,24 +859,28 @@ class AccountInfo(TBase): Attributes: - plugin - loginname + - owner - valid - validuntil - trafficleft - maxtraffic - premium - activated + - shared - options """ __slots__ = [ 'plugin', 'loginname', + 'owner', 'valid', 'validuntil', 'trafficleft', 'maxtraffic', 'premium', 'activated', + 'shared', 'options', ] @@ -812,24 +888,28 @@ class AccountInfo(TBase): None, # 0 (1, TType.STRING, 'plugin', None, None, ), # 1 (2, TType.STRING, 'loginname', None, None, ), # 2 - (3, TType.BOOL, 'valid', None, None, ), # 3 - (4, TType.I64, 'validuntil', None, None, ), # 4 - (5, TType.I64, 'trafficleft', None, None, ), # 5 - (6, TType.I64, 'maxtraffic', None, None, ), # 6 - (7, TType.BOOL, 'premium', None, None, ), # 7 - (8, TType.BOOL, 'activated', None, None, ), # 8 - (9, TType.MAP, 'options', (TType.STRING,None,TType.STRING,None), None, ), # 9 + (3, TType.I32, 'owner', None, None, ), # 3 + (4, TType.BOOL, 'valid', None, None, ), # 4 + (5, TType.I64, 'validuntil', None, None, ), # 5 + (6, TType.I64, 'trafficleft', None, None, ), # 6 + (7, TType.I64, 'maxtraffic', None, None, ), # 7 + (8, TType.BOOL, 'premium', None, None, ), # 8 + (9, TType.BOOL, 'activated', None, None, ), # 9 + (10, TType.BOOL, 'shared', None, None, ), # 10 + (11, TType.MAP, 'options', (TType.STRING,None,TType.STRING,None), None, ), # 11 ) - def __init__(self, plugin=None, loginname=None, valid=None, validuntil=None, trafficleft=None, maxtraffic=None, premium=None, activated=None, options=None,): + def __init__(self, plugin=None, loginname=None, owner=None, valid=None, validuntil=None, trafficleft=None, maxtraffic=None, premium=None, activated=None, shared=None, options=None,): self.plugin = plugin self.loginname = loginname + self.owner = owner self.valid = valid self.validuntil = validuntil self.trafficleft = trafficleft self.maxtraffic = maxtraffic self.premium = premium self.activated = activated + self.shared = shared self.options = options diff --git a/module/web/utils.py b/module/web/utils.py index 5cb0cebdd..ac4bdd4f8 100644 --- a/module/web/utils.py +++ b/module/web/utils.py @@ -20,7 +20,7 @@ from bottle import request, HTTPError, redirect, ServerAdapter from webinterface import env, TEMPLATE -from module.Api import has_permission, PERMS, ROLE +from module.Api import has_permission, Permission, Role def render_to_response(name, args={}, proc=[]): for p in proc: @@ -31,14 +31,14 @@ def render_to_response(name, args={}, proc=[]): def parse_permissions(session): - perms = dict([(x, False) for x in dir(PERMS) if not x.startswith("_")]) + perms = dict([(x, False) for x in dir(Permission) if not x.startswith("_")]) perms["ADMIN"] = False perms["is_admin"] = False if not session.get("authenticated", False): return perms - if session.get("role") == ROLE.ADMIN: + if session.get("role") == Role.Admin: for k in perms.iterkeys(): perms[k] = True @@ -50,7 +50,7 @@ def parse_permissions(session): def permlist(): - return [x for x in dir(PERMS) if not x.startswith("_") and x != "ALL"] + return [x for x in dir(Permission) if not x.startswith("_") and x != "ALL"] def get_permission(perms, p): @@ -60,7 +60,7 @@ def get_permission(perms, p): :param p: bits """ for name in permlist(): - perms[name] = has_permission(p, getattr(PERMS, name)) + perms[name] = has_permission(p, getattr(Permission, name)) def set_permission(perms): @@ -69,11 +69,11 @@ def set_permission(perms): :param perms: dict """ permission = 0 - for name in dir(PERMS): + for name in dir(Permission): if name.startswith("_"): continue if name in perms and perms[name]: - permission |= getattr(PERMS, name) + permission |= getattr(Permission, name) return permission |