Ejemplo n.º 1
0
def format_podcast_list(obj_list, format, title, get_podcast=None,
        json_map=lambda x: x.url, jsonp_padding=None,
        xml_template=None, request=None, template_args={}):
    """
    Formats a list of podcasts for use in a API response

    obj_list is a list of podcasts or objects that contain podcasts
    format is one if txt, opml or json
    title is a label of the list
    if obj_list is a list of objects containing podcasts, get_podcast is the
      function used to get the podcast out of the each of these objects
    json_map is a function returning the contents of an object (from obj_list)
      that should be contained in the result (only used for format='json')
    """

    def default_get_podcast(p):
        return p

    get_podcast = get_podcast or default_get_podcast

    if format == 'txt':
        podcasts = map(get_podcast, obj_list)
        s = '\n'.join([p.url for p in podcasts] + [''])
        return HttpResponse(s, content_type='text/plain')

    elif format == 'opml':
        podcasts = map(get_podcast, obj_list)
        exporter = Exporter(title)
        opml = exporter.generate(podcasts)
        return HttpResponse(opml, content_type='text/xml')

    elif format == 'json':
        objs = list(map(json_map, obj_list))
        return JsonResponse(objs)

    elif format == 'jsonp':
        ALLOWED_FUNCNAME = string.ascii_letters + string.digits + '_'

        if not jsonp_padding:
            return HttpResponseBadRequest('For a JSONP response, specify the name of the callback function in the jsonp parameter')

        if any(x not in ALLOWED_FUNCNAME for x in jsonp_padding):
            return HttpResponseBadRequest('JSONP padding can only contain the characters %(char)s' % {'char': ALLOWED_FUNCNAME})

        objs = map(json_map, obj_list)
        return JsonResponse(objs, jsonp_padding=jsonp_padding)

    elif format == 'xml':
        if None in (xml_template, request):
            return HttpResponseBadRequest('XML is not a valid format for this request')

        podcasts = map(json_map, obj_list)
        template_args.update({'podcasts': podcasts})

        return render(request, xml_template, template_args,
                content_type='application/xml')

    else:
        return None
Ejemplo n.º 2
0
def tag_podcasts(request, tag, count):
    count = parse_range(count, 1, 100, 100)
    try:
        category = Category.objects.get(tags__tag=tag)

    except Category.DoesNotExist:
        return JsonResponse([])

    domain = RequestSite(request).domain
    entries = category.entries.all().prefetch_related('podcast',
                                                      'podcast__slugs',
                                                      'podcast__urls')[:count]
    resp = [podcast_data(entry.podcast, domain) for entry in entries]
    return JsonResponse(resp)
Ejemplo n.º 3
0
    def get(self, request, username, device_uid):

        now = datetime.utcnow()
        now_ = get_timestamp(now)

        user = request.user

        try:
            device = user.client_set.get(uid=device_uid)
        except Client.DoesNotExist as e:
            return HttpResponseNotFound(str(e))

        try:
            since = self.get_since(request)
        except ValueError as e:
            return HttpResponseBadRequest(str(e))

        include_actions = parse_bool(request.GET.get("include_actions", False))

        domain = RequestSite(request).domain

        add, rem, subscriptions = self.get_subscription_changes(
            user, device, since, now, domain)
        updates = self.get_episode_changes(user, subscriptions, domain,
                                           include_actions, since)

        return JsonResponse({
            "add": add,
            "rem": rem,
            "updates": updates,
            "timestamp": get_timestamp(now),
        })
Ejemplo n.º 4
0
    def post(self, request, version, username, device_uid):
        """ Client sends subscription updates """
        now = get_timestamp(datetime.utcnow())
        logger.info(
            "Subscription Upload @{username}/{device_uid}".format(
                username=request.user.username, device_uid=device_uid
            )
        )

        d = get_device(
            request.user, device_uid, request.META.get("HTTP_USER_AGENT", "")
        )

        actions = self.parsed_body(request)

        add = list(filter(None, actions.get("add", [])))
        rem = list(filter(None, actions.get("remove", [])))
        logger.info(
            "Subscription Upload @{username}/{device_uid}: add "
            "{num_add}, remove {num_remove}".format(
                username=request.user.username,
                device_uid=device_uid,
                num_add=len(add),
                num_remove=len(rem),
            )
        )

        update_urls = self.update_subscriptions(request.user, d, add, rem)

        return JsonResponse({"timestamp": now, "update_urls": update_urls})
