Beispiel #1
0
    def _api_validate(self, *args, **kwargs):
        """ Sets class vars and remove unneeded parameters. """

        if not plexpy.CONFIG.API_ENABLED:
            self._api_msg = 'API not enabled'

        elif not plexpy.CONFIG.API_KEY:
            self._api_msg = 'API key not generated'

        elif len(plexpy.CONFIG.API_KEY) != 32:
            self._api_msg = 'API key not generated correctly'

        elif 'apikey' not in kwargs:
            self._api_msg = 'Parameter apikey is required'

        elif 'cmd' not in kwargs:
            self._api_msg = 'Parameter cmd is required. Possible commands are: %s' % ', '.join(self._api_valid_methods)

        elif 'cmd' in kwargs and kwargs.get('cmd') not in self._api_valid_methods:
            self._api_msg = 'Unknown command: %s. Possible commands are: %s' % (kwargs.get('cmd', ''), ', '.join(sorted(self._api_valid_methods)))

        self._api_callback = kwargs.pop('callback', None)
        self._api_apikey = kwargs.pop('apikey', None)
        self._api_cmd = kwargs.pop('cmd', None)
        self._api_debug = kwargs.pop('debug', False)
        self._api_profileme = kwargs.pop('profileme', None)
        # Allow override for the api.
        self._api_out_type = kwargs.pop('out_type', 'json')

        if 'app' in kwargs and kwargs.pop('app') == 'true':
            self._api_app = True

        if plexpy.CONFIG.API_ENABLED and not self._api_msg:
            if self._api_apikey == plexpy.CONFIG.API_KEY or (self._api_app and self._api_apikey == mobile_app.TEMP_DEVICE_TOKEN):
                self._api_authenticated = True

            elif self._api_app and mobile_app.get_mobile_device_by_token(self._api_apikey):
                mobile_app.set_last_seen(self._api_apikey)
                self._api_authenticated = True

            else:
                self._api_msg = 'Invalid apikey'

            if self._api_authenticated and self._api_cmd in self._api_valid_methods:
                self._api_msg = None
                self._api_kwargs = kwargs

            elif not self._api_authenticated and self._api_cmd in ('get_apikey', 'docs', 'docs_md'):
                self._api_authenticated = True
                # Remove the old error msg
                self._api_msg = None
                self._api_kwargs = kwargs

        if self._api_msg:
            logger.api_debug(u'Tautulli APIv2 :: %s.' % self._api_msg)

        logger.api_debug(u'Tautulli APIv2 :: Cleaned kwargs: %s' % self._api_kwargs)

        return self._api_kwargs
Beispiel #2
0
    def notify_newsletter(self,
                          newsletter_id='',
                          subject='',
                          body='',
                          message='',
                          **kwargs):
        """ Send a newsletter using Tautulli.

            ```
            Required parameters:
                newsletter_id (int):    The ID number of the newsletter agent

            Optional parameters:
                subject (str):          The subject of the newsletter
                body (str):             The body of the newsletter
                message (str):          The message of the newsletter

            Returns:
                None
            ```
        """
        if not newsletter_id:
            self._api_msg = 'Newsletter failed: no newsletter id provided.'
            self._api_result_type = 'error'
            return

        newsletter = newsletters.get_newsletter_config(
            newsletter_id=newsletter_id)

        if not newsletter:
            self._api_msg = 'Newsletter failed: invalid newsletter_id provided %s.' % newsletter_id
            self._api_result_type = 'error'
            return

        logger.api_debug('Tautulli APIv2 :: Sending newsletter.')
        success = newsletter_handler.notify(newsletter_id=newsletter_id,
                                            notify_action='api',
                                            subject=subject,
                                            body=body,
                                            message=message,
                                            **kwargs)

        if success:
            self._api_msg = 'Newsletter sent.'
            self._api_result_type = 'success'
        else:
            self._api_msg = 'Newsletter failed.'
            self._api_result_type = 'error'

        return
Beispiel #3
0
    def notify(self,
               notifier_id='',
               subject='Tautulli',
               body='Test notification',
               **kwargs):
        """ Send a notification using Tautulli.

            ```
            Required parameters:
                notifier_id (int):      The ID number of the notification agent
                subject (str):          The subject of the message
                body (str):             The body of the message

            Optional parameters:
                headers (str):          The JSON headers for webhook notifications
                script_args (str):      The arguments for script notifications

            Returns:
                None
            ```
        """
        if not notifier_id:
            self._api_msg = 'Notification failed: no notifier id provided.'
            self._api_result_type = 'error'
            return

        notifier = notifiers.get_notifier_config(notifier_id=notifier_id)

        if not notifier:
            self._api_msg = 'Notification failed: invalid notifier_id provided %s.' % notifier_id
            self._api_result_type = 'error'
            return

        logger.api_debug(u'Tautulli APIv2 :: Sending notification.')
        success = notification_handler.notify(notifier_id=notifier_id,
                                              notify_action='api',
                                              subject=subject,
                                              body=body,
                                              **kwargs)

        if success:
            self._api_msg = 'Notification sent.'
            self._api_result_type = 'success'
        else:
            self._api_msg = 'Notification failed.'
            self._api_result_type = 'error'

        return
