Skip to content

Commit

Permalink
feat: add module 12 files
Browse files Browse the repository at this point in the history
  • Loading branch information
guicarvalho committed Apr 27, 2024
1 parent 7736b24 commit 2f1e61f
Show file tree
Hide file tree
Showing 82 changed files with 2,133 additions and 0 deletions.
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
10 changes: 10 additions & 0 deletions 12 - Desenvolvimento fullstack com Django/desafio/cards/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from django.contrib import admin

from cards.models import Card


@admin.register(Card)
class CardAdmin(admin.ModelAdmin):
list_display = ("number", "user", "network", "status", "created_at")
list_filter = ("status", "network", "created_at")
search_fields = ("user__username", "status")
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.apps import AppConfig


class CardsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "cards"
verbose_name = "Cartão"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django import forms

from .models import Card


class CardForm(forms.ModelForm):
class Meta:
model = Card
fields = ["holder_name"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 5.0.4 on 2024-04-08 19:28

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


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='Card',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=20)),
('number', models.CharField(max_length=16)),
('holder_name', models.CharField(max_length=20)),
('network', models.CharField(choices=[('V', 'Visa'), ('M', 'Mastercard')], max_length=1)),
('expiration_date', models.CharField(max_length=5)),
('cvv', models.CharField(max_length=4)),
('status', models.CharField(choices=[('P', 'Pendente'), ('A', 'Aprovado'), ('E', 'Enviado'), ('R', 'Recebido')], default='P', max_length=1)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='cards', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-created_at'],
},
),
]
Empty file.
Binary file not shown.
Binary file not shown.
34 changes: 34 additions & 0 deletions 12 - Desenvolvimento fullstack com Django/desafio/cards/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from django.contrib.auth.models import User
from django.db import models


class Card(models.Model):
STATUS_CHOICES = (
("P", "Pendente"),
("A", "Aprovado"),
("E", "Enviado"),
("R", "Recebido"),
)

CARD_NETWORK = (
("V", "Visa"),
("M", "Mastercard"),
)

user = models.ForeignKey(User, on_delete=models.PROTECT, related_name="cards", verbose_name="Usuário")
name = models.CharField("Nome", max_length=20)
number = models.CharField("Número", max_length=16)
holder_name = models.CharField("Titular", max_length=20)
network = models.CharField("Rede", max_length=1, choices=CARD_NETWORK)
expiration_date = models.CharField("Data de expiração", max_length=5)
cvv = models.CharField("CVV", max_length=4)
status = models.CharField("Status", max_length=1, choices=STATUS_CHOICES, default=STATUS_CHOICES[0][0])
created_at = models.DateTimeField("Criado em", auto_now_add=True)
updated_at = models.DateTimeField("Alterado em", auto_now=True)

def __str__(self) -> str:
return f"Cartão {self.id} - {self.user.username} - {self.get_status_display()}"