Ejemplo n.º 5
0
    def post(self, request, version, username, device_uid):
        """ Client sends subscription updates """
        now = get_timestamp(datetime.utcnow())
        logger.info('Subscription Upload @{username}/{device_uid}'.format(
            username=request.user.username, device_uid=device_uid))

        d = get_device(request.user, device_uid,
                       request.META.get('HTTP_USER_AGENT', ''))

        actions = self.parsed_body(request)

        add = list(filter(None, actions.get('add', [])))
        rem = list(filter(None, actions.get('remove', [])))
        logger.info('Subscription Upload @{username}/{device_uid}: add '
                    '{num_add}, remove {num_remove}'.format(
                        username=request.user.username,
                        device_uid=device_uid,
                        num_add=len(add),
                        num_remove=len(rem)))

        update_urls = self.update_subscriptions(request.user, d, add, rem)

        return JsonResponse({
            'timestamp': now,
            'update_urls': update_urls,
        })
Ejemplo n.º 6
0
 def get(self, request, version, username, device_uid):
     """ Client retrieves subscription updates """
     now = datetime.utcnow()
     user = request.user
     device = get_object_or_404(Client, user=user, uid=device_uid)
     since = self.get_since(request)
     add, rem, until = self.get_changes(user, device, since, now)
     return JsonResponse({"add": add, "remove": rem, "timestamp": until})
Ejemplo n.º 7
0
 def post(self, request, username, scope):
     """ Update settings for scope object """
     user = request.user
     scope = self.get_scope(request, scope)
     actions = self.parsed_body(request)
     settings = UserSettings.objects.get_for_scope(user, scope)
     resp = self.update_settings(settings, actions)
     return JsonResponse(resp)
Ejemplo n.º 8
0
def podcast_info(request):
    url = normalize_feed_url(request.GET.get('url', ''))

    # 404 before we query for url, because query would complain
    # about missing param
    if not url:
        raise Http404

    podcast = get_object_or_404(Podcast, urls__url=url)
    domain = RequestSite(request).domain
    resp = podcast_data(podcast, domain)

    return JsonResponse(resp)
Ejemplo n.º 9
0
def main(request, username):
    """ API Endpoint for Device Synchronisation """

    if request.method == "GET":
        return JsonResponse(get_sync_status(request.user))

    else:
        try:
            actions = parse_request_body(request)
        except ValueError as e:
            return HttpResponseBadRequest(str(e))

        synclist = actions.get("synchronize", [])
        stopsync = actions.get("stop-synchronize", [])

        try:
            update_sync_status(request.user, synclist, stopsync)
        except ValueError as e:
            return HttpResponseBadRequest(str(e))
        except Client.DoesNotExist as e:
            return HttpResponseNotFound(str(e))

        return JsonResponse(get_sync_status(request.user))
Ejemplo n.º 10
0
def add_podcast_status(request, job_id):
    url = request.GET.get('url', '')
    result = update_podcasts.AsyncResult(job_id)
    resp = {'id': str(job_id), 'type': 'create-podcast', 'url': url}

    if not result.ready():
        resp['status'] = 'pending'
    elif result.successful():
        resp['status'] = 'successful'
        resp['podcast'] = f'/api/2/data/podcast.json?url={url}'
    elif result.failed():
        resp['status'] = 'unsuccessful'
        resp['error'] = 'feed could not be parsed'

    return JsonResponse(resp)
Ejemplo n.º 11
0
def add_podcast_status(request, job_id):
    url = request.GET.get("url", "")
    result = update_podcasts.AsyncResult(job_id)
    resp = {"id": str(job_id), "type": "create-podcast", "url": url}

    if not result.ready():
        resp["status"] = "pending"
    elif result.successful():
        resp["status"] = "successful"
        resp["podcast"] = f"/api/2/data/podcast.json?url={url}"
    elif result.failed():
        resp["status"] = "unsuccessful"
        resp["error"] = "feed could not be parsed"

    return JsonResponse(resp)
Ejemplo n.º 12
0
    def post(self, request, username):
        """ Add / remove Chapters to/from an episode """
        user = request.user
        now_ = get_timestamp(datetime.utcnow())

        body = self.parsed_body(request)

        podcast_url, episode_url, update_urls = self.get_urls(body)
        body['podcast'] = podcast_url
        body['episode'] = episode_url

        if not podcast_url or not episode_url:
            raise RequestException('Invalid Podcast or Episode URL')

        self.update_chapters(body, user)
        return JsonResponse({'update_url': update_urls, 'timestamp': now_})
