Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contrib/env-sample
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ DEBUG=True
SECRET_KEY=Change for a secret here
ALLOWED_HOSTS=localhost, 127.0.0.1
SENTRY_DSN=
DATABASE_URL=

# Amazon S3 configuration
DJANGO_AWS_ACCESS_KEY_ID=
Expand Down
13 changes: 9 additions & 4 deletions pythonpro/modules/admin.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
from django.contrib import admin
from ordered_model.admin import OrderedModelAdmin

from pythonpro.modules.models import Section, Module
from pythonpro.modules.models import Section, Module, Chapter


class ModuleAdmin(OrderedModelAdmin):
list_display = 'title slug order move_up_down_links'.split()


class SectionAdmin(OrderedModelAdmin):
list_display = 'title slug module order move_up_down_links'.split()


class ModuleAdmin(OrderedModelAdmin):
list_display = 'title slug order move_up_down_links'.split()
class ChapterAdmin(OrderedModelAdmin):
list_display = 'title slug section order move_up_down_links'.split()


admin.site.register(Section, SectionAdmin)
admin.site.register(Module, ModuleAdmin)
admin.site.register(Section, SectionAdmin)
admin.site.register(Chapter, ChapterAdmin)
8 changes: 8 additions & 0 deletions pythonpro/modules/chapters_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.urls import path

from pythonpro.modules import chapters_views

app_name = 'chapters'
urlpatterns = [
path('<slug:slug>/', chapters_views.detail, name='detail'),
]
8 changes: 8 additions & 0 deletions pythonpro/modules/chapters_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.shortcuts import render

from pythonpro.modules import facade


def detail(request, slug):
ctx = {'chapter': facade.get_chapter_with_contents(slug=slug)}
return render(request, 'chapters/chapter_detail.html', context=ctx)
40 changes: 35 additions & 5 deletions pythonpro/modules/facade.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.db.models import Prefetch

from pythonpro.modules.models import Section as _Section, Module as _Module
from pythonpro.modules.models import Section as _Section, Module as _Module, Chapter as _Chapter


def get_all_modules():
Expand All @@ -11,16 +11,46 @@ def get_all_modules():
return tuple(_Module.objects.order_by('order'))


def get_module_sections(slug):
def get_module_with_sections_and_chapters(slug):
"""
Search for a module with respective sections
:param slug: module slugs
Search for a module with respective sections and chapters
:param slug: module's slug
:return: Module with respective section on attribute sections
"""

return _Module.objects.filter(slug=slug).prefetch_related(
Prefetch(
'section_set',
queryset=_Section.objects.order_by('order'),
queryset=_Section.objects.order_by('order').prefetch_related(
Prefetch(
'chapter_set',
queryset=_Chapter.objects.order_by('order'),
to_attr='chapters'
)
),
to_attr='sections')
).get()


def get_section_with_module_and_chapters(slug):
"""
Search for a section with respective module and chapters
:param slug: section's slug
:return: Section
"""
return _Section.objects.filter(slug=slug).select_related('module').prefetch_related(
Prefetch(
'chapter_set',
queryset=_Chapter.objects.order_by('order'),
to_attr='chapters'
)
).get()


