From 0ae09a4daa5e2fc5196bb86445e226b7564b88dd Mon Sep 17 00:00:00 2001 From: task_manager contributor Date: Mon, 29 Jun 2026 16:59:59 -0300 Subject: [PATCH 1/2] docs: add contributing guide --- CONTRIBUTING.md | 339 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 291 insertions(+), 48 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3f4c6cc..383999b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,93 +1,336 @@ -# Contributing to DevBoard +# Contribuindo com task_manager -Welcome! DevBoard is an open-hours project built on top of the [Navas Task Manager API](https://dev.to/navas_herbert/building-a-rest-api-with-fastapi-from-scratch-full-crud-sqlite-middleware-cors-j92). -The goal is to evolve a basic FastAPI CRUD app into a full collaborative task board - one PR at a time. +Olá! 👋 Seja muito bem-vindo(a) ao projeto task_manager. Este repositório é um espaço aberto para aprender, colaborar e melhorar um gerenciador de tarefas com a comunidade. Nossa ideia é manter um ambiente acolhedor, profissional e fácil de contribuir, inclusive para quem está começando no GitHub e no desenvolvimento. -Every merged contribution is a real open source commit on your GitHub profile. +Este documento reúne as principais diretrizes para você participar de forma organizada e tranquila. + +## Índice + +- [Como Começar](#como-começar) +- [Fluxo de Contribuição](#fluxo-de-contribuição) +- [Convenções](#convenções) +- [Tipos de Commit](#tipos-de-commit) +- [Checklist de Pull Request](#checklist-de-pull-request) +- [Perguntas Frequentes](#perguntas-frequentes-faqs) +- [Rodapé](#rodapé) --- -## How to Contribute +## Como Começar + +### Pré-requisitos + +Antes de contribuir, certifique-se de ter instalado: + +- Git +- Uma conta no GitHub +- Python 3.8+ (a versão 3.10 ou 3.11 é recomendada) + +Se você ainda não tiver o Git configurado, pode usar os comandos abaixo para definir seu nome e e-mail: + +```bash +git config --global user.name "Seu Nome" +git config --global user.email "seuemail@example.com" +``` -### 1. Fork the repo +### 1. Faça o fork do repositório -Click the **Fork** button at the top right of this page. +No GitHub, abra a página do repositório e clique em “Fork”. Isso cria uma cópia do projeto na sua conta. -### 2. Clone your fork +Depois, acesse o seu fork e copie o URL remoto. + +### 2. Clone o fork para sua máquina ```bash -git clone git@github.com:Navashub/task_manager.git +git clone https://github.com/SEU_USUARIO/task_manager.git cd task_manager ``` -### 3. Create a branch +### 3. Configure o remote upstream + +O remote upstream aponta para o repositório original. Isso facilita manter seu fork atualizado. + +```bash +git remote -v +git remote add upstream https://github.com/OWNER/task_manager.git +git remote -v +``` + +> ⚠️ Se o remote upstream já existir, use o comando abaixo para atualizar o endereço: + +```bash +git remote set-url upstream https://github.com/OWNER/task_manager.git +``` + +--- + +## Fluxo de Contribuição -Use this naming convention: +A seguir, veja o fluxo principal para enviar uma contribuição com segurança e organização. + +### 1. Escolher uma issue + +Antes de começar, confira as issues abertas e escolha uma que faça sentido para você. Se estiver começando, prefira tarefas marcadas como “good first issue” ou “beginner-friendly”. + +Você pode comentar na issue para dizer que vai trabalhar nela, evitando duplicidade. + +### 2. Criar uma branch + +Sempre crie uma branch específica para a sua mudança. + +Exemplos de nomes: ```bash -git checkout -b feature/your-issue-name -# e.g. feature/add-priority-field -# e.g. fix/pagination-off-by-one +git checkout -b feature/adicionar-prioridade +# ou +git checkout -b fix/corrigir-validacao +# ou +git checkout -b docs/atualizar-readme +# ou +git checkout -b refactor/organizar-crud ``` -### 4. Make your changes +### 3. Fazer as mudanças + +Mantenha as alterações focadas no que foi proposto. Evite misturar correções, refatorações e novas funcionalidades em um único commit, a menos que seja realmente necessário. -- Keep changes focused on the issue you picked. -- Follow the existing code style (snake_case, type hints, Pydantic schemas). -- Test your changes locally before submitting. +### 4. Fazer commit com mensagem bem formatada -### 5. Commit with a clear message +Use mensagens claras e objetivas. ```bash git add . -git commit -m "feat: add priority field to Task model (#1)" +git commit -m "feat: adicionar campo de prioridade à tarefa" ``` -Prefix convention: -- `feat:` - new feature -- `fix:` - bug fix -- `docs:` - documentation only -- `test:` - adding or updating tests -- `refactor:` - code change with no feature/fix +### 5. Fazer push da branch + +```bash +git push -u origin feature/adicionar-prioridade +``` + +### 6. Abrir um Pull Request + +No GitHub, clique em “Compare & pull request”. Escolha a branch do seu fork como origem e a branch principal do repositório original como destino. + +### 7. Descrever o Pull Request corretamente + +Um bom PR explica o que foi feito, por que foi feito e como validar. + +Estrutura recomendada: + +- Resumo da mudança +- Motivação +- Alterações principais +- Como testar +- Issue relacionada + +Exemplo: + +```md +## Resumo +Adicionei um campo de prioridade às tarefas. + +## Motivo +Melhorar a organização das tarefas por urgência. + +## Alterações +- Adicionei o campo `priority` ao modelo +- Atualizei o schema de entrada +- Ajustei a documentação + +## Testes +- Executei a aplicação localmente +- Validei os endpoints no Swagger +``` + +--- + +## Convenções + +### Estrutura de branches + +Use nomes curtos, em minúsculas e com hífen: + +- `feature/` — novas funcionalidades +- `fix/` — correções de bugs +- `docs/` — atualização de documentação +- `refactor/` — reorganização de código +- `test/` — testes +- `chore/` — manutenção e ajustes menores + +Exemplos: + +```bash +git checkout -b feature/adicionar-filtro +``` + +### Formato de mensagens de commit + +O padrão recomendado é: -### 6. Push and open a Pull Request +```text +tipo(escopo): descrição +``` + +Exemplos: ```bash -git push origin feature/your-issue-name +git commit -m "feat(tasks): adicionar campo de prioridade" +git commit -m "fix(users): corrigir validação de e-mail" +git commit -m "docs(readme): atualizar instruções de instalação" ``` -Then open a PR on GitHub against the `main` branch of `Navashub/task_manager`. +### Exemplos de bons e maus commits + +Bons commits: + +- `feat(tasks): adicionar status de conclusão` +- `fix(api): corrigir erro ao deletar tarefa` +- `docs(readme): incluir passo a passo para Windows` + +Commits que podem melhorar: + +- `arrumei coisa` +- `update` +- `teste` +- `fix bug` + +Mensagens vagas dificultam a revisão e o histórico do projeto. + +### Estilo de código + +Para manter o código consistente: + +- Use indentação de 4 espaços em Python +- Siga o estilo PEP 8 sempre que possível +- Prefira nomes claros e descritivos para funções e variáveis +- Use `snake_case` para funções e variáveis +- Use `CamelCase` apenas quando o padrão do projeto exigir +- Comente apenas quando necessário, sem exagerar +- Evite código duplicado e mudanças desnecessárias --- -## PR Checklist +## Tipos de Commit + +Os tipos abaixo ajudam a entender rapidamente a intenção da alteração: -Before submitting, make sure: +- `feat` — nova funcionalidade +- `fix` — correção de bug +- `docs` — atualização ou criação de documentação +- `style` — formatação, ajustes visuais ou organização sem alterar lógica +- `refactor` — refatoração sem mudança de comportamento externo +- `test` — inclusão ou ajuste de testes +- `chore` — manutenção, configuração e tarefas auxiliares -- [ ] The app still runs (`uvicorn main:app --reload`) -- [ ] Your endpoint(s) appear and work in `/docs` -- [ ] You haven't introduced unused imports or dead code -- [ ] You've updated the README if you added a new endpoint or changed behaviour -- [ ] Your branch name matches the issue you're solving +Exemplos práticos: + +```bash +git commit -m "feat: adicionar filtro por status" +git commit -m "fix: corrigir erro ao salvar tarefa vazia" +git commit -m "docs: melhorar guia de contribuição" +``` --- -## Picking an Issue +## Checklist de Pull Request -Issues are labelled by difficulty: +Antes de enviar seu PR, faça estas validações: -| Label | Who it's for | -|---|---| -| `good-first-issue` | Just getting started with FastAPI | -| `intermediate` | Comfortable with models, schemas, routers | -| `advanced` | Ready for auth, testing, or DevOps | -| `frontend` | HTML/CSS/JS or React work | -| `devops` | Docker, PostgreSQL, deployment | +- [ ] O código foi testado localmente +- [ ] A aplicação roda sem erros +- [ ] A mudança está relacionada à issue escolhida +- [ ] A documentação foi atualizada, se necessário +- [ ] Não há prints de debug ou código comentado desnecessário +- [ ] A branch possui um nome claro e objetivo +- [ ] A mensagem do commit está bem escrita -Comment on an issue before starting so others know it's taken. +### Como sincronizar com a branch principal + +Antes de abrir o PR, é uma boa prática manter sua branch atualizada com a `main`. + +```bash +git fetch upstream +git checkout main +git merge upstream/main +git checkout sua-branch +git merge main +``` + +### Como resolver conflitos + +Se aparecerem conflitos: + +1. Abra os arquivos marcados como conflitantes +2. Ajuste as partes necessárias +3. Adicione os arquivos resolvidos +4. Continue o merge ou o rebase + +```bash +git add +git commit +``` + +> ⚠️ Se o conflito parecer complicado, peça ajuda na issue ou no PR. Não precisa resolver sozinho se estiver inseguro(a). --- -## Questions? +## Perguntas Frequentes (FAQs) + +### Como sincronizar meu fork com o repositório original? + +```bash +git fetch upstream +git checkout main +git merge upstream/main +git push origin main +``` + +### Como desfazer commits? + +Se quiser remover o último commit, mas manter as alterações no seu computador: + +```bash +git reset --soft HEAD~1 +``` + +Se quiser apagar o commit e também descartar as mudanças: + +```bash +git reset --hard HEAD~1 +``` + +### Como atualizar minha branch com mudanças da main? + +```bash +git fetch upstream +git checkout sua-branch +git merge upstream/main +``` + +### Como fazer correções após o PR ser rejeitado? + +Não se preocupe. Correções são parte normal do processo. Faça as alterações, crie um novo commit e envie com push novamente. O PR será atualizado automaticamente. + +```bash +git add . +git commit -m "fix: corrigir pontos levantados na revisão" +git push +``` + +--- + +## Rodapé + +Obrigado por investir seu tempo em melhorar este projeto. Cada contribuição, mesmo a menor, ajuda a tornar o task_manager melhor para a comunidade. Se tiver dúvidas, não hesite em abrir uma issue ou comentar em uma discussão — qualquer pergunta é válida, especialmente quando o objetivo é aprender. + +### Links úteis + +- [README](README.md) +- [Issues](https://github.com/OWNER/task_manager/issues) +- [Pull Requests](https://github.com/OWNER/task_manager/pulls) + +### Data -Reach out on WhatsApp or open a GitHub Discussion. Don't be afraid to ask - that's what open hours is for. +Última atualização: 29/06/2026 From 42cbc39f12af01defc1ed919f2bc07d849f081c4 Mon Sep 17 00:00:00 2001 From: task_manager contributor Date: Mon, 29 Jun 2026 17:13:59 -0300 Subject: [PATCH 2/2] feat: add pagination to task and user list endpoints --- README.md | 4 +- crud.py | 8 ++-- routers/tasks.py | 4 +- routers/users.py | 4 +- tests/test_pagination.py | 89 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 tests/test_pagination.py diff --git a/README.md b/README.md index 6357b21..829d4c5 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ All 10 endpoints are grouped neatly by resource - **Users** and **Tasks** - with | Method | URL | Description | |--------|-----|-------------| | `POST` | `/users/` | Create a new user | -| `GET` | `/users/` | List all users | +| `GET` | `/users/` | List users with optional `skip` and `limit` query params | | `GET` | `/users/{id}` | Get one user (includes their tasks) | | `PUT` | `/users/{id}` | Update a user's name or email | | `DELETE` | `/users/{id}` | Delete a user | @@ -110,7 +110,7 @@ All 10 endpoints are grouped neatly by resource - **Users** and **Tasks** - with | Method | URL | Description | |--------|-----|-------------| | `POST` | `/tasks/` | Create a new task | -| `GET` | `/tasks/` | List all tasks | +| `GET` | `/tasks/` | List tasks with optional `skip` and `limit` query params | | `GET` | `/tasks/{id}` | Get one task by ID | | `PUT` | `/tasks/{id}` | Update a task | | `DELETE` | `/tasks/{id}` | Delete a task | diff --git a/crud.py b/crud.py index 4de4386..ad5ffba 100644 --- a/crud.py +++ b/crud.py @@ -14,8 +14,8 @@ def get_user(db: Session, user_id: int): return db.query(models.User).filter(models.User.id == user_id).first() -def get_users(db: Session): - return db.query(models.User).all() +def get_users(db: Session, skip: int = 0, limit: int = 10): + return db.query(models.User).offset(skip).limit(limit).all() @@ -29,8 +29,8 @@ def create_task(db:Session, task: schemas.TaskCreate): def get_task(db:Session, task_id: int): return db.query(models.Task).filter(models.Task.id == task_id).first() -def get_tasks(db: Session): - return db.query(models.Task).all() +def get_tasks(db: Session, skip: int = 0, limit: int = 10): + return db.query(models.Task).offset(skip).limit(limit).all() def update_task(db:Session, task_id: int, data: schemas.TaskUpdate): db_task = db.query(models.Task).filter(models.Task.id == task_id).first() diff --git a/routers/tasks.py b/routers/tasks.py index 368791f..11b8199 100644 --- a/routers/tasks.py +++ b/routers/tasks.py @@ -12,8 +12,8 @@ def create_task(task: schemas.TaskCreate, db: Session = Depends(get_db)): @router.get("/", response_model=List[schemas.TaskResponse]) -def get_tasks(db: Session = Depends(get_db)): - return crud.get_tasks(db) +def get_tasks(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): + return crud.get_tasks(db, skip=skip, limit=limit) @router.get("/{task_id}", response_model=schemas.TaskResponse) diff --git a/routers/users.py b/routers/users.py index 7f738a9..c449950 100644 --- a/routers/users.py +++ b/routers/users.py @@ -12,8 +12,8 @@ def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)): @router.get("/", response_model=List[schemas.UserResponse]) -def get_users(db: Session = Depends(get_db)): - return crud.get_users(db) +def get_users(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): + return crud.get_users(db, skip=skip, limit=limit) @router.get("/{user_id}", response_model=schemas.UserResponse) def get_user(user_id: int, db: Session = Depends(get_db)): diff --git a/tests/test_pagination.py b/tests/test_pagination.py new file mode 100644 index 0000000..4b02a43 --- /dev/null +++ b/tests/test_pagination.py @@ -0,0 +1,89 @@ +import os +import tempfile +import unittest + +from fastapi.testclient import TestClient +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +import database +import main +import models + + +class PaginationTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.temp_db = tempfile.NamedTemporaryFile(suffix=".db", delete=False) + cls.temp_db.close() + + database.engine = create_engine( + f"sqlite:///{cls.temp_db.name}", + connect_args={"check_same_thread": False}, + ) + database.SessionLocal = sessionmaker( + autocommit=False, + autoflush=False, + bind=database.engine, + ) + models.Base.metadata.create_all(bind=database.engine) + cls.client = TestClient(main.app) + + @classmethod + def tearDownClass(cls): + if hasattr(cls, "client"): + cls.client.close() + if hasattr(database, "SessionLocal"): + database.SessionLocal.close_all() + if hasattr(database, "engine"): + database.engine.dispose() + if os.path.exists(cls.temp_db.name): + try: + os.remove(cls.temp_db.name) + except PermissionError: + pass + + def setUp(self): + db = database.SessionLocal() + try: + db.query(models.Task).delete() + db.query(models.User).delete() + db.commit() + + for index in range(12): + user = models.User(name=f"User {index}", email=f"user{index}@example.com") + db.add(user) + db.commit() + + users = db.query(models.User).all() + for index, user in enumerate(users): + db.add(models.Task(title=f"Task {index}", description="desc", owner_id=user.id)) + db.commit() + finally: + db.close() + + def test_tasks_pagination(self): + response = self.client.get("/tasks/") + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.json()), 10) + + paged_response = self.client.get("/tasks/", params={"skip": 5, "limit": 5}) + self.assertEqual(paged_response.status_code, 200) + data = paged_response.json() + self.assertEqual(len(data), 5) + self.assertEqual(data[0]["title"], "Task 5") + + def test_users_pagination(self): + response = self.client.get("/users/") + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.json()), 10) + + paged_response = self.client.get("/users/", params={"skip": 5, "limit": 5}) + self.assertEqual(paged_response.status_code, 200) + data = paged_response.json() + self.assertEqual(len(data), 5) + self.assertEqual(data[0]["email"], "user5@example.com") + + +if __name__ == "__main__": + unittest.main()