Ejemplo n.º 13
0
def get_lists(request, username):
    """ Returns a list of all podcast lists by the given user """

    User = get_user_model()
    user = User.objects.get(username=username)
    if not user:
        raise Http404

    lists = PodcastList.objects.filter(user=user)

    site = RequestSite(request)

    get_data = partial(_get_list_data, username=user.username,
                domain=site.domain)
    lists_data = list(map(get_data, lists))

    return JsonResponse(lists_data)
Ejemplo n.º 14
0
    def get(self, request, username):
        """ Get chapters for an episode """
        user = request.user
        now_ = get_timestamp(datetime.utcnow())

        podcast_url, episode_url, _update_urls = self.get_urls(request)

        episode = Episode.objects.filter(podcast__urls__url=podcast_url,
                                         urls__url=episode_url).get()

        chapters = Chapter.objects.filter(user=user, episode=episode)

        since = self.get_since(request)
        if since:
            chapters = chapters.filter(created__gte=since)

        chapters_json = map(self.chapter_to_json, chapters)

        return JsonResponse({'chapters': chapters_json, 'timestamp': now_})
Ejemplo n.º 15
0
def episode_info(request):
    podcast_url = normalize_feed_url(request.GET.get('podcast', ''))
    episode_url = normalize_feed_url(request.GET.get('url', ''))

    # 404 before we query for url, because query would complain
    # about missing parameters
    if not podcast_url or not episode_url:
        raise Http404

    try:
        query = Episode.objects.filter(podcast__urls__url=podcast_url,
                                       urls__url=episode_url)
        episode = query.select_related('podcast').get()
    except Episode.DoesNotExist:
        raise Http404

    domain = RequestSite(request).domain

    resp = episode_data(episode, domain)
    return JsonResponse(resp)
Ejemplo n.º 16
0
def episodes(request, username, version=1):

    version = int(version)
    now = datetime.utcnow()
    now_ = get_timestamp(now)
    ua_string = request.META.get('HTTP_USER_AGENT', '')

    if request.method == 'POST':
        try:
            actions = parse_request_body(request)
        except (UnicodeDecodeError, ValueError) as e:
            msg = ('Could not decode episode update POST data for ' +
                   'user %s: %s') % (username,
                                     request.body.decode('ascii',
                                                         errors='replace'))
            logger.warn(msg, exc_info=True)
            return HttpResponseBadRequest(msg)

        logger.info('start: user %s: %d actions from %s' %
                    (request.user, len(actions), ua_string))

        # handle in background
        if len(actions) > dsettings.API_ACTIONS_MAX_NONBG:
            bg_handler = dsettings.API_ACTIONS_BG_HANDLER
            if bg_handler is not None:

                modname, funname = bg_handler.rsplit('.', 1)
                mod = import_module(modname)
                fun = getattr(mod, funname)

                fun(request.user, actions, now, ua_string)

                # TODO: return 202 Accepted
                return JsonResponse({'timestamp': now_, 'update_urls': []})

        try:
            update_urls = update_episodes(request.user, actions, now,
                                          ua_string)
        except ValidationError as e:
            logger.warning(
                'Validation Error while uploading episode actions '
                'for user %s: %s', username, str(e))
            return HttpResponseBadRequest(str(e))

        except InvalidEpisodeActionAttributes as e:
            msg = 'invalid episode action attributes while uploading episode actions for user %s' % (
                username, )
            logger.warn(msg, exc_info=True)
            return HttpResponseBadRequest(str(e))

        logger.info('done:  user %s: %d actions from %s' %
                    (request.user, len(actions), ua_string))
        return JsonResponse({'timestamp': now_, 'update_urls': update_urls})

    elif request.method == 'GET':
        podcast_url = request.GET.get('podcast', None)
        device_uid = request.GET.get('device', None)
        since_ = request.GET.get('since', None)
        aggregated = parse_bool(request.GET.get('aggregated', False))

        try:
            since = int(since_) if since_ else None
            if since is not None:
                since = datetime.utcfromtimestamp(since)
        except ValueError:
            return HttpResponseBadRequest(
                'since-value is not a valid timestamp')

        if podcast_url:
            podcast = get_object_or_404(Podcast, urls__url=podcast_url)
        else:
            podcast = None

        if device_uid:

            try:
                user = request.user
                device = user.client_set.get(uid=device_uid)
            except Client.DoesNotExist as e:
                return HttpResponseNotFound(str(e))

        else:
            device = None

        changes = get_episode_changes(request.user, podcast, device, since,
                                      now, aggregated, version)

        return JsonResponse(changes)