def get_chapter_with_contents(slug):
"""
Search for a chapter respective to slug with it's module and section
:param slug: chapter's slug
:return: Chapter
"""
return _Chapter.objects.filter(slug=slug).select_related('section').select_related('section__module').get()
1 change: 1 addition & 0 deletions pythonpro/modules/fixtures/pythonpro_chapters.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"model": "modules.chapter", "pk": 1, "fields": {"order": 0, "title": "Introdu\u00e7\u00e3o", "description": "Nesse cap\u00edtulo voc\u00ea vai conferir a motiva\u00e7\u00e3o do curso, ou seja, como o jogo ficar\u00e1 ap\u00f3s a implementa\u00e7\u00e3o. Logo depois voc\u00ea vai aprender como instalar o Python em seu sistema operacional, editar c\u00f3digo e fazer pequenos testes no console.", "slug": "introducao-python-birds", "section": 1}}, {"model": "modules.chapter", "pk": 2, "fields": {"order": 1, "title": "Tipos Embutidos", "description": "Nesse cap\u00edtulo voc\u00ea vai aprender sobre os tipos embutidos. Eles formam um conjunto b\u00e1sicos de classes que serve para modelar o seu programa como n\u00fameros e palavras.", "slug": "tipos-embutidos", "section": 1}}]
1 change: 1 addition & 0 deletions pythonpro/modules/fixtures/pythonpro_sections.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"model": "modules.section", "pk": 1, "fields": {"order": 0, "title": "Programa\u00e7\u00e3o Procedural", "description": "Nessa se\u00e7\u00e3o voc\u00ea vai aprender programa\u00e7\u00e3o procedural. Esse paradigma consiste em voc\u00ea definir a resolu\u00e7\u00e3o de um problema, passo a passo, de forma linear. Funciona como uma receita culin\u00e1ria, onde cada passado \u00e9 definido exatamente um depois do outro.", "slug": "programacao-procedural", "module": 1}}, {"model": "modules.section", "pk": 2, "fields": {"order": 1, "title": "Orienta\u00e7\u00e3o a Objetos", "description": "Depois de aprende o paradigma procedural na se\u00e7\u00e3o anterior chega hora de conhecer outro: a Orienta\u00e7\u00e3o a Objetos (OO). Voc\u00ea vai aprender sobre classes e seus componentes, heran\u00e7a e utilizar esses conceitos para implementar o jogo Python Birds. Como toda mudan\u00e7a de paradigma, demora um tempo para se acostumar, mas \u00e9 importante aprender bem OO porque ela utilizada em in\u00fameras bibliotecas e frameworks.", "slug": "orientacao-a-objetos", "module": 1}}]
28 changes: 28 additions & 0 deletions pythonpro/modules/migrations/0006_chapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 2.0.3 on 2018-03-17 16:03

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('modules', '0005_auto_20180314_1817'),
]

operations = [
migrations.CreateModel(
name='Chapter',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('order', models.PositiveIntegerField(db_index=True, editable=False)),
('title', models.CharField(max_length=50)),
('description', models.TextField()),
('slug', models.SlugField(unique=True)),
('section', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='modules.Section')),
],
options={
'ordering': ['section', 'order'],
},
),
]
14 changes: 14 additions & 0 deletions pythonpro/modules/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,17 @@ def get_absolute_url(self):

def parent(self):
return self.module


class Chapter(Content):
section = models.ForeignKey('Section', on_delete=models.CASCADE)
order_with_respect_to = 'section'

class Meta:
ordering = ['section', 'order']

def get_absolute_url(self):
return reverse('chapters:detail', kwargs={'slug': self.slug})

def parent(self):
return self.section
4 changes: 2 additions & 2 deletions pythonpro/modules/modules_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
from django.shortcuts import render

# Create your views here.
from pythonpro.modules.facade import get_module_sections, get_all_modules
from pythonpro.modules.facade import get_module_with_sections_and_chapters, get_all_modules


@login_required
def detail(request, slug):
module = get_module_sections(slug)
module = get_module_with_sections_and_chapters(slug)
return render(request, 'modules/module_detail.html', {'module': module})


Expand Down
6 changes: 3 additions & 3 deletions pythonpro/modules/sections_views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from django.shortcuts import render, get_object_or_404
from django.shortcuts import render

from pythonpro.modules.models import Section
from pythonpro.modules import facade


def detail(request, slug):
ctx = {'section': get_object_or_404(Section, slug=slug)}
ctx = {'section': facade.get_section_with_module_and_chapters(slug=slug)}
return render(request, 'sections/section_detail.html', ctx)
31 changes: 31 additions & 0 deletions pythonpro/modules/templates/chapters/chapter_detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{% extends 'core/base.html' %}
{% load static %}

{% block title %}{{ chapter.title }}{% endblock %}

{% block body %}
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
{% for title, url in chapter.breadcrumb %}
{% if not forloop.last %}
<li class="breadcrumb-item"><a href="{{ url }}">{{ title }}</a></li>
{% else %}
<li class="breadcrumb-item active" aria-current="page">{{ title }}</li>
{% endif %}
{% endfor %}
</ol>
</nav>
<div class="container">
<div class="row">
<div class="col">
<h1 class="mt-4 mb-3">{{ chapter.title }}</h1>
<dt>Descrição</dt>
<dd>
<ul>
<li>{{ chapter.description }}</li>
</ul>
</dd>
</div>
</div>
</div>
{% endblock body %}
13 changes: 11 additions & 2 deletions pythonpro/modules/templates/modules/module_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,20 @@ <h1 class="mt-4 mb-3">{{ module.title }}</h1>
<ol>
{% for section in module.sections %}
<li><a href="{{ section.get_absolute_url }}">{{ section.title }}</a></li>
<dd>
<ol>
{% for chapter in section.chapters %}
<li><a href="{{chapter.get_absolute_url}}">{{ chapter.title }}</a></li>
{% empty %}
<li>Nenhum Capítulo definido ainda</li>
{% endfor %}
</ol>
</dd>
{% empty %}
<li>Nenhuma seção definida ainda</li>
{% endfor %}
</li>
</ol>
</li>
</ol>
</dd>
</div>
</div>
Expand Down
10 changes: 10 additions & 0 deletions pythonpro/modules/templates/sections/section_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ <h1 class="mt-4 mb-3">{{ section.title }}</h1>
<li>{{ section.description }}</li>
</ul>
</dd>
<dt>Capítulos</dt>
<dd>
<ol>
{% for chapter in section.chapters %}
<li><a href="{{ chapter.get_absolute_url }}">{{ chapter.title }}</a></li>
{% empty %}
<li>Nenhum Capítulo definido ainda</li>
{% endfor %}
</ol>
</dd>
</div>
</div>
</div>
Expand Down
75 changes: 75 additions & 0 deletions pythonpro/modules/tests/test_chapters_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import pytest
from django.urls import reverse
from model_mommy import mommy

