Skip to content

Commit

Permalink
Merge pull request #119 from matorral-project/more-fixes-towards-mvp-2
Browse files Browse the repository at this point in the history
More fixes towards mvp 2
  • Loading branch information
matagus authored Mar 3, 2024
2 parents 719095d + 3701e54 commit be446bf
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 15 deletions.
27 changes: 23 additions & 4 deletions matorral/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.apps import apps
from django.db import models
from django.utils import timezone


class BaseModel(models.Model):
Expand All @@ -16,6 +17,17 @@ class Meta:
def __str__(self):
return self.title

def is_done(self):
return self.state.stype == self.state.STATE_DONE

def save(self, *args, **kwargs):
if self.is_done():
self.completed_at = timezone.now()
else:
self.completed_at = None

super().save(*args, **kwargs)


class ModelWithProgress(models.Model):
class Meta:
Expand All @@ -42,20 +54,27 @@ def update_points_and_progress(self, save=True):

parent_dict = {self._meta.model_name: self.id}

# calculate total points
total_points = Story.objects.filter(**parent_dict).aggregate(models.Sum("points"))["points__sum"] or 0

if total_points == 0:
# if no story has points, then count the stories
total_points = Story.objects.filter(**parent_dict).count()

# calculate points done
params = parent_dict.copy()
params["state__stype"] = StoryState.STATE_DONE
points_done = Story.objects.filter(**params).aggregate(models.Sum("points"))["points__sum"] or 0

if points_done == 0:
# if no story has points, then count the stories
points_done = Story.objects.filter(**params).count()

self.total_points = total_points
self.points_done = points_done
self.story_count = Story.objects.filter(**parent_dict).count()

if total_points > 0:
self.progress = int(float(points_done) / total_points * 100)
else:
self.progress = 0
self.progress = int(float(points_done) / (total_points or 1) * 100)

if save:
self.save()
22 changes: 22 additions & 0 deletions matorral/sprints/migrations/0009_alter_sprint_options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 4.2.10 on 2024-03-02 00:27

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("sprints", "0008_alter_historicalsprint_options_and_more"),
]

operations = [
migrations.AlterModelOptions(
name="sprint",
options={
"get_latest_by": "created_at",
"ordering": ["starts_at", "-updated_at"],
"verbose_name": "sprint",
"verbose_name_plural": "sprints",
},
),
]
3 changes: 3 additions & 0 deletions matorral/sprints/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ def reset_sprint(story_ids):
for sprint in Sprint.objects.filter(id__in=sprint_ids):
sprint.update_points_and_progress()

update_state.delay()


@app.task(ignore_result=True)
def handle_sprint_change(epic_id):
Expand All @@ -51,3 +53,4 @@ def handle_sprint_change(epic_id):
return

sprint.update_points_and_progress()
update_state.delay()
8 changes: 2 additions & 6 deletions matorral/stories/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,7 @@ class Meta:

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["requester"].queryset = User.objects.filter(is_active=True, workspace=self.workspace).order_by(
"username"
)
self.fields["assignee"].queryset = User.objects.filter(is_active=True, workspace=self.workspace).order_by(
"username"
)
self.fields["requester"].queryset = self.workspace.members.filter(is_active=True).order_by("username")
self.fields["assignee"].queryset = self.workspace.members.filter(is_active=True).order_by("username")
self.fields["epic"].queryset = Epic.objects.filter(workspace=self.workspace).order_by("title")
self.fields["sprint"].queryset = Sprint.objects.filter(workspace=self.workspace).order_by("ends_at")
13 changes: 12 additions & 1 deletion matorral/stories/tasks.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from matorral.taskapp.celery import app

from .models import Epic, EpicState, Story, StoryState
from matorral.sprints.tasks import update_state as update_sprint_state


@app.task(ignore_result=True)
Expand All @@ -27,6 +28,8 @@ def remove_stories(story_ids):
for sprint in Sprint.objects.filter(story__id__in=story_ids).distinct():
sprint.update_points_and_progress()

update_sprint_state.delay()


@app.task(ignore_result=True)
def story_set_assignee(story_ids, user_id):
Expand All @@ -40,7 +43,12 @@ def story_set_state(story_ids, state_slug):
except StoryState.DoesNotExist:
return

Story.objects.filter(id__in=story_ids).update(state=state)
# update stories one by one to trigger signals and tasks that update the progress and points, etc
for story in Story.objects.filter(id__in=story_ids):
story.state = state
story.save()

update_sprint_state.delay()


@app.task(ignore_result=True)
Expand Down Expand Up @@ -109,6 +117,7 @@ def handle_story_change(story_id):

if story.sprint is not None:
story.sprint.update_points_and_progress()
update_sprint_state.delay()


@app.task(ignore_result=True)
Expand Down Expand Up @@ -145,3 +154,5 @@ def story_set_sprint(story_ids, sprint_id):
for story in Story.objects.filter(id__in=story_ids):
story.sprint = sprint
story.save()

update_sprint_state.delay()
2 changes: 1 addition & 1 deletion matorral/stories/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def get_children(self):
except KeyError:
return [(None, queryset)]
else:
queryset = queryset.order_by(F(order_by).asc(nulls_last=True))
queryset = queryset.order_by(F(order_by).asc(nulls_last=True), "priority")
foo = [(t[0], list(t[1])) for t in groupby(queryset, key=fx)]
return foo

Expand Down
49 changes: 49 additions & 0 deletions matorral/workspaces/migrations/0005_auto_20240302_1301.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Generated by Django 4.2.10 on 2024-03-02 13:01

from django.db import migrations


def create_default_workspace(apps, schema_editor):
"""
Creates the default workspace and add all the users to it
"""

User = apps.get_model("users", "User")

if User.objects.count() == 0:
# No users, nothing to do: the workspace will be created when the first user is created
return

# Get the first superuser or admin user
admin_user = User.objects.filter(is_superuser=True).first()

if admin_user is None:
admin_user = User.objects.filter(is_staff=True).first()

if admin_user is None:
admin_user = User.objects.first()

Workspace = apps.get_model("workspaces", "Workspace")
default_workspace = Workspace.objects.create(
name="Default Workspace", slug="default-workspace", owner=admin_user
)

# Now add all the users to the default workspace
for user in User.objects.all():
default_workspace.members.add(user)


def delete_default_workspace(apps, schema_editor):
Workspace = apps.get_model("workspaces", "Workspace")
Workspace.objects.filter(slug="default-workspace").delete()


class Migration(migrations.Migration):

dependencies = [
("workspaces", "0004_auto_20200815_1608"),
]

operations = [
migrations.RunPython(create_default_workspace, reverse_code=delete_default_workspace),
]
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ extra-dependencies = [
]

[tool.hatch.envs.local.scripts]
server = "python manage.py runserver_plus --settings=config.settings.local"
shell = "python manage.py shell_plus --settings=config.settings.local"
migrate = "python manage.py migrate --settings=config.settings.local"
server = "python manage.py runserver_plus --settings=config.settings.local {args}"
shell = "python manage.py shell_plus --settings=config.settings.local {args}"
migrate = "python manage.py migrate --settings=config.settings.local {args}"
makemigrations = "python manage.py makemigrations --settings=config.settings.local {args}"

# Production environment
Expand Down

0 comments on commit be446bf

Please sign in to comment.