Compare commits
7 Commits
latest
...
development
| Author | SHA1 | Date | |
|---|---|---|---|
| c33def1124 | |||
| 52dfa51af2 | |||
| a02617f8d2 | |||
| 53b4e89347 | |||
| df0579dd86 | |||
| 1022a44f12 | |||
| bb697d92c6 |
@@ -8,3 +8,4 @@ __pycache__/
|
|||||||
tienda/__pycache__/
|
tienda/__pycache__/
|
||||||
proyecto/__pycache__/
|
proyecto/__pycache__/
|
||||||
media
|
media
|
||||||
|
staticfiles
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# AGENTS.md - Django Tienda Project
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run tests (runs tienda/tests.py by default)
|
||||||
|
make test
|
||||||
|
|
||||||
|
# Or manually
|
||||||
|
python manage.py test
|
||||||
|
|
||||||
|
# Run dev server
|
||||||
|
python manage.py runserver
|
||||||
|
|
||||||
|
# Run migrations
|
||||||
|
python manage.py migrate
|
||||||
|
|
||||||
|
# Static files (production)
|
||||||
|
python manage.py collectstatic
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Redis**: Must be running on `redis://127.0.0.1:6379/1` for sessions and caching
|
||||||
|
- Start: `sudo systemctl start redis-server` (Linux) or `brew services start redis` (macOS)
|
||||||
|
- Verify: `redis-cli ping` → PONG
|
||||||
|
- **PostgreSQL**: Default database; set `POSTGRES_ENABLED=False` to use SQLite
|
||||||
|
- **Environment**: Copy `.env.example` to `.env` and configure required vars
|
||||||
|
|
||||||
|
## Important Quirks
|
||||||
|
|
||||||
|
1. **Migrations**: If `makemigrations` fails with error code 130, **check `tienda/migrations/`** - the file is often created despite the error
|
||||||
|
2. **Test DB**: Uses SQLite regardless of POSTGRES_ENABLED (hardcoded in settings.py)
|
||||||
|
3. **App URL**: Not at `/` - access at `http://localhost:8000/tienda/`
|
||||||
|
4. **Admin**: At `/admin/` (not `/tienda/admin/`)
|
||||||
|
5. **Custom User Model**: AUTH_USER_MODEL = 'tienda.User' - use for all user-related queries
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- `proyecto/` - Django settings, URLs, WSGI/ASGI
|
||||||
|
- `tienda/` - Main app (models, views, admin, templates)
|
||||||
|
- `tienda/static/` - CSS, JS, images, fonts
|
||||||
|
- Templates extend `tienda/templates/tienda/base.html`
|
||||||
|
|
||||||
|
## Shipping Restrictions
|
||||||
|
|
||||||
|
Only sells to Almería province, Spain (postal codes 04xxx). All addresses saved with country "España".
|
||||||
|
|
||||||
|
## External Services
|
||||||
|
|
||||||
|
- **Payment**: Stripe + PayPal (configured via .env)
|
||||||
|
- **Storage**: S3 support - set `S3_ENABLE=True` to enable
|
||||||
|
- **Email**: SMTP required (see .env.example)
|
||||||
|
- **Async**: Celery uses Redis broker
|
||||||
|
|
||||||
|
## Useful References
|
||||||
|
|
||||||
|
- Full developer docs: `.github/copilot-instructions.md`
|
||||||
|
- Redis setup: `docs/REDIS_SETUP.md`
|
||||||
|
- PayPal: `docs/PAYPAL_SETUP.md`, `docs/PAYPAL_TROUBLESHOOTING.md`
|
||||||
|
- View documentation: `docs/views/`
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+7
-2
@@ -33,7 +33,11 @@ def enviar_correo_confirmacion(id: int):
|
|||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def enviar_correo_recuperacion(email: str):
|
def enviar_correo_recuperacion(email: str):
|
||||||
usuario = User.objects.get(email=email)
|
usuario: User | None
|
||||||
|
try:
|
||||||
|
usuario = User.objects.get(email=email)
|
||||||
|
except User.DoesNotExist as e:
|
||||||
|
usuario = None
|
||||||
if usuario is not None:
|
if usuario is not None:
|
||||||
ver_code = VerificationCode.objects.create(
|
ver_code = VerificationCode.objects.create(
|
||||||
code_mode = VerificationCode.VerificationModes.RESET_PASSWORD,
|
code_mode = VerificationCode.VerificationModes.RESET_PASSWORD,
|
||||||
@@ -53,7 +57,8 @@ def enviar_correo_recuperacion(email: str):
|
|||||||
)
|
)
|
||||||
|
|
||||||
send_hemail(email, "Reset de Contraseña", html_content, "Estas reseteando la contraseña...")
|
send_hemail(email, "Reset de Contraseña", html_content, "Estas reseteando la contraseña...")
|
||||||
|
else:
|
||||||
|
print("User does not exist, Cancelling TASK.")
|
||||||
|
|
||||||
# Purchased items should be a list of dictionary, the dictionary must follow this tags: amount, product name, price (each)
|
# Purchased items should be a list of dictionary, the dictionary must follow this tags: amount, product name, price (each)
|
||||||
@shared_task
|
@shared_task
|
||||||
|
|||||||
+18
-1
@@ -240,7 +240,24 @@ def login(request: HttpRequest):
|
|||||||
|
|
||||||
# Autenticar usuario
|
# Autenticar usuario
|
||||||
user = authenticate(request, username=username, password=password)
|
user = authenticate(request, username=username, password=password)
|
||||||
if user is None: # Bug de error 500 en caso de fallar la contra
|
if user is None:
|
||||||
|
data: str = cache.get(f"tries_login_{username}")
|
||||||
|
logins: int
|
||||||
|
if data is None:
|
||||||
|
logins = int(data)
|
||||||
|
else:
|
||||||
|
logins = 0
|
||||||
|
|
||||||
|
if logins >= 5:
|
||||||
|
# Si ha fallado 5 intentos de login...
|
||||||
|
audit_logger.info(
|
||||||
|
"LOGIN_FAILED email=%s reason=rate_limited", username
|
||||||
|
)
|
||||||
|
messages.error(request, "Has sufrido de Rate Limit por fallar 5 veces la contraseña")
|
||||||
|
return render(request, "tienda/login.html")
|
||||||
|
|
||||||
|
logins+=1
|
||||||
|
cache.set(f"tries_login_{username}", str(logins), 600)
|
||||||
messages.error(request, "Correo electrónico o contraseña incorrectos.")
|
messages.error(request, "Correo electrónico o contraseña incorrectos.")
|
||||||
return render(request, "tienda/login.html")
|
return render(request, "tienda/login.html")
|
||||||
user = User.objects.get(username=user.username)
|
user = User.objects.get(username=user.username)
|
||||||
|
|||||||
Reference in New Issue
Block a user