diff options
Diffstat (limited to 'pyload/Api.py')
| -rw-r--r-- | pyload/Api.py | 206 | 
1 files changed, 206 insertions, 0 deletions
| diff --git a/pyload/Api.py b/pyload/Api.py new file mode 100644 index 000000000..32a077c08 --- /dev/null +++ b/pyload/Api.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +############################################################################### +#   Copyright(c) 2008-2013 pyLoad Team +#   http://www.pyload.org +# +#   This file is part of pyLoad. +#   pyLoad is free software: you can redistribute it and/or modify +#   it under the terms of the GNU Affero General Public License as +#   published by the Free Software Foundation, either version 3 of the +#   License, or (at your option) any later version. +# +#   Subjected to the terms and conditions in LICENSE +# +#   @author: RaNaN +############################################################################### + +import re +from types import MethodType + +from remote.apitypes import * + +# contains function names mapped to their permissions +# unlisted functions are for admins only +perm_map = {} + +# decorator only called on init, never initialized, so has no effect on runtime +def RequirePerm(bits): +    class _Dec(object): +        def __new__(cls, func, *args, **kwargs): +            perm_map[func.__name__] = bits +            return func + +    return _Dec + +urlmatcher = re.compile(r"((https?|ftps?|xdcc|sftp):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-=\\\.&]*)", re.IGNORECASE) + +stateMap = { +    DownloadState.All: frozenset(getattr(DownloadStatus, x) for x in dir(DownloadStatus) if not x.startswith("_")), +    DownloadState.Finished: frozenset((DownloadStatus.Finished, DownloadStatus.Skipped)), +    DownloadState.Unfinished: None, # set below +    DownloadState.Failed: frozenset((DownloadStatus.Failed, DownloadStatus.TempOffline, DownloadStatus.Aborted)), +    DownloadState.Unmanaged: None, #TODO +} + +stateMap[DownloadState.Unfinished] = frozenset(stateMap[DownloadState.All].difference(stateMap[DownloadState.Finished])) + +def state_string(state): +    return ",".join(str(x) for x in stateMap[state]) + +from datatypes.User import User + +class Api(Iface): +    """ +    **pyLoads API** + +    This is accessible either internal via core.api, websocket backend or json api. + +    see Thrift specification file remote/thriftbackend/pyload.thrift\ +    for information about data structures and what methods are usable with rpc. + +    Most methods requires specific permissions, please look at the source code if you need to know.\ +    These can be configured via web interface. +    Admin user have all permissions, and are the only ones who can access the methods with no specific permission. +    """ + +    EXTERNAL = Iface  # let the json api know which methods are external +    EXTEND = False  # only extendable when set too true + +    def __init__(self, core): +        self.core = core +        self.user_apis = {} + +    @property +    def user(self): +        return None #TODO return default user? + +    @property +    def primaryUID(self): +        return self.user.primary if self.user else None + +    @classmethod +    def initComponents(cls): +        # Allow extending the api +        # This prevents unintentionally registering of the components, +        # but will only work once when they are imported +        cls.EXTEND = True +        # Import all Api modules, they register themselves. +        import pyload.api +        # they will vanish from the namespace afterwards + + +    @classmethod +    def extend(cls, api): +        """Takes all params from api and extends cls with it. +            api class can be removed afterwards + +        :param api: Class with methods to extend +        """ +        if cls.EXTEND: +            for name, func in api.__dict__.iteritems(): +                if name.startswith("_"): continue +                setattr(cls, name, MethodType(func, None, cls)) + +        return cls.EXTEND + +    def withUserContext(self, uid): +        """ Returns a proxy version of the api, to call method in user context + +        :param uid: user or userData instance or uid +        :return: :class:`UserApi` +        """ +        if isinstance(uid, User): +            uid = uid.uid + +        if uid not in self.user_apis: +            user = self.core.db.getUserData(uid=uid) +            if not user: #TODO: anonymous user? +                return None + +            self.user_apis[uid] = UserApi(self.core, User.fromUserData(self, user)) + +        return self.user_apis[uid] + + +    ############################# +    #  Auth+User Information +    ############################# + +    # TODO + +    @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. + +        :param username: +        :param password: +        :param remoteip: Omit this argument, its only used internal +        :return: bool indicating login was successful +        """ +        return True if self.checkAuth(username, password, remoteip) else False + +    def checkAuth(self, username, password, remoteip=None): +        """Check authentication and returns details + +        :param username: +        :param password: +        :param remoteip: +        :return: dict with info, empty when login is incorrect +        """ +        self.core.log.info(_("User '%s' tries to log in") % username) + +        return self.core.db.checkAuth(username, password) + +    def isAuthorized(self, func, user): +        """checks if the user is authorized for specific method + +        :param func: function name +        :param user: `User` +        :return: boolean +        """ +        if user.isAdmin(): +            return True +        elif func in perm_map and user.hasPermission(perm_map[func]): +            return True +        else: +            return False + +    # TODO +    @RequirePerm(Permission.All) +    def getUserData(self, username, password): +        """similar to `checkAuth` but returns UserData thrift type """ +        user = self.checkAuth(username, password) +        if not user: +            raise UserDoesNotExists(username) + +        return user.toUserData() + +    def getAllUserData(self): +        """returns all known user and info""" +        return self.core.db.getAllUserData() + +    def changePassword(self, username, oldpw, newpw): +        """ changes password for specific user """ +        return self.core.db.changePassword(username, oldpw, newpw) + +    def setUserPermission(self, user, permission, role): +        self.core.db.setPermission(user, permission) +        self.core.db.setRole(user, role) + + +class UserApi(Api): +    """  Proxy object for api that provides all methods in user context """ + +    def __init__(self, core, user): +        # No need to init super class +        self.core = core +        self._user = user + +    def withUserContext(self, uid): +        raise Exception("Not allowed") + +    @property +    def user(self): +        return self._user
\ No newline at end of file | 