Ejemplo n.º 17
0
 def get(self, request, username, scope):
     """ Get settings for scope object """
     user = request.user
     scope = self.get_scope(request, scope)
     settings = UserSettings.objects.get_for_scope(user, scope)
     return JsonResponse(settings.as_dict())
Ejemplo n.º 18
0
def top_tags(request, count):
    count = parse_range(count, 1, 100, 100)
    tag_cloud = Topics(count, num_cat=0)
    resp = list(map(category_data, tag_cloud.tagcloud))
    return JsonResponse(resp)
Ejemplo n.º 19
0
def episodes(request, username, version=1):

    version = int(version)
    now = datetime.utcnow()
    now_ = get_timestamp(now)
    ua_string = request.META.get("HTTP_USER_AGENT", "")

    if request.method == "POST":
        try:
            actions = parse_request_body(request)
        except (UnicodeDecodeError, ValueError) as e:
            msg = ("Could not decode episode update POST data for " +
                   "user %s: %s") % (
                       username,
                       request.body.decode("ascii", errors="replace"),
                   )
            logger.warning(msg, exc_info=True)
            return HttpResponseBadRequest(msg)

        logger.info("start: user %s: %d actions from %s" %
                    (request.user, len(actions), ua_string))

        # handle in background
        if (dsettings.API_ACTIONS_MAX_NONBG is not None
                and len(actions) > dsettings.API_ACTIONS_MAX_NONBG):
            bg_handler = dsettings.API_ACTIONS_BG_HANDLER
            if bg_handler is not None:

                modname, funname = bg_handler.rsplit(".", 1)
                mod = import_module(modname)
                fun = getattr(mod, funname)

                fun(request.user, actions, now, ua_string)

                # TODO: return 202 Accepted
                return JsonResponse({"timestamp": now_, "update_urls": []})

        try:
            update_urls = update_episodes(request.user, actions, now,
                                          ua_string)
        except ValidationError as e:
            logger.warning(
                "Validation Error while uploading episode actions "
                "for user %s: %s",
                username,
                str(e),
            )
            return HttpResponseBadRequest(str(e))

        except InvalidEpisodeActionAttributes as e:
            msg = (
                "invalid episode action attributes while uploading episode actions for user %s"
                % (username, ))
            logger.warning(msg, exc_info=True)
            return HttpResponseBadRequest(str(e))

        logger.info("done:  user %s: %d actions from %s" %
                    (request.user, len(actions), ua_string))
        return JsonResponse({"timestamp": now_, "update_urls": update_urls})

    elif request.method == "GET":
        podcast_url = request.GET.get("podcast", None)
        device_uid = request.GET.get("device", None)
        since_ = request.GET.get("since", None)
        aggregated = parse_bool(request.GET.get("aggregated", False))

        try:
            since = int(since_) if since_ else None
            if since is not None:
                since = datetime.utcfromtimestamp(since)
        except ValueError:
            return HttpResponseBadRequest(
                "since-value is not a valid timestamp")

        if podcast_url:
            podcast = get_object_or_404(Podcast, urls__url=podcast_url)
        else:
            podcast = None

        if device_uid:

            try:
                user = request.user
                device = user.client_set.get(uid=device_uid)
            except Client.DoesNotExist as e:
                return HttpResponseNotFound(str(e))

        else:
            device = None

        changes = get_episode_changes(request.user, podcast, device, since,
                                      now, aggregated, version)

        return JsonResponse(changes)
Ejemplo n.º 20
0
def favorites(request, username):
    favorites = FavoriteEpisode.episodes_for_user(request.user)
    domain = RequestSite(request).domain
    e_data = lambda e: episode_data(e, domain)
    ret = list(map(e_data, favorites))
    return JsonResponse(ret)
Ejemplo n.º 21
0
def devices(request, username, version=None):
    user = request.user
    clients = user.client_set.filter(deleted=False)
    client_data = [get_client_data(user, client) for client in clients]
    return JsonResponse(client_data)
Ejemplo n.º 22
0
    def get(self, request):

        cs = ClientStats()
        clients = cs.get_entries()

        return JsonResponse(map(self.to_dict, clients.most_common()))
Ejemplo n.º 23
0
 def get(self, request):
     stats = self._get_stats()
     return JsonResponse(stats)