diff --git a/base_urls.py b/base_urls.py
index 24c9f32..8e3c5f5 100644
--- a/base_urls.py
+++ b/base_urls.py
@@ -10,6 +10,4 @@ For your project, ignore this file and add
to your site's urlconf.
"""
-urlpatterns = [
- path('lists/', include('todo.urls')),
-]
+urlpatterns = [path("lists/", include("todo.urls"))]
diff --git a/test_settings.py b/test_settings.py
index 81007c8..4cb22ce 100644
--- a/test_settings.py
+++ b/test_settings.py
@@ -2,11 +2,7 @@ import os
DEBUG = (True,)
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
-DATABASES = {
- "default": {
- "ENGINE": "django.db.backends.sqlite3"
- }
-}
+DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3"}}
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
@@ -65,28 +61,12 @@ TEMPLATES = [
]
LOGGING = {
- 'version': 1,
- 'disable_existing_loggers': False,
- 'handlers': {
- 'console': {
- 'class': 'logging.StreamHandler',
- },
- },
- 'loggers': {
- '': {
- 'handlers': ['console'],
- 'level': 'DEBUG',
- 'propagate': True,
- },
- 'django': {
- 'handlers': ['console'],
- 'level': 'WARNING',
- 'propagate': True,
- },
- 'django.request': {
- 'handlers': ['console'],
- 'level': 'DEBUG',
- 'propagate': True,
- },
+ "version": 1,
+ "disable_existing_loggers": False,
+ "handlers": {"console": {"class": "logging.StreamHandler"}},
+ "loggers": {
+ "": {"handlers": ["console"], "level": "DEBUG", "propagate": True},
+ "django": {"handlers": ["console"], "level": "WARNING", "propagate": True},
+ "django.request": {"handlers": ["console"], "level": "DEBUG", "propagate": True},
},
}
diff --git a/todo/__init__.py b/todo/__init__.py
index c3d3df8..7139c3b 100644
--- a/todo/__init__.py
+++ b/todo/__init__.py
@@ -1,12 +1,12 @@
"""
A multi-user, multi-group task management and assignment system for Django.
"""
-__version__ = '2.4.6'
+__version__ = "2.4.6"
-__author__ = 'Scot Hacker'
-__email__ = 'shacker@birdhouse.org'
+__author__ = "Scot Hacker"
+__email__ = "shacker@birdhouse.org"
-__url__ = 'https://github.com/shacker/django-todo'
-__license__ = 'BSD License'
+__url__ = "https://github.com/shacker/django-todo"
+__license__ = "BSD License"
from . import check
diff --git a/todo/check.py b/todo/check.py
index 68560ce..67ec10c 100644
--- a/todo/check.py
+++ b/todo/check.py
@@ -11,9 +11,7 @@ def dal_check(app_configs, **kwargs):
return []
errors = []
- missing_apps = {'dal', 'dal_select2'} - set(settings.INSTALLED_APPS)
+ missing_apps = {"dal", "dal_select2"} - set(settings.INSTALLED_APPS)
for missing_app in missing_apps:
- errors.append(
- Error('{} needs to be in INSTALLED_APPS'.format(missing_app))
- )
+ errors.append(Error("{} needs to be in INSTALLED_APPS".format(missing_app)))
return errors
diff --git a/todo/features.py b/todo/features.py
index 8cd084e..a6f6b3e 100644
--- a/todo/features.py
+++ b/todo/features.py
@@ -11,5 +11,6 @@ except ImportError:
HAS_TASK_MERGE = False
if HAS_AUTOCOMPLETE:
import dal.autocomplete
- if getattr(dal.autocomplete, 'Select2QuerySetView', None) is not None:
+
+ if getattr(dal.autocomplete, "Select2QuerySetView", None) is not None:
HAS_TASK_MERGE = True
diff --git a/todo/mail/delivery.py b/todo/mail/delivery.py
index 33f916f..8477172 100644
--- a/todo/mail/delivery.py
+++ b/todo/mail/delivery.py
@@ -1,8 +1,9 @@
import importlib
+
def _declare_backend(backend_path):
- backend_path = backend_path.split('.')
- backend_module_name = '.'.join(backend_path[:-1])
+ backend_path = backend_path.split(".")
+ backend_module_name = ".".join(backend_path[:-1])
class_name = backend_path[-1]
def backend(*args, headers={}, from_address=None, **kwargs):
@@ -17,9 +18,10 @@ def _declare_backend(backend_path):
_backend.from_address = from_address
_backend.headers = headers
return _backend
+
return backend
-smtp_backend = _declare_backend('django.core.mail.backends.smtp.EmailBackend')
-console_backend = _declare_backend('django.core.mail.backends.console.EmailBackend')
-locmem_backend = _declare_backend('django.core.mail.backends.locmem.EmailBackend')
+smtp_backend = _declare_backend("django.core.mail.backends.smtp.EmailBackend")
+console_backend = _declare_backend("django.core.mail.backends.console.EmailBackend")
+locmem_backend = _declare_backend("django.core.mail.backends.locmem.EmailBackend")
diff --git a/todo/mail/producers/imap.py b/todo/mail/producers/imap.py
index 977c76f..af00358 100644
--- a/todo/mail/producers/imap.py
+++ b/todo/mail/producers/imap.py
@@ -70,14 +70,12 @@ def imap_producer(
try:
yield message
except Exception:
- logger.exception(
- f"something went wrong while processing {message_uid}"
- )
+ logger.exception(f"something went wrong while processing {message_uid}")
raise
if not preserve:
# tag the message for deletion
- conn.store(message_uid, '+FLAGS', '\\Deleted')
+ conn.store(message_uid, "+FLAGS", "\\Deleted")
else:
logger.debug("did not receive any message")
finally:
diff --git a/todo/management/commands/hopper.py b/todo/management/commands/hopper.py
index 933656b..1b322bf 100644
--- a/todo/management/commands/hopper.py
+++ b/todo/management/commands/hopper.py
@@ -18,7 +18,7 @@ def gen_title(tc=True):
# faker doesn't provide a way to generate headlines in Title Case, without periods, so make our own.
# With arg `tc=True`, Title Cases The Generated Text
fake = Faker()
- thestr = fake.text(max_nb_chars=32).rstrip('.')
+ thestr = fake.text(max_nb_chars=32).rstrip(".")
if tc:
thestr = titlecase(thestr)
@@ -29,7 +29,7 @@ def gen_content():
# faker provides paragraphs as a list; convert with linebreaks
fake = Faker()
grafs = fake.paragraphs()
- thestr = ''
+ thestr = ""
for g in grafs:
thestr += "{}\n\n".format(g)
return thestr
@@ -43,11 +43,12 @@ class Command(BaseCommand):
"-d",
"--delete",
help="Wipe out existing content before generating new.",
- action="store_true")
+ action="store_true",
+ )
def handle(self, *args, **options):
- if options.get('delete'):
+ if options.get("delete"):
# Wipe out previous contents? Cascade deletes the Tasks from the TaskLists.
TaskList.objects.all().delete()
print("Content from previous run deleted.")
@@ -56,11 +57,11 @@ class Command(BaseCommand):
fake = Faker() # Use to create user's names
# Create users and groups, add different users to different groups. Staff user is in both groups.
- sd_group, created = Group.objects.get_or_create(name='Scuba Divers')
- bw_group, created = Group.objects.get_or_create(name='Basket Weavers')
+ sd_group, created = Group.objects.get_or_create(name="Scuba Divers")
+ bw_group, created = Group.objects.get_or_create(name="Basket Weavers")
# Put user1 and user2 in one group, user3 and user4 in another
- usernames = ['user1', 'user2', 'user3', 'user4', 'staffer']
+ usernames = ["user1", "user2", "user3", "user4", "staffer"]
for username in usernames:
if get_user_model().objects.filter(username=username).exists():
user = get_user_model().objects.get(username=username)
@@ -70,15 +71,16 @@ class Command(BaseCommand):
first_name=fake.first_name(),
last_name=fake.last_name(),
email="{}@example.com".format(username),
- password="todo")
+ password="todo",
+ )
- if username in ['user1', 'user2']:
+ if username in ["user1", "user2"]:
user.groups.add(bw_group)
- if username in ['user3', 'user4']:
+ if username in ["user3", "user4"]:
user.groups.add(sd_group)
- if username == 'staffer':
+ if username == "staffer":
user.is_staff = True
user.first_name = fake.first_name()
user.last_name = fake.last_name()
@@ -91,7 +93,9 @@ class Command(BaseCommand):
TaskListFactory.create_batch(5, group=sd_group)
TaskListFactory.create(name="Public Tickets", slug="tickets", group=bw_group)
- print("For each of two groups, created fake tasks in each of {} fake lists.".format(num_lists))
+ print(
+ "For each of two groups, created fake tasks in each of {} fake lists.".format(num_lists)
+ )
class TaskListFactory(factory.django.DjangoModelFactory):
@@ -120,9 +124,11 @@ class TaskFactory(factory.django.DjangoModelFactory):
task_list = None # Pass this in
note = factory.LazyAttribute(lambda o: gen_content())
priority = factory.LazyAttribute(lambda o: random.randint(1, 100))
- completed = factory.Faker('boolean', chance_of_getting_true=30)
- created_by = factory.LazyAttribute(lambda o: get_user_model().objects.get(username='staffer')) # Randomized in post
- created_date = factory.Faker('date_this_year')
+ completed = factory.Faker("boolean", chance_of_getting_true=30)
+ created_by = factory.LazyAttribute(
+ lambda o: get_user_model().objects.get(username="staffer")
+ ) # Randomized in post
+ created_date = factory.Faker("date_this_year")
@factory.post_generation
def add_details(self, build, extracted, **kwargs):
@@ -130,7 +136,7 @@ class TaskFactory(factory.django.DjangoModelFactory):
fake = Faker() # Use to create user's names
taskgroup = self.task_list.group
- self.created_by = taskgroup.user_set.all().order_by('?').first()
+ self.created_by = taskgroup.user_set.all().order_by("?").first()
if self.completed:
self.completed_date = fake.date_this_year()
@@ -141,6 +147,6 @@ class TaskFactory(factory.django.DjangoModelFactory):
# 1/3 of generated tasks are assigned to someone in this tasks's group
if random.randint(1, 3) == 1:
- self.assigned_to = taskgroup.user_set.all().order_by('?').first()
+ self.assigned_to = taskgroup.user_set.all().order_by("?").first()
self.save()
diff --git a/todo/management/commands/mail_worker.py b/todo/management/commands/mail_worker.py
index b0750fd..717e7f9 100644
--- a/todo/management/commands/mail_worker.py
+++ b/todo/management/commands/mail_worker.py
@@ -26,10 +26,7 @@ class Command(BaseCommand):
worker_name = options["worker_name"]
tracker = settings.TODO_MAIL_TRACKERS.get(worker_name, None)
if tracker is None:
- logger.error(
- "couldn't find configuration for %r in TODO_MAIL_TRACKERS",
- worker_name
- )
+ logger.error("couldn't find configuration for %r in TODO_MAIL_TRACKERS", worker_name)
sys.exit(1)
# set the default socket timeout (imaplib doesn't enable configuring it)
diff --git a/todo/migrations/0001_initial.py b/todo/migrations/0001_initial.py
index c29c7a6..7b0fff1 100644
--- a/todo/migrations/0001_initial.py
+++ b/todo/migrations/0001_initial.py
@@ -9,70 +9,93 @@ from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
- ('auth', '0001_initial'),
+ ("auth", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
- name='Comment',
+ name="Comment",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('date', models.DateTimeField(default=datetime.datetime.now)),
- ('body', models.TextField(blank=True)),
- ('author', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID", serialize=False, auto_created=True, primary_key=True
+ ),
+ ),
+ ("date", models.DateTimeField(default=datetime.datetime.now)),
+ ("body", models.TextField(blank=True)),
+ (
+ "author",
+ models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
+ ),
],
- options={
- },
+ options={},
bases=(models.Model,),
),
migrations.CreateModel(
- name='Item',
+ name="Item",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('title', models.CharField(max_length=140)),
- ('created_date', models.DateField(auto_now=True, auto_now_add=True)),
- ('due_date', models.DateField(null=True, blank=True)),
- ('completed', models.BooleanField(default=None)),
- ('completed_date', models.DateField(null=True, blank=True)),
- ('note', models.TextField(null=True, blank=True)),
- ('priority', models.PositiveIntegerField(max_length=3)),
- ('assigned_to', models.ForeignKey(related_name='todo_assigned_to', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
- ('created_by', models.ForeignKey(related_name='todo_created_by', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID", serialize=False, auto_created=True, primary_key=True
+ ),
+ ),
+ ("title", models.CharField(max_length=140)),
+ ("created_date", models.DateField(auto_now=True, auto_now_add=True)),
+ ("due_date", models.DateField(null=True, blank=True)),
+ ("completed", models.BooleanField(default=None)),
+ ("completed_date", models.DateField(null=True, blank=True)),
+ ("note", models.TextField(null=True, blank=True)),
+ ("priority", models.PositiveIntegerField(max_length=3)),
+ (
+ "assigned_to",
+ models.ForeignKey(
+ related_name="todo_assigned_to",
+ to=settings.AUTH_USER_MODEL,
+ on_delete=models.CASCADE,
+ ),
+ ),
+ (
+ "created_by",
+ models.ForeignKey(
+ related_name="todo_created_by",
+ to=settings.AUTH_USER_MODEL,
+ on_delete=models.CASCADE,
+ ),
+ ),
],
- options={
- 'ordering': ['priority'],
- },
+ options={"ordering": ["priority"]},
bases=(models.Model,),
),
migrations.CreateModel(
- name='List',
+ name="List",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('name', models.CharField(max_length=60)),
- ('slug', models.SlugField(max_length=60, editable=False)),
- ('group', models.ForeignKey(to='auth.Group', on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID", serialize=False, auto_created=True, primary_key=True
+ ),
+ ),
+ ("name", models.CharField(max_length=60)),
+ ("slug", models.SlugField(max_length=60, editable=False)),
+ ("group", models.ForeignKey(to="auth.Group", on_delete=models.CASCADE)),
],
- options={
- 'ordering': ['name'],
- 'verbose_name_plural': 'Lists',
- },
+ options={"ordering": ["name"], "verbose_name_plural": "Lists"},
bases=(models.Model,),
),
- migrations.AlterUniqueTogether(
- name='list',
- unique_together=set([('group', 'slug')]),
- ),
+ migrations.AlterUniqueTogether(name="list", unique_together=set([("group", "slug")])),
migrations.AddField(
- model_name='item',
- name='list',
- field=models.ForeignKey(to='todo.List', on_delete=models.CASCADE),
+ model_name="item",
+ name="list",
+ field=models.ForeignKey(to="todo.List", on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AddField(
- model_name='comment',
- name='task',
- field=models.ForeignKey(to='todo.Item', on_delete=models.CASCADE),
+ model_name="comment",
+ name="task",
+ field=models.ForeignKey(to="todo.Item", on_delete=models.CASCADE),
preserve_default=True,
),
]
diff --git a/todo/migrations/0002_auto_20150614_2339.py b/todo/migrations/0002_auto_20150614_2339.py
index a346e88..09f2d4a 100644
--- a/todo/migrations/0002_auto_20150614_2339.py
+++ b/todo/migrations/0002_auto_20150614_2339.py
@@ -6,19 +6,13 @@ from django.db import models, migrations
class Migration(migrations.Migration):
- dependencies = [
- ('todo', '0001_initial'),
- ]
+ dependencies = [("todo", "0001_initial")]
operations = [
migrations.AlterField(
- model_name='item',
- name='created_date',
- field=models.DateField(auto_now=True),
+ model_name="item", name="created_date", field=models.DateField(auto_now=True)
),
migrations.AlterField(
- model_name='item',
- name='priority',
- field=models.PositiveIntegerField(),
+ model_name="item", name="priority", field=models.PositiveIntegerField()
),
]
diff --git a/todo/migrations/0003_assignee_optional.py b/todo/migrations/0003_assignee_optional.py
index f5f2625..e370ea0 100644
--- a/todo/migrations/0003_assignee_optional.py
+++ b/todo/migrations/0003_assignee_optional.py
@@ -9,14 +9,18 @@ import django.db.models.deletion
class Migration(migrations.Migration):
- dependencies = [
- ('todo', '0002_auto_20150614_2339'),
- ]
+ dependencies = [("todo", "0002_auto_20150614_2339")]
operations = [
migrations.AlterField(
- model_name='item',
- name='assigned_to',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='todo_assigned_to', to=settings.AUTH_USER_MODEL),
- ),
+ model_name="item",
+ name="assigned_to",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="todo_assigned_to",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ )
]
diff --git a/todo/migrations/0004_rename_list_tasklist.py b/todo/migrations/0004_rename_list_tasklist.py
index 65e9b04..41f5fee 100644
--- a/todo/migrations/0004_rename_list_tasklist.py
+++ b/todo/migrations/0004_rename_list_tasklist.py
@@ -7,46 +7,39 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
- ('auth', '0009_alter_user_last_name_max_length'),
- ('todo', '0003_assignee_optional'),
+ ("auth", "0009_alter_user_last_name_max_length"),
+ ("todo", "0003_assignee_optional"),
]
operations = [
migrations.CreateModel(
- name='TaskList',
+ name="TaskList",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(max_length=60)),
- ('slug', models.SlugField(default='')),
- ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
+ ),
+ ),
+ ("name", models.CharField(max_length=60)),
+ ("slug", models.SlugField(default="")),
+ (
+ "group",
+ models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="auth.Group"),
+ ),
],
- options={
- 'verbose_name_plural': 'Lists',
- 'ordering': ['name'],
- },
- ),
- migrations.AlterUniqueTogether(
- name='list',
- unique_together=set(),
- ),
- migrations.RemoveField(
- model_name='list',
- name='group',
- ),
- migrations.RemoveField(
- model_name='item',
- name='list',
- ),
- migrations.DeleteModel(
- name='List',
+ options={"verbose_name_plural": "Lists", "ordering": ["name"]},
),
+ migrations.AlterUniqueTogether(name="list", unique_together=set()),
+ migrations.RemoveField(model_name="list", name="group"),
+ migrations.RemoveField(model_name="item", name="list"),
+ migrations.DeleteModel(name="List"),
migrations.AddField(
- model_name='item',
- name='task_list',
- field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='todo.TaskList'),
- ),
- migrations.AlterUniqueTogether(
- name='tasklist',
- unique_together={('group', 'slug')},
+ model_name="item",
+ name="task_list",
+ field=models.ForeignKey(
+ null=True, on_delete=django.db.models.deletion.CASCADE, to="todo.TaskList"
+ ),
),
+ migrations.AlterUniqueTogether(name="tasklist", unique_together={("group", "slug")}),
]
diff --git a/todo/migrations/0005_auto_20180212_2325.py b/todo/migrations/0005_auto_20180212_2325.py
index 5a8c466..94a2c9c 100644
--- a/todo/migrations/0005_auto_20180212_2325.py
+++ b/todo/migrations/0005_auto_20180212_2325.py
@@ -5,18 +5,13 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('todo', '0004_rename_list_tasklist'),
- ]
+ dependencies = [("todo", "0004_rename_list_tasklist")]
operations = [
migrations.AlterModelOptions(
- name='tasklist',
- options={'ordering': ['name'], 'verbose_name_plural': 'Task Lists'},
+ name="tasklist", options={"ordering": ["name"], "verbose_name_plural": "Task Lists"}
),
migrations.AlterField(
- model_name='item',
- name='completed',
- field=models.BooleanField(default=False),
+ model_name="item", name="completed", field=models.BooleanField(default=False)
),
]
diff --git a/todo/migrations/0006_rename_item_model.py b/todo/migrations/0006_rename_item_model.py
index cd9830d..42f5c51 100644
--- a/todo/migrations/0006_rename_item_model.py
+++ b/todo/migrations/0006_rename_item_model.py
@@ -8,12 +8,7 @@ class Migration(migrations.Migration):
atomic = False
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('todo', '0005_auto_20180212_2325'),
+ ("todo", "0005_auto_20180212_2325"),
]
- operations = [
- migrations.RenameModel(
- old_name='Item',
- new_name='Task',
- ),
- ]
+ operations = [migrations.RenameModel(old_name="Item", new_name="Task")]
diff --git a/todo/migrations/0007_auto_update_created_date.py b/todo/migrations/0007_auto_update_created_date.py
index dfee145..b98eb94 100644
--- a/todo/migrations/0007_auto_update_created_date.py
+++ b/todo/migrations/0007_auto_update_created_date.py
@@ -6,14 +6,12 @@ import django.utils.timezone
class Migration(migrations.Migration):
- dependencies = [
- ('todo', '0006_rename_item_model'),
- ]
+ dependencies = [("todo", "0006_rename_item_model")]
operations = [
migrations.AlterField(
- model_name='task',
- name='created_date',
+ model_name="task",
+ name="created_date",
field=models.DateField(blank=True, default=django.utils.timezone.now, null=True),
- ),
+ )
]
diff --git a/todo/migrations/0009_priority_optional.py b/todo/migrations/0009_priority_optional.py
index 108ec30..1dd6305 100644
--- a/todo/migrations/0009_priority_optional.py
+++ b/todo/migrations/0009_priority_optional.py
@@ -5,18 +5,15 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('todo', '0008_mail_tracker'),
- ]
+ dependencies = [("todo", "0008_mail_tracker")]
operations = [
migrations.AlterModelOptions(
- name='task',
- options={'ordering': ['priority', 'created_date']},
+ name="task", options={"ordering": ["priority", "created_date"]}
),
migrations.AlterField(
- model_name='task',
- name='priority',
+ model_name="task",
+ name="priority",
field=models.PositiveIntegerField(blank=True, null=True),
),
]
diff --git a/todo/migrations/0010_attachment.py b/todo/migrations/0010_attachment.py
index 885411a..2f62eff 100644
--- a/todo/migrations/0010_attachment.py
+++ b/todo/migrations/0010_attachment.py
@@ -11,18 +11,36 @@ class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('todo', '0009_priority_optional'),
+ ("todo", "0009_priority_optional"),
]
operations = [
migrations.CreateModel(
- name='Attachment',
+ name="Attachment",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('timestamp', models.DateTimeField(default=datetime.datetime.now)),
- ('file', models.FileField(max_length=255, upload_to=todo.models.get_attachment_upload_dir)),
- ('added_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
- ('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='todo.Task')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
+ ),
+ ),
+ ("timestamp", models.DateTimeField(default=datetime.datetime.now)),
+ (
+ "file",
+ models.FileField(
+ max_length=255, upload_to=todo.models.get_attachment_upload_dir
+ ),
+ ),
+ (
+ "added_by",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
+ ),
+ ),
+ (
+ "task",
+ models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="todo.Task"),
+ ),
],
- ),
+ )
]
diff --git a/todo/models.py b/todo/models.py
index a9582dc..60ab220 100644
--- a/todo/models.py
+++ b/todo/models.py
@@ -45,9 +45,7 @@ class LockedAtomicTransaction(Atomic):
cursor = get_connection(self.using).cursor()
for model in self.models:
cursor.execute(
- "LOCK TABLE {table_name}".format(
- table_name=model._meta.db_table
- )
+ "LOCK TABLE {table_name}".format(table_name=model._meta.db_table)
)
finally:
if cursor and not cursor.closed:
@@ -159,9 +157,7 @@ class Comment(models.Model):
def snippet(self):
body_snippet = textwrap.shorten(self.body, width=35, placeholder="...")
# Define here rather than in __str__ so we can use it in the admin list_display
- return "{author} - {snippet}...".format(
- author=self.author_text, snippet=body_snippet
- )
+ return "{author} - {snippet}...".format(author=self.author_text, snippet=body_snippet)
def __str__(self):
return self.snippet
@@ -173,9 +169,7 @@ class Attachment(models.Model):
"""
task = models.ForeignKey(Task, on_delete=models.CASCADE)
- added_by = models.ForeignKey(
- settings.AUTH_USER_MODEL, on_delete=models.CASCADE
- )
+ added_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
timestamp = models.DateTimeField(default=datetime.datetime.now)
file = models.FileField(upload_to=get_attachment_upload_dir, max_length=255)
diff --git a/todo/operations/csv_importer.py b/todo/operations/csv_importer.py
index 7b847fa..6313786 100644
--- a/todo/operations/csv_importer.py
+++ b/todo/operations/csv_importer.py
@@ -67,7 +67,11 @@ class CSVImporter:
# newrow at this point is fully validated, and all FK relations exist,
# e.g. `newrow.get("Assigned To")`, is a Django User instance.
assignee = newrow.get("Assigned To") if newrow.get("Assigned To") else None
- created_date = newrow.get("Created Date") if newrow.get("Created Date") else datetime.datetime.today()
+ created_date = (
+ newrow.get("Created Date")
+ if newrow.get("Created Date")
+ else datetime.datetime.today()
+ )
due_date = newrow.get("Due Date") if newrow.get("Due Date") else None
priority = newrow.get("Priority") if newrow.get("Priority") else None
@@ -178,7 +182,7 @@ class CSVImporter:
row["Assigned To"] = assignee
# Set Completed
- row["Completed"] = (row["Completed"] == "Yes")
+ row["Completed"] = row["Completed"] == "Yes"
# #######################
if row_errors:
diff --git a/todo/tests/test_tracker.py b/todo/tests/test_tracker.py
index 3387d75..5ea5ad0 100644
--- a/todo/tests/test_tracker.py
+++ b/todo/tests/test_tracker.py
@@ -9,24 +9,21 @@ from email.message import EmailMessage
def consumer(*args, title_format="[TEST] {subject}", **kwargs):
return tracker_consumer(
- group="Workgroup One",
- task_list_slug="zip",
- priority=1,
- task_title_format=title_format,
+ group="Workgroup One", task_list_slug="zip", priority=1, task_title_format=title_format
)(*args, **kwargs)
def make_message(subject, content):
msg = EmailMessage()
msg.set_content(content)
- msg['Subject'] = subject
+ msg["Subject"] = subject
return msg
def test_tracker_task_creation(todo_setup, django_user_model):
msg = make_message("test1 subject", "test1 content")
- msg['From'] = 'test1@example.com'
- msg['Message-ID'] = ''
+ msg["From"] = "test1@example.com"
+ msg["Message-ID"] = ""
# test task creation
task_count = Task.objects.count()
@@ -38,30 +35,26 @@ def test_tracker_task_creation(todo_setup, django_user_model):
# test thread answers
msg = make_message("test2 subject", "test2 content")
- msg['From'] = 'test1@example.com'
- msg['Message-ID'] = ''
- msg['References'] = ' '
+ msg["From"] = "test1@example.com"
+ msg["Message-ID"] = ""
+ msg["References"] = " "
task_count = Task.objects.count()
consumer([msg])
assert task_count == Task.objects.count(), "comment created another task"
Comment.objects.get(
- task=task,
- body__contains="test2 content",
- email_message_id=''
+ task=task, body__contains="test2 content", email_message_id=""
)
# test notification answer
msg = make_message("test3 subject", "test3 content")
- msg['From'] = 'test1@example.com'
- msg['Message-ID'] = ''
- msg['References'] = ' '.format(task.pk)
+ msg["From"] = "test1@example.com"
+ msg["Message-ID"] = ""
+ msg["References"] = " ".format(task.pk)
task_count = Task.objects.count()
consumer([msg])
assert task_count == Task.objects.count(), "comment created another task"
Comment.objects.get(
- task=task,
- body__contains="test3 content",
- email_message_id=''
+ task=task, body__contains="test3 content", email_message_id=""
)
diff --git a/todo/tests/test_utils.py b/todo/tests/test_utils.py
index 48f3149..cf26a38 100644
--- a/todo/tests/test_utils.py
+++ b/todo/tests/test_utils.py
@@ -55,5 +55,6 @@ def test_send_email_to_thread_participants(todo_setup, django_user_model, email_
assert "u3@example.com" in mail.outbox[0].recipients()
assert "u4@example.com" in mail.outbox[0].recipients()
+
# FIXME: Add tests for:
-# Attachments: Test whether allowed, test multiple, test extensions
\ No newline at end of file
+# Attachments: Test whether allowed, test multiple, test extensions
diff --git a/todo/tests/test_views.py b/todo/tests/test_views.py
index c15d9df..9ad05d6 100644
--- a/todo/tests/test_views.py
+++ b/todo/tests/test_views.py
@@ -166,6 +166,7 @@ def test_no_javascript_in_comments(todo_setup, client):
# ### PERMISSIONS ###
+
def test_view_add_list_nonadmin(todo_setup, client):
url = reverse("todo:add_list")
client.login(username="you", password="password")
diff --git a/todo/urls.py b/todo/urls.py
index a539616..9b68ca2 100644
--- a/todo/urls.py
+++ b/todo/urls.py
@@ -4,93 +4,46 @@ from django.urls import path
from todo import views
from todo.features import HAS_TASK_MERGE
-app_name = 'todo'
+app_name = "todo"
urlpatterns = [
- path(
- '',
- views.list_lists,
- name="lists"),
-
+ path("", views.list_lists, name="lists"),
# View reorder_tasks is only called by JQuery for drag/drop task ordering.
- path(
- 'reorder_tasks/',
- views.reorder_tasks,
- name="reorder_tasks"),
-
+ path("reorder_tasks/", views.reorder_tasks, name="reorder_tasks"),
# Allow users to post tasks from outside django-todo (e.g. for filing tickets - see docs)
- path(
- 'ticket/add/',
- views.external_add,
- name="external_add"),
-
+ path("ticket/add/", views.external_add, name="external_add"),
# Three paths into `list_detail` view
+ path("mine/", views.list_detail, {"list_slug": "mine"}, name="mine"),
path(
- 'mine/',
+ "//completed/",
views.list_detail,
- {'list_slug': 'mine'},
- name="mine"),
-
+ {"view_completed": True},
+ name="list_detail_completed",
+ ),
+ path("//", views.list_detail, name="list_detail"),
+ path("//delete/", views.del_list, name="del_list"),
+ path("add_list/", views.add_list, name="add_list"),
+ path("task//", views.task_detail, name="task_detail"),
path(
- '//completed/',
- views.list_detail,
- {'view_completed': True},
- name='list_detail_completed'),
-
- path(
- '//',
- views.list_detail,
- name='list_detail'),
-
- path(
- '//delete/',
- views.del_list,
- name="del_list"),
-
- path(
- 'add_list/',
- views.add_list,
- name="add_list"),
-
- path(
- 'task//',
- views.task_detail,
- name='task_detail'),
-
- path(
- 'attachment/remove//',
- views.remove_attachment,
- name='remove_attachment'),
+ "attachment/remove//", views.remove_attachment, name="remove_attachment"
+ ),
]
if HAS_TASK_MERGE:
# ensure mail tracker autocomplete is optional
from todo.views.task_autocomplete import TaskAutocomplete
+
urlpatterns.append(
path(
- 'task//autocomplete/',
- TaskAutocomplete.as_view(),
- name='task_autocomplete')
+ "task//autocomplete/", TaskAutocomplete.as_view(), name="task_autocomplete"
+ )
)
-urlpatterns.extend([
- path(
- 'toggle_done//',
- views.toggle_done,
- name='task_toggle_done'),
-
- path(
- 'delete//',
- views.delete_task,
- name='delete_task'),
-
- path(
- 'search/',
- views.search,
- name="search"),
-
- path(
- 'import_csv/',
- views.import_csv,
- name="import_csv"),
-])
+urlpatterns.extend(
+ [
+ path("toggle_done//", views.toggle_done, name="task_toggle_done"),
+ path("delete//", views.delete_task, name="delete_task"),
+ path("search/", views.search, name="search"),
+ path("import_csv/", views.import_csv, name="import_csv"),
+ ]
+)
diff --git a/todo/utils.py b/todo/utils.py
index f63df38..a2b6fa8 100644
--- a/todo/utils.py
+++ b/todo/utils.py
@@ -20,7 +20,7 @@ def staff_check(user):
https://github.com/shacker/django-todo/issues/50
"""
- if defaults('TODO_STAFF_ONLY'):
+ if defaults("TODO_STAFF_ONLY"):
return user.is_staff
else:
# If unset or False, allow all logged in users
diff --git a/todo/views/external_add.py b/todo/views/external_add.py
index f5f7950..077b527 100644
--- a/todo/views/external_add.py
+++ b/todo/views/external_add.py
@@ -43,7 +43,7 @@ def external_add(request) -> HttpResponse:
task = form.save(commit=False)
task.task_list = TaskList.objects.get(slug=settings.TODO_DEFAULT_LIST_SLUG)
task.created_by = request.user
- if defaults('TODO_DEFAULT_ASSIGNEE'):
+ if defaults("TODO_DEFAULT_ASSIGNEE"):
task.assigned_to = User.objects.get(username=settings.TODO_DEFAULT_ASSIGNEE)
task.save()
diff --git a/todo/views/remove_attachment.py b/todo/views/remove_attachment.py
index 75b235f..588e31e 100644
--- a/todo/views/remove_attachment.py
+++ b/todo/views/remove_attachment.py
@@ -18,10 +18,7 @@ def remove_attachment(request, attachment_id: int) -> HttpResponse:
if request.method == "POST":
attachment = get_object_or_404(Attachment, pk=attachment_id)
- redir_url = reverse(
- "todo:task_detail",
- kwargs={"task_id": attachment.task.id},
- )
+ redir_url = reverse("todo:task_detail", kwargs={"task_id": attachment.task.id})
# Permissions
if not (
@@ -33,7 +30,9 @@ def remove_attachment(request, attachment_id: int) -> HttpResponse:
if remove_attachment_file(attachment.id):
messages.success(request, f"Attachment {attachment.id} removed.")
else:
- messages.error(request, f"Sorry, there was a problem deleting attachment {attachment.id}.")
+ messages.error(
+ request, f"Sorry, there was a problem deleting attachment {attachment.id}."
+ )
return redirect(redir_url)
diff --git a/todo/views/task_detail.py b/todo/views/task_detail.py
index fa0f4f3..bf558d4 100644
--- a/todo/views/task_detail.py
+++ b/todo/views/task_detail.py
@@ -121,13 +121,13 @@ def task_detail(request, task_id: int) -> HttpResponse:
if request.FILES.get("attachment_file_input"):
file = request.FILES.get("attachment_file_input")
- if file.size > defaults('TODO_MAXIMUM_ATTACHMENT_SIZE'):
+ if file.size > defaults("TODO_MAXIMUM_ATTACHMENT_SIZE"):
messages.error(request, f"File exceeds maximum attachment size.")
return redirect("todo:task_detail", task_id=task.id)
name, extension = os.path.splitext(file.name)
- if extension not in defaults('TODO_LIMIT_FILE_ATTACHMENTS'):
+ if extension not in defaults("TODO_LIMIT_FILE_ATTACHMENTS"):
messages.error(request, f"This site does not allow upload of {extension} files.")
return redirect("todo:task_detail", task_id=task.id)
@@ -144,7 +144,7 @@ def task_detail(request, task_id: int) -> HttpResponse:
"merge_form": merge_form,
"thedate": thedate,
"comment_classes": defaults("TODO_COMMENT_CLASSES"),
- "attachments_enabled": defaults('TODO_ALLOW_FILE_ATTACHMENTS'),
+ "attachments_enabled": defaults("TODO_ALLOW_FILE_ATTACHMENTS"),
}
return render(request, "todo/task_detail.html", context)