diff --git a/osinaweb/db.sqlite3 b/osinaweb/db.sqlite3 index 37ca83ac..9e91a117 100644 Binary files a/osinaweb/db.sqlite3 and b/osinaweb/db.sqlite3 differ diff --git a/osinaweb/osinacore/__pycache__/admin.cpython-310.pyc b/osinaweb/osinacore/__pycache__/admin.cpython-310.pyc index 91305e5c..4843b162 100644 Binary files a/osinaweb/osinacore/__pycache__/admin.cpython-310.pyc and b/osinaweb/osinacore/__pycache__/admin.cpython-310.pyc differ diff --git a/osinaweb/osinacore/__pycache__/models.cpython-310.pyc b/osinaweb/osinacore/__pycache__/models.cpython-310.pyc index e10f04a4..bd2736db 100644 Binary files a/osinaweb/osinacore/__pycache__/models.cpython-310.pyc and b/osinaweb/osinacore/__pycache__/models.cpython-310.pyc differ diff --git a/osinaweb/osinacore/__pycache__/views.cpython-310.pyc b/osinaweb/osinacore/__pycache__/views.cpython-310.pyc index 2accf427..bf802236 100644 Binary files a/osinaweb/osinacore/__pycache__/views.cpython-310.pyc and b/osinaweb/osinacore/__pycache__/views.cpython-310.pyc differ diff --git a/osinaweb/osinacore/admin.py b/osinaweb/osinacore/admin.py index 948d21ae..86697b32 100644 --- a/osinaweb/osinacore/admin.py +++ b/osinaweb/osinacore/admin.py @@ -37,6 +37,7 @@ admin.site.register(StaffProfile) admin.site.register(ProjectType) admin.site.register(Project, ProjectAdmin) admin.site.register(ProjectStatus) +admin.site.register(PinnedProject) admin.site.register(Epic) admin.site.register(Note) admin.site.register(Task) diff --git a/osinaweb/osinacore/edit/__pycache__/urls.cpython-310.pyc b/osinaweb/osinacore/edit/__pycache__/urls.cpython-310.pyc index 70b09fcc..cb26155a 100644 Binary files a/osinaweb/osinacore/edit/__pycache__/urls.cpython-310.pyc and b/osinaweb/osinacore/edit/__pycache__/urls.cpython-310.pyc differ diff --git a/osinaweb/osinacore/edit/__pycache__/views.cpython-310.pyc b/osinaweb/osinacore/edit/__pycache__/views.cpython-310.pyc index 63154f64..87487f1b 100644 Binary files a/osinaweb/osinacore/edit/__pycache__/views.cpython-310.pyc and b/osinaweb/osinacore/edit/__pycache__/views.cpython-310.pyc differ diff --git a/osinaweb/osinacore/edit/urls.py b/osinaweb/osinacore/edit/urls.py index aa4de05a..a622f9cf 100644 --- a/osinaweb/osinacore/edit/urls.py +++ b/osinaweb/osinacore/edit/urls.py @@ -9,6 +9,7 @@ urlpatterns = [ path('business//', views.edit_business, name='editbusiness'), path('staff//', views.edit_staff, name='editstaff'), path('project//', views.edit_project, name='editproject'), + path('project//toggle_pin/', views.toggle_pin_project, name='toggle_pin_project'), path('projectstatus//', views.edit_project_status_modal, name='editprojectstatusmodal'), path('task//', views.edit_task, name='edittask'), path('task-status//', views.edit_task_status_modal, name='edittaskstatusmodal'), diff --git a/osinaweb/osinacore/edit/views.py b/osinaweb/osinacore/edit/views.py index b36b7c4d..47fee5f8 100644 --- a/osinaweb/osinacore/edit/views.py +++ b/osinaweb/osinacore/edit/views.py @@ -232,6 +232,20 @@ def edit_project_status_modal(request, project_id): +@staff_login_required +def toggle_pin_project(request, project_id): + project = get_object_or_404(Project, id=project_id) + if PinnedProject.objects.filter(user=request.user, project=project): + PinnedProject.objects.filter(user=request.user, project=project).delete() + else: + PinnedProject.objects.create(user=request.user, project=project) + + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + + + + + @staff_login_required def edit_task(request, task_id): task = get_object_or_404(Task, task_id=task_id) diff --git a/osinaweb/osinacore/migrations/0082_pinnedproject.py b/osinaweb/osinacore/migrations/0082_pinnedproject.py new file mode 100644 index 00000000..4a51c897 --- /dev/null +++ b/osinaweb/osinacore/migrations/0082_pinnedproject.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.5 on 2024-05-29 06:37 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('osinacore', '0081_status_task'), + ] + + operations = [ + migrations.CreateModel( + name='PinnedProject', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osinacore.project')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/osinaweb/osinacore/migrations/__pycache__/0082_pinnedproject.cpython-310.pyc b/osinaweb/osinacore/migrations/__pycache__/0082_pinnedproject.cpython-310.pyc new file mode 100644 index 00000000..66b640a1 Binary files /dev/null and b/osinaweb/osinacore/migrations/__pycache__/0082_pinnedproject.cpython-310.pyc differ diff --git a/osinaweb/osinacore/models.py b/osinaweb/osinacore/models.py index 571b2c94..76e3d041 100644 --- a/osinaweb/osinacore/models.py +++ b/osinaweb/osinacore/models.py @@ -160,6 +160,31 @@ class Project(models.Model): new_id = str(int(max_id[-4:]) + 1).zfill(4) if max_id else '0001' # If no existing records, start with '0001' self.project_id = 'P' + current_year + new_id # Add 'p' prefix super(Project, self).save(*args, **kwargs) + def is_pinned(self, user): + return PinnedProject.objects.filter(user=user, project=self).exists() + def total_time_worked(self, user): + total_time_seconds = 0 + tasks = self.task_set.all() if user.is_superuser else self.task_set.filter(assigned_to=user.staffprofile) + + for task in tasks: + total_time_hours, total_time_minutes, total_time_seconds_task = task.total_task_time() + total_time_seconds += (total_time_hours * 3600) + (total_time_minutes * 60) + total_time_seconds_task + + total_time_hours = total_time_seconds // 3600 + total_time_minutes = (total_time_seconds % 3600) // 60 + total_time_seconds = total_time_seconds % 60 + + return { + 'hours': total_time_hours, + 'minutes': total_time_minutes, + 'seconds': total_time_seconds + } + def open_tasks_count(self, user): + if user.is_superuser: + return Task.objects.filter(project=self).exclude(status='Closed').count() + else: + return Task.objects.filter(project=self, assigned_to=user.staffprofile).exclude(status='Closed').count() + class ProjectStatus(models.Model): @@ -175,6 +200,12 @@ class ProjectStatus(models.Model): +class PinnedProject(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + project = models.ForeignKey(Project, on_delete=models.CASCADE) + + + class Milestone(models.Model): title = models.CharField(max_length=150) description = models.TextField() diff --git a/osinaweb/osinacore/templates/details_templates/project-details.html b/osinaweb/osinacore/templates/details_templates/project-details.html index d7b3a3d1..a6a28636 100644 --- a/osinaweb/osinacore/templates/details_templates/project-details.html +++ b/osinaweb/osinacore/templates/details_templates/project-details.html @@ -21,32 +21,36 @@ {% endfor %} -
- - - - -
- - + + {% if not is_pinned %} +
+ + + + +
+ {% else %} +
+ + + + + + +
+ {% endif %} +
diff --git a/osinaweb/osinacore/templates/index.html b/osinaweb/osinacore/templates/index.html index 67ee885e..ff26f97f 100644 --- a/osinaweb/osinacore/templates/index.html +++ b/osinaweb/osinacore/templates/index.html @@ -5,191 +5,107 @@
-
-
-
-
-

hallo

- -
-

20-2-24

-

20-2-24

-
+ {% if pinned_projects_with_time %} +
-
- - - - - - -
-
+ {% for pinned in pinned_projects_with_time %} + +
+
+
+

{{pinned.project.name}}

+ +
+

{{ pinned.project.start_date|date:'d-m-Y' }}

+

{{ pinned.project.end_date|date:'d-m-Y' }}

+
- -
-
-
-
+
+ + + + + + +
-
-
+ {% endif %} diff --git a/osinaweb/osinacore/templates/listing_pages/projects.html b/osinaweb/osinacore/templates/listing_pages/projects.html index 4fd4aba5..a0039e76 100644 --- a/osinaweb/osinacore/templates/listing_pages/projects.html +++ b/osinaweb/osinacore/templates/listing_pages/projects.html @@ -153,7 +153,7 @@

{{project.open_user_tasks_count}} Open {% if project.open_user_tasks_count == 1 %} Ticket {% else %} Tickets {% endif %}

+ class="font-poppinsBold">{{project.ticket_set.all.count}} Open {% if project.ticket_set.all.count == 1 %} Ticket {% else %} Tickets {% endif %}

diff --git a/osinaweb/osinacore/views.py b/osinaweb/osinacore/views.py index 6e7d5c66..a5ccbdfe 100644 --- a/osinaweb/osinacore/views.py +++ b/osinaweb/osinacore/views.py @@ -181,10 +181,21 @@ def home(request, *args, **kwargs): else: # Non-superadmin user can only see their assigned tasks tasks = Task.objects.filter(Q(assigned_to=request.user.staffprofile) & (Q(status='Open') | Q(status='Working On'))).order_by('-status_date', '-id') + + + pinned_projects = PinnedProject.objects.filter(user=request.user).order_by('-id')[:3] + pinned_projects_with_time = [] + for pinned_project in pinned_projects: + project = pinned_project.project + total_time_worked = project.total_time_worked(request.user) + open_tasks = project.open_tasks_count(request.user) + pinned_projects_with_time.append({'project': project, 'total_time_worked': total_time_worked, 'open_tasks': open_tasks}) + context = { 'notes': notes, 'recent_note': recent_note, 'tasks': tasks, + 'pinned_projects_with_time': pinned_projects_with_time, } return render(request, 'index.html', context) @@ -648,6 +659,7 @@ def timeline_modal(request, task_id): @staff_login_required def projectdetails(request, project_id): project = get_object_or_404(Project, project_id=project_id) + is_pinned = project.is_pinned(request.user) epics = Epic.objects.filter(project=project).order_by('-id') project_notes = Note.objects.filter(project=project).order_by('-id') @@ -687,6 +699,7 @@ def projectdetails(request, project_id): 'members': members, 'statuses' : statuses, 'all_tickets_ordered': all_tickets_ordered, + 'is_pinned': is_pinned, } return render(request, 'details_templates/project-details.html', context)