from pythonpro.django_assertions import dj_assert_contains
from pythonpro.modules.models import Section, Module, Chapter


@pytest.fixture
def module(db):
return mommy.make(Module)


@pytest.fixture
def section(module):
return mommy.make(Section, module=module)


@pytest.fixture
def chapter(section):
return mommy.make(Chapter, section=section)


@pytest.fixture
def chapters(section):
return mommy.make(Chapter, 2, section=section)


@pytest.fixture
def resp_section(client, django_user_model, section, chapters):
user = mommy.make(django_user_model)
client.force_login(user)
return client.get(reverse('sections:detail', kwargs={'slug': section.slug}))


def test_chapter_title_on_section(resp_section, chapters):
for chapter in chapters:
dj_assert_contains(resp_section, chapter.title)


def test_chapter_url_on_section(resp_section, chapters):
for chapter in chapters:
dj_assert_contains(resp_section, chapter.get_absolute_url())


@pytest.fixture
def resp(client, chapter, django_user_model):
user = mommy.make(django_user_model)
client.force_login(user)
return client.get(reverse('chapters:detail', kwargs={'slug': chapter.slug}))


def test_status_code(resp):
assert resp.status_code == 200


def test_breadcrumb_module(resp, module):
dj_assert_contains(
resp,
f'<li class="breadcrumb-item"><a href="{module.get_absolute_url()}">{module.title}</a></li>'
)


def test_breadcrumb_section(resp, section):
dj_assert_contains(
resp,
f'<li class="breadcrumb-item"><a href="{section.get_absolute_url()}">{section.title}</a></li>'
)
#
#
# def test_breadcrumb_current(resp, section):
# dj_assert_contains(
# resp,
# f'<li class="breadcrumb-item active" aria-current="page">{section.title}</li>'
# )
36 changes: 32 additions & 4 deletions pythonpro/modules/tests/test_module_detail_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from pythonpro.django_assertions import dj_assert_contains
from pythonpro.modules import facade
from pythonpro.modules.models import Section, Module
from pythonpro.modules.models import Section, Module, Chapter


def generate_resp(slug, client):
Expand Down Expand Up @@ -79,10 +79,38 @@ def python_birds(modules):


@pytest.fixture
def resp_with_user(client_with_user, sections, python_birds):
def resp_with_sections(client_with_user, sections, python_birds):
return client_with_user.get(reverse('modules:detail', kwargs={'slug': python_birds.slug}))


def test_sections_urls(resp_with_user, sections):
def test_section_titles(resp_with_sections, sections):
for section in sections:
dj_assert_contains(resp_with_user, section.get_absolute_url())
dj_assert_contains(resp_with_sections, section.title)


def test_section_urls(resp_with_sections, sections):
for section in sections:
dj_assert_contains(resp_with_sections, section.get_absolute_url())


@pytest.fixture
def chapters(sections):
result = []
for section in sections:
result.extend(mommy.make(Chapter, 2, section=section))
return result


@pytest.fixture
def resp_with_chapters(client_with_user, python_birds, sections, chapters):
return resp_with_sections(client_with_user, sections, python_birds)


def test_chapter_titles(resp_with_chapters, chapters):
for chapter in chapters:
dj_assert_contains(resp_with_chapters, chapter.title)


def test_chapter_urls(resp_with_chapters, chapters):
for chapter in chapters:
dj_assert_contains(resp_with_chapters, chapter.get_absolute_url())
2 changes: 1 addition & 1 deletion pythonpro/tests/test_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@


def test_urls_len():
assert 12 == len(urlpatterns)
assert 13 == len(urlpatterns)
Loading