Ejemplo n.º 1
0
def group(request: HttpRequest, g_id: int) -> HttpResponse:
    """
     View that serves a single group's page.

    :param request: The original request.
    :param g_id: The ID of the group.

    :return: A response with the rendered ``group.html`` template.

    :raises Http404: If the group does not exist.
    """
    if g_id == 0:
        raise Http404('Group ID cannot be 0')
    try:
        _group = Group.objects.get(id=g_id)
    except Group.DoesNotExist as e:
        raise Http404 from e
    members = _group.members \
        .prefetch_related('roles') \
        .order_by('name').distinct()
    url = request.path
    p_url = url.rsplit('/', 2)[0] + '/'
    crumbs = breadcrumbs([('Groups', request.build_absolute_uri(p_url)),
                          (_group.name, request.build_absolute_uri(url))])
    return render(request, 'group.html', {
        'group': _group,
        'members': list(members),
        'breadcrumbs': crumbs
    })
Ejemplo n.º 2
0
def profile(request: 'HttpRequest') -> HttpResponse:
    """
    View that serves the profile page of a user.
    A :class:`UserProfile` will be created if it doesn't exist.

    It serves the logged in user's profile by default, but accepts
    an ``id`` query parameter to view an arbitrary user's profile.

    :param request: The original request.

    :return: A response with the rendered ``profile.html`` template.

    :raises Http404: If there is no user with the specified ``id``.
    """
    try:
        uid = int(request.GET.get('id', request.user.id))
        prof = UserProfile.objects.get_or_create(user_id=uid)[0]
    except (ValueError, IntegrityError) as e:
        raise Http404 from e
    if uid != request.user.id and prof.user.is_superuser:
        raise Http404('Cannot view profile of superuser')
    uri = request.build_absolute_uri(request.path)
    crumbs = breadcrumbs([('User', uri)])
    return render(request, 'profile.html', {
        'profile': prof,
        'breadcrumbs': crumbs
    })
Ejemplo n.º 3
0
def directory(request: HttpRequest) -> HttpResponse:
    """
    View that serves a page which lists all the series.

    :param request: The original request.

    :return: A response with the rendered ``all_series.html`` template.
    """
    chapters = Chapter.objects.filter(
        published__lte=tz.now()).order_by('-published').defer(
            'file', 'views', 'modified')
    groups = Group.objects.only('name')
    q = Q(chapters__published__lte=tz.now())
    series = list(
        Series.objects.alias(chapter_count=Count('chapters', filter=q)).filter(
            chapter_count__gt=0).prefetch_related(
                Prefetch('chapters', queryset=chapters),
                Prefetch('chapters__groups',
                         queryset=groups)).distinct().order_by('title').only(
                             'title', 'slug', 'format',
                             'cover').exclude(licensed=True))
    uri = request.build_absolute_uri(request.path)
    crumbs = jsonld.breadcrumbs([('Reader', uri)])
    library = jsonld.carousel([s.get_absolute_url() for s in series])
    return render(request, 'directory.html', {
        'all_series': series,
        'library': library,
        'breadcrumbs': crumbs
    })
Ejemplo n.º 4
0
def breadcrumbs_ld(request: HttpRequest, page: FlatPage) -> str:
    """
    Create a JSON-LD ``<script>`` with the page's breadcrumbs.

    :param request: The original request.
    :param page: A :class:`FlatPage` object instance.

    :return: An HTML script tag.
    """
    uri = request.build_absolute_uri(page.url)
    crumbs = breadcrumbs([(page.title, uri)])
    return jsonld(crumbs, 'breadcrumbs')
Ejemplo n.º 5
0
def all_groups(request: 'HttpRequest') -> 'HttpResponse':
    """
     View that serves a page with all the groups.

    :param request: The original request.

    :return: A response with the rendered ``all_groups.html`` template.
    """
    uri = request.build_absolute_uri(request.path)
    crumbs = breadcrumbs([('Groups', uri)])
    return render(request, 'all_groups.html', {
        'groups': Group.objects.all(),
        'breadcrumbs': crumbs
    })
