Skip to content
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Pasos para iniciar proyecto

Primero tener descargado sqlite e iniciar el ejecutable de sqlite3.
[Link de descarga del .zip](https://www.sqlite.org/2023/sqlite-tools-win-x64-3440200.zip)


1. `pip install -r requirements.txt`
2. `python manage.py makemigrations`
3. `python manage.py migrate`
4. `python manage.py createsuperuser`
5. `python manage.py runserver`
6. Ingresar a tu navegador en el puerto 8000 [http://127.0.0.1:8000/](http://127.0.0.1:8000/)
2 changes: 1 addition & 1 deletion djangocrud/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/

STATIC_URL = 'static/'
STATIC_URL = '/static/'

LOGIN_URL = '/signin'

Expand Down
3 changes: 2 additions & 1 deletion djangocrud/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@
path('signup/', views.signup, name='signup'),
path('tasks/', views.tasks, name='tasks'),
path('tasks_completed/', views.tasks_completed, name='tasks_completed'),
path('shared_tasks/', views.shared_tasks, name='shared_tasks'),
path('logout/', views.signout, name='logout'),
path('signin/', views.signin, name='signin'),
path('create_task/', views.create_task, name='create_task'),
path('tasks/<int:task_id>', views.task_detail, name='task_detail'),
path('taks/<int:task_id>/complete', views.complete_task, name='complete_task'),
path('tasks/<int:task_id>/complete', views.complete_task, name='complete_task'),
path('tasks/<int:task_id>/delete', views.delete_task, name='delete_task'),
]
13 changes: 10 additions & 3 deletions tasks/forms.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
from django.forms import ModelForm
from django import forms
from django.contrib.auth.models import User
from .models import Task

class TaskForm(ModelForm):
class TaskForm(forms.ModelForm):
shared_with = forms.ModelMultipleChoiceField(
queryset=User.objects.all(),
widget=forms.CheckboxSelectMultiple,
required=False,
)

class Meta:
model = Task
fields = ['title', 'description', 'important']
fields = ['title', 'description', 'important', 'shared']
2 changes: 2 additions & 0 deletions tasks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class Task(models.Model):
datecompleted = models.DateTimeField(null=True, blank=True)
important = models.BooleanField(default=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
shared = models.BooleanField(default=False)
shared_with = models.ManyToManyField(User, related_name='shared_tasks', blank=True)

def __str__(self):
return self.title + ' - ' + self.user.username
14 changes: 11 additions & 3 deletions tasks/templates/create_task.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@

{% block content %}

<h1>CReate task</h1>
<h1>Create task</h1>

{{error}}
<form action="/create_task/" method="POST">
{% csrf_token %}
{{form}}

{{form.title.label_tag}} {{form.title}}
<br>
{{form.description.label_tag}} {{form.description}}
<br>
{{form.important}} {{form.important.label_tag}}
<br>
{{form.shared}} {{form.shared.label_tag}}
<br>
{{ form.shared_with.label_tag }} {{ form.shared_with }}
<br>
<button>Save</button>
</form>
{% endblock %}
14 changes: 9 additions & 5 deletions tasks/templates/task_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,32 @@

{{task.title}}

{% if_is_shared_task %}
<p>This is a shared task</p>
{% endif %}

{{error}}

<form method="POST">
{% csrf_token %}
{{form.as_p}}

<button>
<button type="submit">
Update
</button>
</form>

<form action="{% url 'complete_task' task.id %}" method="POST">
{% csrf_token %}
<button>
complete
<button type="submit">
Complete
</button>
</form>

<form action="{% url 'delete_task' task.id %}" method="POST">
{% csrf_token %}
<button>
delete
<button type="submit">
Delete
</button>
</form>

Expand Down
10 changes: 10 additions & 0 deletions tasks/templates/tasks.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

<h1>tasks</h1>

<form>
<label for="filter">Filter:</label>
<select name="filter" id="filter">
<option value="all" {% if filter_type == 'all' %}selected{% endif %}>ALL</option>
<option value="shared" {% if filter_type == 'shared' %}selected{% endif %}>Shared</option>
<option value="normal" {% if filter_type == 'normal' %}selected{% endif %}>Normal</option>
</select>
<button type="submit">Apply</button>
</form>

<ul>
{% for task in tasks %}
<li>
Expand Down
51 changes: 50 additions & 1 deletion tasks/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,52 @@
from django.test import TestCase
from django.contrib.auth.models import User
from django.urls import reverse
from .models import Task

# Create your tests here.
class SharedTasksTestCase(TestCase):
username_template = 'EGRM23'
password_template = 'V6E388KR'
title_template = 'Tarea Compartida'
description_template = 'Esta es una tarea compartida'

def setUp(self):
user_exists = User.objects.filter(username=self.username_template).exists()
if not user_exists:
User.objects.create_user(
username=self.username_template,
password=self.password_template
)

users_data = [
{'username': 'UsuarioPrueba1', 'password': 'contra1molde'},
{'username': 'UsuarioPrueba2', 'password': 'contra2molde'},
{'username': 'UsuarioPrueba3', 'password': 'contra3molde'},
]

for user_data in users_data:
user_exists = User.objects.filter(username=user_data['username']).exists()
if not user_exists:
User.objects.create_user(
username=user_data['username'],
password=user_data['password']
)

self.client.login(username=self.username_template, password=self.password_template)

def test_create_shared_task(self):
user1_id = User.objects.get(username='UsuarioPrueba1').id
user2_id = User.objects.get(username='UsuarioPrueba2').id

response = self.client.post(reverse('create_task'), {
'title': self.username_template,
'description': self.description_template,
'shared': True,
'shared_with': [user1_id, user2_id]
})
self.assertEqual(response.status_code, 302)
self.assertTrue(Task.objects.filter(title=self.username_template, shared=True).exists())

def test_view_shared_tasks(self):
response = self.client.get(reverse('shared_tasks'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, self.username_template)
29 changes: 20 additions & 9 deletions tasks/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@
from django.utils import timezone
from django.contrib.auth.decorators import login_required
from .models import Task

from .forms import TaskForm

# Create your views here.


def signup(request):
signup_template = 'signup.html'
if request.method == 'GET':
return render(request, 'signup.html', {"form": UserCreationForm})
return render(request, signup_template, {"form": UserCreationForm})
else:

if request.POST["password1"] == request.POST["password2"]:
Expand All @@ -25,15 +22,25 @@ def signup(request):
login(request, user)
return redirect('tasks')
except IntegrityError:
return render(request, 'signup.html', {"form": UserCreationForm, "error": "Username already exists."})
return render(request, signup_template, {"form": UserCreationForm, "error": "Username already exists."})

return render(request, 'signup.html', {"form": UserCreationForm, "error": "Passwords did not match."})
return render(request, signup_template, {"form": UserCreationForm, "error": "Passwords did not match."})


@login_required
def tasks(request):
tasks = Task.objects.filter(user=request.user, datecompleted__isnull=True)
return render(request, 'tasks.html', {"tasks": tasks})
filter_type = request.GET.get('filter','all')
if filter_type == 'shared':
tasks = tasks.filter(shared=True)
elif filter_type == 'normal':
tasks = tasks.filter(shared=False)
return render(request, 'tasks.html', {"tasks": tasks, "filter_type": filter_type})

@login_required
def shared_tasks(request):
shared_tasks = Task.objects.filter(shared=True)
return render(request, 'shared_tasks.html', {"tasks": shared_tasks})

@login_required
def tasks_completed(request):
Expand All @@ -51,6 +58,8 @@ def create_task(request):
new_task = form.save(commit=False)
new_task.user = request.user
new_task.save()
shared_with_users = request.POST.getlist('shared_with')
new_task.shared_with.set(shared_with_users)
return redirect('tasks')
except ValueError:
return render(request, 'create_task.html', {"form": TaskForm, "error": "Error creating task."})
Expand Down Expand Up @@ -82,8 +91,9 @@ def signin(request):
def task_detail(request, task_id):
if request.method == 'GET':
task = get_object_or_404(Task, pk=task_id, user=request.user)
is_shared_task = task.shared
form = TaskForm(instance=task)
return render(request, 'task_detail.html', {'task': task, 'form': form})
return render(request, 'task_detail.html', {'task': task, 'form': form, 'is_shared_task': is_shared_task})
else:
try:
task = get_object_or_404(Task, pk=task_id, user=request.user)
Expand All @@ -98,6 +108,7 @@ def complete_task(request, task_id):
task = get_object_or_404(Task, pk=task_id, user=request.user)
if request.method == 'POST':
task.datecompleted = timezone.now()
task.shared = request.POST.get('shared', False)
task.save()
return redirect('tasks')

Expand Down