class Meta:
verbose_name_plural = "Cartões"
ordering = ["-created_at"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{% extends 'base.html' %}

{% block content %}
<h2 class="my-4">Detalhes da Solicitação do Cartão</h2>
<div class="card" style="width: 20rem;">
<div class="card-body">
<h5 class="card-title">{{ card.name }}</h5>
<h6 class="card-subtitle mb-2 text-body-secondary">**** **** **** {{ card.number|slice:"12:" }}</h6>
<p class="card-text">{{ card.holder_name }}</p>
<span class="badge text-bg-{%if card.network == 'M'%}danger{% else %}primary{%endif%}">{{ card.get_network_display }}</span>
<span class="badge text-bg-{%if card.status == 'P'%}secondary{%endif%}{%if card.status == 'A'%}dark{%endif%}{%if card.status == 'E'%}info{%endif%}{%if card.status == 'R'%}success{%endif%}">{{ card.get_status_display }}</span>
</div>
</div>
<a class="d-block mt-4" href="{% url 'cards:view_requests' %}">Voltar às solicitações</a>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{% extends 'base.html' %}

{% block title %}Solicitar novo cartão{% endblock %}

{% load widget_tweaks %}

{% block content %}
<p><a href="{% url 'cards:view_requests' %}">Voltar</a></p>
<h2 class="my-4">Solicitar Novo Cartão</h2>
<div>
<form method="post" novalidate class="w-25">
{% csrf_token %}

{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}

{% for field in form %}
<div class="mb-3">
<label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
<div class="invalid-feedback">
{{ field.errors|first }}
</div>
{% else %}
{% render_field field class="form-control" %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Enviar Solicitação</button>
</form>
</div>
{% endblock %}


Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% extends 'base.html' %}

{% block content %}
<p>
<a href="{% url 'home' %}">Início</a> |
<a href="{% url 'cards:request_card' %}">Solicitar cartão</a>
</p>
<h2 class="my-4">Minhas Solicitações de Cartão</h2>
{% if user_requests %}
<div class="list-group">
{% for request in user_requests %}
<a href="{% url 'cards:card_details' request.id %}" class="list-group-item list-group-item-action">
Solicitação feita em: {{ request.created_at }} - Status: {{ request.get_status_display }}
</a>
{% endfor %}
</div>
{% else %}
<p>Você não tem solicitações de cartão.</p>
{% endif %}
{% endblock %}
10 changes: 10 additions & 0 deletions 12 - Desenvolvimento fullstack com Django/desafio/cards/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from django.urls import path

from . import views

app_name = "cards"
urlpatterns = [
path("request-card/", views.request_card, name="request_card"),
path("my-requests/", views.view_requests, name="view_requests"),
path("request-details/<int:card_id>/", views.card_details, name="card_details"),
]
54 changes: 54 additions & 0 deletions 12 - Desenvolvimento fullstack com Django/desafio/cards/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse

from .forms import CardForm
from .models import Card


@login_required
def request_card(request):
def generate_card_info() -> dict[str, str]:
import random
from datetime import UTC, datetime

cc_month = str(random.randint(1, 12)).zfill(2)
cc_year = str(datetime.now(UTC).year + 10)[2:]
return {
"name": "DIO Bank Platinum",
"number": "".join([str(random.randint(0, 9)) for _ in range(16)]),
"network": random.choice(["V", "M"]),
"expiration_date": f"{cc_month}/{cc_year}",
"cvv": "".join([str(random.randint(0, 9)) for _ in range(3)]),
}

if request.method == "POST":
form = CardForm(request.POST)
if form.is_valid():
card_info = generate_card_info()

card_request = form.save(commit=False)
card_request.user = request.user
card_request.name = card_info["name"]
card_request.number = card_info["number"]
card_request.network = card_info["network"]
card_request.expiration_date = card_info["expiration_date"]
card_request.cvv = card_info["cvv"]
card_request.save()

return redirect(reverse("cards:view_requests"))
else:
form = CardForm()
return render(request, "cards/request_card.html", {"form": form})


@login_required
def view_requests(request):
user_requests = Card.objects.filter(user=request.user).order_by("-created_at")
return render(request, "cards/view_requests.html", {"user_requests": user_requests})


@login_required
def card_details(request, card_id):
card = get_object_or_404(Card, id=card_id, user=request.user)
return render(request, "cards/card_details.html", {"card": card})
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
16 changes: 16 additions & 0 deletions 12 - Desenvolvimento fullstack com Django/desafio/config/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for config project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')

application = get_asgi_application()
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = os.environ.get("SECRET_KEY", default="secret")

DEBUG = True

ALLOWED_HOSTS = []

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"widget_tweaks",
"cards.apps.CardsConfig",
]

MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]

ROOT_URLCONF = "config.urls"

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]

WSGI_APPLICATION = "config.wsgi.application"

DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}

AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]

LANGUAGE_CODE = "pt-br"

TIME_ZONE = "America/Sao_Paulo"

USE_I18N = True

USE_TZ = True

STATIC_URL = "static/"

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

LOGIN_REDIRECT_URL = "home"

LOGOUT_REDIRECT_URL = "home"
12 changes: 12 additions & 0 deletions 12 - Desenvolvimento fullstack com Django/desafio/config/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.contrib import admin
from django.contrib.auth import views as auth_views
from django.urls import include, path
from django.views.generic.base import TemplateView

urlpatterns = [
path("admin/", admin.site.urls),
path("login/", auth_views.LoginView.as_view(), name="login"),
path("logout/", auth_views.LogoutView.as_view(), name="logout"),
path("", TemplateView.as_view(template_name="home.html"), name="home"),
path("cards/", include("cards.urls", namespace="cards")),
]
16 changes: 16 additions & 0 deletions 12 - Desenvolvimento fullstack com Django/desafio/config/wsgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
WSGI config for config project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/
"""

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')

application = get_wsgi_application()
Binary file not shown.
Loading

0 comments on commit 2f1e61f

Please sign in to comment.