Skip to content

Commit

Permalink
feat: finished proj
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielDDHM committed Feb 21, 2022
0 parents commit 930aac7
Show file tree
Hide file tree
Showing 51 changed files with 1,526 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
104 changes: 104 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
## Modelagem do banco

![](modelage-desafio-backend.jpg)

## Download & Instruções para instalação.

* 1 - Clone o projeto: git clone
* 2 - cd desafio-backend
* 3 - Criar virtual environment: python -m venv venv
* 4 - venv\scripts\activate
* 5 - pip install -r requirements.txt
* 6 - python manage.py migrate
* 7 - python manage.py createsuperuser
* 8 - python manage.py runserver

## Tasklist

- [X] Implementar modelo de user personalizado
- [X] Criar models conforme modelagem
- [X] Implementação da autenticação JWT
- [X] CRUD Usuários
- [X] CRUD Categoria
- [X] CRUD Questões
- [X] Implementação do QUIZ
- [X] Implementação dos filtros do Rank


## Endpoints.

**User**:

* http://127.0.0.1:8000/api/users/register/
> Endpoint para registro de usuários.
* http://127.0.0.1:8000/api/users/login/
> Passando email e senha, assim você obterá seu token de acesso.
* http://127.0.0.1:8000/api/users/
> Listagem geral dos usuários.
* http://127.0.0.1:8000/api/users/profile/
> Perfil simples do usuário que fez a requisição.
* http://127.0.0.1:8000/api/users/update/:id/
> Alteração do perfil do usuário passando o ID, endpoint aguarda os fields: name, email e is_admin(Booleano)
* http://127.0.0.1:8000/api/users/delete/:id/
> Desativação do usuário, como boa prática acredito que nenhuma informação seja excluída apenas desativa.
**Categorias**:

* http://127.0.0.1:8000/api/questions/categories/
> Listagem das categorias cadastradas, se filtrado pelo admin busca todas, caso contrario busca apenas as ativas.
* http://127.0.0.1:8000/api/questions/create-category/
> Criação de uma nova categoria, aguarda o field name.
* http://127.0.0.1:8000/api/questions/update-category/:id/
> Atualização de uma categoria existente, aguarda o parâmetro pk e field name.
* http://127.0.0.1:8000/api/questions/delete-category/:id/
> Desativação de uma categoria existente, aguarda o parâmetro pk.
**Perguntas**:

* http://127.0.0.1:8000/api/questions/
> Listagem das perguntas cadastradas.
* http://127.0.0.1:8000/api/questions/create/
> Criação de uma nova pergunta, aguarda os fields: question, first_answer, second_answer, third_answer, correct_answer(1, 2 ou 3) e category(id).
* http://127.0.0.1:8000/api/questions/update/:id/
> Atualização de uma pergunta existente, aguarda o parâmetro pk e os fields: question, first_answer, second_answer, third_answer, correct_answer(1, 2 ou 3) e category(id).
* http://127.0.0.1:8000/api/questions/delete/:id/
> Desativação de uma pergunta existente, aguarda o parâmetro pk.
**Quiz**:

* http://127.0.0.1:8000/api/questions/quiz/
> Para jogar acesse o endpoint acima que listara as categorias.
* http://127.0.0.1:8000/api/questions/quiz/:id/
> Apos a categoria selecionada, passa para esse segundo endpoint com o parâmetro pk da categoria, **esse endpoint lhe retornará as 10 questões aleatórias**.
* http://127.0.0.1:8000/api/questions/quiz-answers/
> Por fim use esse endpoint para responder as questões, passando no form-data o id da pergunta e resposta.
**Rank**:

* http://127.0.0.1:8000/api/rank/
> Listagem dos quizzes respondidos.
* http://127.0.0.1:8000/api/rank/user/
> Pontuação do usuário que chamou o endpoint.
* http://127.0.0.1:8000/api/rank/user/:id/
> Pontuação do usuário por categoria, endpoint requer o pk da categoria.


Faltam alguns pontos como uma regra para só liberar as categorias que tiverem mais de 10 perguntas, e com o rank faltou a listagem por usuário e pontuação.


Empty file added backend/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions backend/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for backend 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/3.2/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

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

application = get_asgi_application()
166 changes: 166 additions & 0 deletions backend/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
from datetime import timedelta
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = (
"django-insecure-l6q3l%l)qn#^+ukwr^kgkdqwg1b_4@*-uk4*-&iot5huj15_-="
)

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# 3rd party
"rest_framework",
"rest_framework_simplejwt",
# LocalApps
"users.apps.UsersConfig",
"questions.apps.QuestionsConfig",
"rank.apps.RankConfig",
]

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 = "backend.urls"

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"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 = "backend.wsgi.application"


# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

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


# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

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",
},
]

REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_simplejwt.authentication.JWTAuthentication",
)
}

AUTH_USER_MODEL = "users.User"

# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = "pt-bt"

TIME_ZONE = "America/Manaus"

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = "/static/"

MEDIA_URL = "/images/"

STATIC_ROOT = BASE_DIR / "staticfiles"

STATICFILES_DIRS = [
BASE_DIR / "static",
]

MEDIA_ROOT = "static/images"

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(days=7),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"ROTATE_REFRESH_TOKENS": False,
"BLACKLIST_AFTER_ROTATION": True,
"UPDATE_LAST_LOGIN": False,
"ALGORITHM": "HS256",
"SIGNING_KEY": SECRET_KEY,
"VERIFYING_KEY": None,
"AUDIENCE": None,
"ISSUER": None,
"JWK_URL": None,
"LEEWAY": 0,
"AUTH_HEADER_TYPES": ("Bearer",),
"AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
"USER_ID_FIELD": "id",
"USER_ID_CLAIM": "user_id",
"USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
"TOKEN_TYPE_CLAIM": "token_type",
"JTI_CLAIM": "jti",
"SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
"SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
"SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
}
9 changes: 9 additions & 0 deletions backend/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
path("admin/", admin.site.urls),
path("api/users/", include("users.urls")),
path("api/questions/", include("questions.urls")),
path("api/rank/", include("rank.urls")),
]
16 changes: 16 additions & 0 deletions backend/wsgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
WSGI config for backend 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/3.2/howto/deployment/wsgi/
"""

import os

from django.core.wsgi import get_wsgi_application

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

application = get_wsgi_application()
22 changes: 22 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)


if __name__ == '__main__':
main()
Binary file added modelage-desafio-backend.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added questions/__init__.py
Empty file.
17 changes: 17 additions & 0 deletions questions/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from django.contrib import admin

from questions.models import Category, Question


@admin.register(Question)
class QuestionAdmin(admin.ModelAdmin):
model = Question
list_display = ["id", "category", "registered_by", "is_active"]
search_fields = ["category"]


@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
model = Category
list_display = ["id", "name", "is_active"]
search_fields = ["name"]
6 changes: 6 additions & 0 deletions questions/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class QuestionsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'questions'
Loading

0 comments on commit 930aac7

Please sign in to comment.