diff options
Diffstat (limited to 'module')
| -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 | 