Beispiel #4
0
    def _api_run(self, *args, **kwargs):
        """ handles the stuff from the handler """

        # Make sure the device ID is not shown in the logs
        if self._api_cmd == 'register_device':
            if kwargs.get('device_id'):
                logger._BLACKLIST_WORDS.add(kwargs['device_id'])
            if kwargs.get('onesignal_id'):
                logger._BLACKLIST_WORDS.add(kwargs['onesignal_id'])

        result = {}
        logger.api_debug('Tautulli APIv2 :: API called with kwargs: %s' %
                         kwargs)

        self._api_validate(**kwargs)

        if self._api_cmd and self._api_authenticated:
            call = getattr(self, self._api_cmd)

            # Profile is written to console.
            if self._api_profileme:
                from profilehooks import profile
                call = profile(call, immediate=True)

            # We allow this to fail so we get a
            # traceback in the browser
            try:

                result = call(**self._api_kwargs)
            except Exception as e:
                logger.api_error(
                    'Tautulli APIv2 :: Failed to run %s with %s: %s' %
                    (self._api_cmd, self._api_kwargs, e))
                self._api_response_code = 500
                if self._api_debug:
                    cherrypy.request.show_tracebacks = True
                    # Reraise the exception so the traceback hits the browser
                    raise
                self._api_msg = 'Check the logs for errors'

        ret = None
        # The api decorated function can return different result types.
        # convert it to a list/dict before we change it to the users
        # wanted output
        try:
            if isinstance(result, (dict, list)):
                ret = result
            else:
                raise Exception
        except Exception:
            try:
                ret = json.loads(result)
            except (ValueError, TypeError):
                try:
                    ret = xmltodict.parse(result, attr_prefix='')
                except:
                    pass

        # Fallback if we cant "parse the response"
        if ret is None:
            ret = result

        if (ret is not None or self._api_result_type
                == 'success') and self._api_authenticated:
            # To allow override for restart etc
            # if the call returns some data we are gonna assume its a success
            self._api_result_type = 'success'
            self._api_response_code = 200

        # Since some of them methods use a api like response for the ui
        # {result: error, message: 'Some shit happened'}
        if isinstance(ret, dict):
            if ret.get('message'):
                self._api_msg = ret.pop('message', None)

            if ret.get('result'):
                self._api_result_type = ret.pop('result', None)

        if self._api_result_type == 'success' and not self._api_response_code:
            self._api_response_code = 200
        elif self._api_result_type == 'error' and not self._api_response_code:
            self._api_response_code = 400

        if not self._api_response_code:
            self._api_response_code = 500

        cherrypy.response.status = self._api_response_code
        return self._api_out_as(
            self._api_responds(result_type=self._api_result_type,
                               msg=self._api_msg,
                               data=ret))
Beispiel #5
0
    def get_logs(self,
                 sort='',
                 search='',
                 order='desc',
                 regex='',
                 start=0,
                 end=0,
                 **kwargs):
        """
            Get the Tautulli logs.

            ```
            Required parameters:
                None

            Optional parameters:
                sort (str):         "time", "thread", "msg", "loglevel"
                search (str):       A string to search for
                order (str):        "desc" or "asc"
                regex (str):        A regex string to search for
                start (int):        Row number to start from
                end (int):          Row number to end at

            Returns:
                json:
                    [{"loglevel": "DEBUG",
                      "msg": "Latest version is 2d10b0748c7fa2ee4cf59960c3d3fffc6aa9512b",
                      "thread": "MainThread",
                      "time": "2016-05-08 09:36:51 "
                      },
                     {...},
                     {...}
                     ]
            ```
        """
        logfile = os.path.join(plexpy.CONFIG.LOG_DIR, logger.FILENAME)
        templog = []
        start = int(start)
        end = int(end)

        if regex:
            logger.api_debug(
                "Tautulli APIv2 :: Filtering log using regex '%s'" % regex)
            reg = re.compile(regex, flags=re.I)

        with open(logfile, 'r') as f:
            for line in f.readlines():
                temp_loglevel_and_time = None

                try:
                    temp_loglevel_and_time = line.split('- ')
                    loglvl = temp_loglevel_and_time[1].split(' :')[0].strip()
                    tl_tread = line.split(' :: ')
                    if loglvl is None:
                        msg = line.replace('\n', '')
                    else:
                        msg = line.split(' : ')[1].replace('\n', '')
                    thread = tl_tread[1].split(' : ')[0]
                except IndexError:
                    # We assume this is a traceback
                    tl = (len(templog) - 1)
                    templog[tl]['msg'] += helpers.sanitize(
                        str(line.replace('\n', ''), 'utf-8'))
                    continue

                if len(
                        line
                ) > 1 and temp_loglevel_and_time is not None and loglvl in line:

                    d = {
                        'time':
                        temp_loglevel_and_time[0],
                        'loglevel':
                        loglvl,
                        'msg':
                        helpers.sanitize(str(msg.replace('\n', ''), 'utf-8')),
                        'thread':
                        thread
                    }
                    templog.append(d)

        if order == 'desc':
            templog = templog[::-1]

        if end > 0 or start > 0:
            logger.api_debug(
                "Tautulli APIv2 :: Slicing the log from %s to %s" %
                (start, end))
            templog = templog[start:end]

        if sort:
            logger.api_debug("Tautulli APIv2 :: Sorting log based on '%s'" %
                             sort)
            templog = sorted(templog, key=lambda k: k[sort])

        if search:
            logger.api_debug(
                "Tautulli APIv2 :: Searching log values for '%s'" % search)
            tt = [
                d for d in templog for k, v in d.items()
                if search.lower() in v.lower()
            ]

            if len(tt):
                templog = tt

        if regex:
            tt = []
            for l in templog:
                stringdict = ' '.join('{}{}'.format(k, v)
                                      for k, v in l.items())
                if reg.search(stringdict):
                    tt.append(l)

            if len(tt):
                templog = tt

        return templog