Skip to content
This repository has been archived by the owner on Jul 25, 2024. It is now read-only.

Commit

Permalink
core/models,frontend/user_settings: Add user preference for failures …
Browse files Browse the repository at this point in the history
…only

Add support for a user preference for the "failures only" field in the
build results screen.
When the user is logged in, they can set a user preference in their
profile for this "failures only" field. The default for this field is
for the "failures only" tickbox to be checked.

Signed-off-by: Katie Worton <[email protected]>
  • Loading branch information
katieworton committed Nov 22, 2023
1 parent 59d0963 commit b5bbdc9
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 5 deletions.
38 changes: 38 additions & 0 deletions squad/core/migrations/0169_userpreferences.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 4.2.4 on 2023-11-21 17:54

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),
("core", "0168_add_group_settings"),
]

operations = [
migrations.CreateModel(
name="UserPreferences",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("display_failures_only", models.BooleanField(default=True)),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
5 changes: 5 additions & 0 deletions squad/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ class Meta:
proxy = True


class UserPreferences(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
display_failures_only = models.BooleanField(default=True)


class ProjectManager(models.Manager):

def accessible_to(self, user):
Expand Down
1 change: 1 addition & 0 deletions squad/frontend/templates/squad/user_settings/base.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<li class="list-group-item {{active("settings-projects")}}"><a href="{{url('settings-projects')}}">{{ _('Personal projects') }}</a></li>
<li class="list-group-item {{active("settings-api-token")}}"><a href="{{url('settings-api-token')}}">{{ _('API token') }}</a></li>
<li class="list-group-item {{active("settings-subscriptions")}}"><a href="{{url('settings-subscriptions')}}">{{ _('Subscriptions') }}</a></li>
<li class="list-group-item {{active("settings-user-preferences")}}"><a href="{{url('settings-user-preferences')}}">{{ _('User Preferences') }}</a></li>
</ul>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends "squad/user_settings/base.jinja2" %}
{% block settings %}
<h1>{{ _('User Preferences') }}</h1>

<form method="POST">
{{ csrf_input }}
{{crispy(form)}}
<input class='btn btn-primary' type="submit" value="{{ _('Save') }}" />
</form>

{% endblock %}

27 changes: 26 additions & 1 deletion squad/frontend/user_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
from rest_framework.authtoken.models import Token


from squad.core.models import Group, Project, Subscription, UserNamespace
from squad.core.models import Group, Project, Subscription, UserNamespace, UserPreferences
from squad.frontend.views import get_user_preferences


logger = logging.getLogger()
Expand All @@ -30,6 +31,29 @@ class Meta:
fields = ['first_name', 'last_name', 'email']


class UserPreferencesForm(forms.ModelForm):
class Meta:
model = UserPreferences
fields = ['display_failures_only']


@login_required
def user_preferences(request):
preferences = get_user_preferences(request.user)
if request.method == "POST":
form = UserPreferencesForm(request.POST, instance=preferences)
if form.is_valid():
form.save()
return redirect(request.path)
else:
form = UserPreferencesForm(instance=preferences)

context = {
'form': form,
}
return render(request, 'squad/user_settings/user_preferences.jinja2', context)


@login_required
def profile(request):
if request.method == "POST":
Expand Down Expand Up @@ -126,6 +150,7 @@ def projects(request):
url('^profile/$', profile, name='settings-profile'),
url('^api-token/$', api_token, name='settings-api-token'),
url('^subscriptions/$', subscriptions, name='settings-subscriptions'),
url('^user-preferences/$', user_preferences, name='settings-user-preferences'),
url(r'^remove-subscription/(?P<id>\d+)$', remove_subscription, name='settings-subscription-remove'),
url(r'^remove-subscription/$', remove_subscription, name='settings-subscription-remove-post'),
url('^projects/$', projects, name='settings-projects'),
Expand Down
20 changes: 18 additions & 2 deletions squad/frontend/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from squad.ci.models import TestJob
from squad.core.models import Group, Metric, ProjectStatus, Status, MetricThreshold, KnownIssue, Test
from squad.core.models import Build, Subscription, TestRun, SuiteMetadata
from squad.core.models import Build, Subscription, TestRun, SuiteMetadata, UserPreferences
from squad.core.queries import get_metric_data, test_confidence
from squad.frontend.queries import get_metrics_list
from squad.frontend.utils import file_type, alphanum_sort
Expand All @@ -29,6 +29,18 @@ def __init__(self, date, days):
super(BuildDeleted, self).__init__(msg)


def get_user_preferences(user):
if user.is_authenticated:
try:
preferences = UserPreferences.objects.get(user=user)
except UserPreferences.DoesNotExist:
preferences = UserPreferences.objects.create(user=user)
else:
return None

return preferences


def get_build(project, version):
if version == 'latest-finished':
status = ProjectStatus.objects.prefetch_related('build').filter(
Expand Down Expand Up @@ -362,7 +374,11 @@ def build(request, group_slug, project_slug, version):
project = request.project
build = get_build(project, version)

failures_only = request.GET.get('failures_only', 'true')
user_default_failures_only = ""
user_preferences = get_user_preferences(request.user)
if user_preferences:
user_default_failures_only = str(user_preferences.display_failures_only).lower()
failures_only = request.GET.get('failures_only', user_default_failures_only)
if failures_only not in ['true', 'false']:
failures_only = 'true'

Expand Down
42 changes: 40 additions & 2 deletions test/frontend/test_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from django.test import Client
import json

from squad.frontend.views import get_user_preferences

tests_file = {
("suite1/test%d" % i): "fail" for i in range(0, 50)
}
Expand Down Expand Up @@ -148,18 +150,54 @@ def setUp(self):

def test_table_layout(self):
response = self.client.get('/mygroup/myproject/build/1/?results_layout=table')
self.assertIn("onclick=\"window.location = \'?results_layout=table&amp;failures_only=false#test-results'\"", response.content.decode("utf-8"))
self.assertEqual(200, response.status_code)

def test_table_layout_failures_only(self):
def test_table_layout_failures_only_false(self):
response = self.client.get('/mygroup/myproject/build/1/?results_layout=table&failures_only=false')
self.assertIn("onclick=\"window.location = \'?results_layout=table&amp;failures_only=true#test-results'\"", response.content.decode("utf-8"))
self.assertEqual(200, response.status_code)

def test_table_layout_failures_only_true(self):
response = self.client.get('/mygroup/myproject/build/1/?results_layout=table&failures_only=true')
self.assertIn("onclick=\"window.location = \'?results_layout=table&amp;failures_only=false#test-results'\"", response.content.decode("utf-8"))
self.assertEqual(200, response.status_code)

def test_envbox_layout(self):
response = self.client.get('/mygroup/myproject/build/1/?results_layout=envbox')
self.assertIn("onclick=\"window.location = \'?results_layout=envbox&amp;failures_only=false#test-results'\"", response.content.decode("utf-8"))
self.assertEqual(200, response.status_code)

def test_envbox_layout_failures_only(self):
def test_envbox_layout_failures_only_false(self):
response = self.client.get('/mygroup/myproject/build/1/?results_layout=envbox&failures_only=false')
self.assertIn("onclick=\"window.location = \'?results_layout=envbox&amp;failures_only=true#test-results'\"", response.content.decode("utf-8"))
self.assertEqual(200, response.status_code)

def test_envbox_layout_failures_only_true(self):
response = self.client.get('/mygroup/myproject/build/1/?results_layout=envbox&failures_only=true')
self.assertIn("onclick=\"window.location = \'?results_layout=envbox&amp;failures_only=false#test-results'\"", response.content.decode("utf-8"))
self.assertEqual(200, response.status_code)

def test_failures_only_user_preference_false(self):
self.user = models.User.objects.create(username='theuser')
self.client = Client()
self.client.force_login(self.user)
self.user_preferences = get_user_preferences(user=self.user)
self.user_preferences.display_failures_only = False
self.user_preferences.save()
response = self.client.get('/mygroup/myproject/build/1/')
self.assertIn("onclick=\"window.location = \'?failures_only=true#test-results'\"", response.content.decode("utf-8"))
self.assertEqual(200, response.status_code)

def test_failures_only_user_preference_true(self):
self.user = models.User.objects.create(username='theuser')
self.client = Client()
self.client.force_login(self.user)
self.user_preferences = get_user_preferences(user=self.user)
self.user_preferences.display_failures_only = True
self.user_preferences.save()
response = self.client.get('/mygroup/myproject/build/1/')
self.assertIn("onclick=\"window.location = \'?failures_only=false#test-results'\"", response.content.decode("utf-8"))
self.assertEqual(200, response.status_code)

def test_suitebox_layout(self):
Expand Down

0 comments on commit b5bbdc9

Please sign in to comment.