Ejemplo n.º 6
0
def directory(request: 'HttpRequest') -> 'HttpResponse':
    """
    View that serves a page which lists all the series.

    :param request: The original request.

    :return: A response with the rendered ``all_series.html`` template.
    """
    _series = Series.objects.prefetch_related('chapters').order_by('title')
    uri = request.build_absolute_uri(request.path)
    crumbs = jsonld.breadcrumbs([('Reader', uri)])
    library = jsonld.carousel([s.get_absolute_url() for s in _series])
    return render(request, 'directory.html', {
        'all_series': _series,
        'library': library,
        'breadcrumbs': crumbs
    })
Ejemplo n.º 7
0
    def setup(self, request: 'HttpRequest', *args, **kwargs):
        """
        Initialize attributes shared by all view methods.

        A :class:`~users.models.UserProfile` will be created
        if the request user does not yet have one.

        :param request: The original request.
        """
        super().setup(request)
        if request.user.is_authenticated:
            self.profile = UserProfile.objects \
                .get_or_create(user_id=request.user.id)[0]
            url = request.path
            p_url = url.rsplit('/', 2)[0] + '/'
            crumbs = breadcrumbs([('User', request.build_absolute_uri(p_url)),
                                  ('Edit', request.build_absolute_uri(url))])
            self.extra_context = {'breadcrumbs': crumbs}
Ejemplo n.º 8
0
def chapter_page(request: 'HttpRequest', slug: str, vol: int, num: float,
                 page: int) -> 'HttpResponse':
    """
    View that serves a chapter page.

    :param request: The original request.
    :param slug: The slug of the series.
    :param vol: The volume of the chapter.
    :param num: The number of the chapter.
    :param page: The number of the page.

    :return: A response with the rendered ``chapter.html`` template.

    :raises Http404: If there is no matching chapter or page.
    """
    if page == 0:
        raise Http404('Page cannot be 0')
    chapters = Chapter.objects.filter(series__slug=slug,
                                      published__lte=tz.now())
    try:
        current = chapters.select_related('series') \
            .prefetch_related('pages').get(volume=vol, number=num)
        all_pages = current.pages.all()
        curr_page = next(p for p in all_pages if p.number == page)
    except (Chapter.DoesNotExist, Page.DoesNotExist, StopIteration) as e:
        raise Http404 from e
    url = request.path
    p_url = url.rsplit('/', 4)[0] + '/'
    p2_url = url.rsplit('/', 5)[0] + '/'
    crumbs = jsonld.breadcrumbs([
        ('Reader', request.build_absolute_uri(p2_url)),
        (current.series.title, request.build_absolute_uri(p_url)),
        (current.title, request.build_absolute_uri(url))
    ])
    return render(
        request, 'chapter.html', {
            'all_chapters': chapters.reverse(),
            'curr_chapter': current,
            'next_chapter': current.next,
            'prev_chapter': current.prev,
            'all_pages': all_pages,
            'curr_page': curr_page,
            'breadcrumbs': crumbs
        })
Ejemplo n.º 9
0
    def get(self, request: 'HttpRequest', *args, **kwargs) -> HttpResponse:
        """
        Handle ``GET`` requests.

        :param request: The original request.

        :return: A response with the rendered
                 :obj:`template <EditUser.template_name>`.
        """
        url = request.path
        p_url = url.rsplit('/', 2)[0] + '/'
        crumbs = breadcrumbs([('User', request.build_absolute_uri(p_url)),
                              ('Bookmarks', request.build_absolute_uri(url))])
        chapters = Chapter.objects.filter(series_id__in=Subquery(
            Bookmark.objects.filter(user_id=request.user.id).values(
                'series'))).order_by('-published')
        token = UserProfile.objects.only('token') \
            .get_or_create(user_id=request.user.id)[0].token
        return self.render_to_response(
            self.get_context_data(releases=chapters,
                                  breadcrumbs=crumbs,
                                  token=token))
Ejemplo n.º 10
0
def series(request: 'HttpRequest', slug: str) -> 'HttpResponse':
    """
    View that serves the page of a single series.

    If the series doesn't have any published chapters,
    only staff members will be able to see it.

    :param request: The original request.
    :param slug: The slug of the series.

    :return: A response with the rendered ``series.html`` template.

    :raises Http404: If there is no series with the specified ``slug``.
    """
    try:
        _series = Series.objects.prefetch_related('chapters__groups',
                                                  'artists', 'categories',
                                                  'authors',
                                                  'aliases').get(slug=slug)
    except Series.DoesNotExist as e:
        raise Http404 from e
    chapters = _series.chapters.filter(published__lte=tz.now()).reverse()
    if not (request.user.is_staff or chapters):
        return render(
            request,
            'error.html', {
                'error_message': 'Sorry. This series is not yet available.',
                'error_status': 403
            },
            status=403)
    marked = (request.user.is_authenticated
              and request.user.bookmarks.filter(series=_series).exists())
    url = request.path
    p_url = url.rsplit('/', 2)[0] + '/'
    uri = request.build_absolute_uri(url)
    crumbs = jsonld.breadcrumbs([('Reader', request.build_absolute_uri(p_url)),
                                 (_series.title, uri)])
    book = jsonld.schema(
        'Book', {
            'url':
            uri,
            'name':
            _series.title,
            'abstract':
            _series.description,
            'author': [{
                '@type': 'Person',
                'name': au.name,
                'alternateName': au.aliases.names()
            } for au in _series.authors.iterator()],
            'illustrator': [{
                '@type': 'Person',
                'name': ar.name,
                'alternateName': ar.aliases.names()
            } for ar in _series.artists.iterator()],
            'alternateName':
            _series.aliases.names(),
            'genre':
            list(_series.categories.values_list('name', flat=True)),
            'creativeWorkStatus':
            ('Published' if _series.completed else 'Incomplete'),
            'dateCreated':
            _series.created.strftime('%F'),
            'dateModified':
            _series.modified.strftime('%F'),
            'bookFormat':
            'GraphicNovel',
        })
    return render(
        request, 'series.html', {
            'series': _series,
            'chapters': chapters,
            'marked': marked,
            'breadcrumbs': crumbs,
            'book_ld': book
        })
Ejemplo n.º 11
0
def chapter_page(request: HttpRequest, slug: str, vol: int, num: float,
                 page: int) -> HttpResponse:
    """
    View that serves a chapter page.

    :param request: The original request.
    :param slug: The slug of the series.
    :param vol: The volume of the chapter.
    :param num: The number of the chapter.
    :param page: The number of the page.

    :return: A response with the rendered ``chapter.html`` template.

    :raises Http404: If there is no matching chapter or page.
    """
    if page == 0:
        raise Http404('Page cannot be 0')
    chapters = list(
        Chapter.objects.filter(
            series__slug=slug, series__licensed=False,
            published__lte=tz.now()).select_related('series').only(
                'title', 'number', 'volume', 'published', 'final',
                'series__slug', 'series__cover', 'series__title',
                'series__format').reverse())
    if not chapters:
        raise Http404('No chapters for this series')
    max_ = len(chapters) - 1
    for idx, current in enumerate(chapters):
        if current == (vol, num):
            next_ = chapters[idx - 1] if idx > 0 else None
            prev_ = chapters[idx + 1] if idx < max_ else None
            break
    if page == 1:
        Chapter.track_view(id=current.id)
    all_pages = list(current.pages.all())
    try:
        curr_page = next(p for p in all_pages if p.number == page)
    except StopIteration as e:
        raise Http404('No such page') from e
    preload = list(
        filter(lambda p: curr_page < p < curr_page.number + 4, all_pages))
    tags = current.series.categories.values_list('name', flat=True)
    url = request.path
    p_url = url.rsplit('/', 4)[0] + '/'
    p2_url = url.rsplit('/', 5)[0] + '/'
    crumbs = jsonld.breadcrumbs([
        ('Reader', request.build_absolute_uri(p2_url)),
        (current.series.title, request.build_absolute_uri(p_url)),
        (current.title, request.build_absolute_uri(url))
    ])
    return render(
        request, 'chapter.html', {
            'all_chapters': chapters,
            'curr_chapter': current,
            'next_chapter': next_,
            'prev_chapter': prev_,
            'all_pages': all_pages,
            'curr_page': curr_page,
            'preload': preload,
            'breadcrumbs': crumbs,
            'tags': ','.join(tags)
        })