Skip to content

Commit 2d6ce5a

Browse files
authored
Merge branch 'dev' into chore/remove-settings
2 parents adf87a3 + 31f4097 commit 2d6ce5a

File tree

25 files changed

+587
-313
lines changed

25 files changed

+587
-313
lines changed

.github/workflows/lint-python.yaml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ name: Lint Python code
22
on:
33
push:
44
branches: [ "main", "dev" ]
5+
pull_request:
6+
branches: [ "main", "dev" ]
57
jobs:
68
lint:
79
runs-on: ubuntu-24.04
@@ -16,10 +18,3 @@ jobs:
1618
isort $dirs --skip-glob '*/migrations/*'
1719
black $dirs --exclude '/migrations/'
1820
flake8 $dirs --exclude '*/migrations/*'
19-
# Suggest merging any changes
20-
- name: Create Pull Request
21-
# https://github.com/marketplace/actions/create-pull-request
22-
uses: peter-evans/create-pull-request@v7
23-
with:
24-
body: "Python code reformatted with black and isort"
25-
branch: "chore/python-formatting"

SORT/settings.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ def cast_to_boolean(obj: Any) -> bool:
6565
"django_extensions",
6666
"debug_toolbar",
6767
"qr_code",
68+
"crispy_forms",
69+
"crispy_bootstrap5",
6870
# apps created by FA:
6971
"home",
7072
"survey",
@@ -172,6 +174,7 @@ def cast_to_boolean(obj: Any) -> bool:
172174

173175
# Email settings
174176
# https://docs.djangoproject.com/en/5.1/topics/email/#email-backends
177+
175178
EMAIL_BACKEND = os.getenv("DJANGO_EMAIL_BACKEND", "django.core.mail.backends.smtp.EmailBackend")
176179
EMAIL_HOST = os.getenv("DJANGO_EMAIL_HOST")
177180
EMAIL_PORT = int(os.getenv("DJANGO_EMAIL_PORT", 465))
@@ -198,7 +201,9 @@ def cast_to_boolean(obj: Any) -> bool:
198201

199202
# Vite integration
200203
VITE_BASE_URL = "http://localhost:5173" # Url of vite dev server
201-
VITE_STATIC_DIR = "ui-components" # Path to vite-generated asset directory in the static folder
204+
VITE_STATIC_DIR = (
205+
"ui-components" # Path to vite-generated asset directory in the static folder
206+
)
202207
VITE_MANIFEST_FILE_PATH = os.path.join(VITE_STATIC_DIR, "manifest.json")
203208

204209
# FA: for production:
@@ -209,7 +214,17 @@ def cast_to_boolean(obj: Any) -> bool:
209214

210215
# File uploading
211216
MEDIA_ROOT = os.getenv("DJANGO_MEDIA_ROOT", BASE_DIR / "uploads")
212-
MEDIA_SUPPORTED_EXTENSIONS = [".jpg", ".jpeg", ".png", ".pdf", ".doc", ".docx", ".txt", ".csv", ".json"]
217+
MEDIA_SUPPORTED_EXTENSIONS = [
218+
".jpg",
219+
".jpeg",
220+
".png",
221+
".pdf",
222+
".doc",
223+
".docx",
224+
".txt",
225+
".csv",
226+
".json",
227+
]
213228

214229
# Security settings
215230
SESSION_COOKIE_SECURE = cast_to_boolean(
@@ -240,3 +255,8 @@ def cast_to_boolean(obj: Any) -> bool:
240255
"Midwives": "sort_only_config_midwives.json",
241256
"NMAHPs": "sort_only_config_nmahps.json",
242257
}
258+
259+
# Crispy enables Bootstrap styling on Django forms
260+
# https://django-crispy-forms.readthedocs.io/en/latest/install.html
261+
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
262+
CRISPY_TEMPLATE_PACK = "bootstrap5"

deploy.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ pip="$venv_dir/bin/pip"
1818
python_version="python3.12"
1919
python="$venv_dir/bin/python"
2020
env_file="$sort_dir/.env"
21-
frontend_dir="$sort_dir/assets/sort-survey-configurator"
2221
node_version=20
2322

2423
# Install British UTF-8 locale so we can use this with PostgreSQL.

home/admin.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
from django.contrib import admin
22

3-
from .models import (
4-
Organisation,
5-
OrganisationMembership,
6-
Project,
7-
User,
8-
)
3+
from .models import Organisation, OrganisationMembership, Project, User
94

105

116
# Register your models here.

home/management/commands/clear_orphaned_files.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
11
from pathlib import Path
2-
from django.core.management.base import BaseCommand, CommandError
2+
33
from django.conf import settings
4-
from survey.models import SurveyFile, SurveyEvidenceFile
4+
from django.core.management.base import BaseCommand
5+
6+
from survey.models import SurveyEvidenceFile, SurveyFile
57

68

79
class Command(BaseCommand):
810
help = "Clear orphaned uploaded files uploaded by the user"
911

10-
1112
def handle(self, *args, **options):
1213

1314
upload_root = Path(settings.MEDIA_ROOT)
1415

1516
# Gets all file in the uploads folder, delete any that's not in use
16-
for (dirpath, dir_names, file_names) in upload_root.walk():
17+
for dirpath, dir_names, file_names in upload_root.walk():
1718
for file_name in file_names:
18-
file_path = dirpath/file_name
19+
file_path = dirpath / file_name
1920
relative_path = file_path.relative_to(upload_root)
20-
if (SurveyEvidenceFile.objects.filter(file=str(relative_path)).count() < 1
21-
and SurveyFile.objects.filter(file=str(relative_path)).count() < 1):
21+
if (
22+
SurveyEvidenceFile.objects.filter(file=str(relative_path)).count()
23+
< 1
24+
and SurveyFile.objects.filter(file=str(relative_path)).count() < 1
25+
):
2226
print(f"Deleting {file_path}")
2327
file_path.unlink(missing_ok=True)
2428

2529
self.clear_empty_directories(settings.MEDIA_ROOT)
2630

27-
2831
def clear_empty_directories(self, root_dir: str):
2932
for item in Path(root_dir).iterdir():
3033
if item.is_dir():

home/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from django.db import models
77
from django.urls import reverse
88

9-
from .constants import ROLE_PROJECT_MANAGER, ROLES, ROLE_ADMIN
9+
from .constants import ROLE_ADMIN, ROLE_PROJECT_MANAGER, ROLES
1010

1111

1212
class UserManager(BaseUserManager):

home/services/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
# Create instances for use in views
66

77

8-
98
__all__ = [
109
"BasePermissionService",
1110
"ProjectService",

home/services/organisation.py

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
"""
22
Organisation service with integrated permissions
33
"""
4+
45
from typing import Dict, Optional, Set
5-
from django.core.exceptions import PermissionDenied
6+
67
from django.db.models import Count
78
from django.db.models.query import QuerySet
89

910
from ..constants import ROLE_ADMIN, ROLE_PROJECT_MANAGER
10-
from ..models import (
11-
Organisation,
12-
OrganisationMembership,
13-
Project,
14-
User
15-
)
11+
from ..models import Organisation, OrganisationMembership, Project, User
1612
from .base import BasePermissionService, requires_permission
1713

1814

@@ -21,7 +17,9 @@ class OrganisationService(BasePermissionService):
2117

2218
def get_user_role(self, user: User, organisation: Organisation) -> Optional[str]:
2319
try:
24-
membership = organisation.organisationmembership_set.filter(user=user).first()
20+
membership = organisation.organisationmembership_set.filter(
21+
user=user
22+
).first()
2523
return membership.role if membership else None
2624
except AttributeError: # In case user is AnonymousUser
2725
return None
@@ -77,7 +75,7 @@ def get_user_organisation_ids(self, user: User) -> Set[int]:
7775

7876
@requires_permission("edit", obj_param="organisation")
7977
def update_organisation(
80-
self, user: User, organisation: Organisation, data: Dict
78+
self, user: User, organisation: Organisation, data: Dict
8179
) -> Organisation:
8280
"""Update organisation with provided data"""
8381
for key, value in data.items():
@@ -86,7 +84,7 @@ def update_organisation(
8684
return organisation
8785

8886
def create_organisation(
89-
self, user: User, name: str, description: str = None
87+
self, user: User, name: str, description: str = None
9088
) -> Organisation:
9189
"""
9290
Create a new organisation, and add the creator to it.
@@ -101,11 +99,11 @@ def create_organisation(
10199

102100
@requires_permission("edit", obj_param="organisation")
103101
def add_user_to_organisation(
104-
self,
105-
user: User,
106-
user_to_add: User,
107-
organisation: Organisation,
108-
role: str,
102+
self,
103+
user: User,
104+
user_to_add: User,
105+
organisation: Organisation,
106+
role: str,
109107
) -> OrganisationMembership:
110108
"""Add a user to an organisation with specified role"""
111109
if role not in [ROLE_ADMIN, ROLE_PROJECT_MANAGER]:
@@ -119,15 +117,15 @@ def add_user_to_organisation(
119117

120118
@requires_permission("edit", obj_param="organisation")
121119
def remove_user_from_organisation(
122-
self, user: User, organisation: Organisation, removed_user: User
120+
self, user: User, organisation: Organisation, removed_user: User
123121
) -> None:
124122
"""Remove user from organisation"""
125123
OrganisationMembership.objects.filter(
126124
user=removed_user, organisation=organisation
127125
).delete()
128126

129127
def get_organisation_projects(
130-
self, organisation: Organisation, user: User = None, with_metrics: bool = True
128+
self, organisation: Organisation, user: User = None, with_metrics: bool = True
131129
) -> QuerySet[Project]:
132130
"""Get projects for an organisation with optional metrics"""
133131
if not self.can_view(user, organisation):
@@ -137,15 +135,15 @@ def get_organisation_projects(
137135

138136
# Add metrics
139137
if with_metrics:
140-
projects = base_query.annotate(
138+
base_query = base_query.annotate(
141139
survey_count=Count("survey__id", distinct=True),
142140
).select_related("created_by", "organisation")
143141

144142
return base_query.order_by("-created_at")
145143

146144
@requires_permission("view", obj_param="organisation")
147145
def get_organisation_members(
148-
self, user: User, organisation: Organisation
146+
self, user: User, organisation: Organisation
149147
) -> QuerySet[OrganisationMembership]:
150148
"""Get all members of an organisation with their roles"""
151149
return OrganisationMembership.objects.filter(

home/services/project.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,13 @@
22
Project service with integrated permissions
33
"""
44

5-
from typing import Optional, Dict
6-
from django.db.models.query import QuerySet
5+
from typing import Dict, Optional
6+
77
from django.core.exceptions import PermissionDenied
8+
from django.db.models.query import QuerySet
89

910
from ..constants import ROLE_ADMIN, ROLE_PROJECT_MANAGER
10-
from ..models import (
11-
Organisation,
12-
Project,
13-
User,
14-
)
11+
from ..models import Organisation, Project, User
1512
from .base import BasePermissionService, requires_permission
1613
from .organisation import organisation_service
1714

@@ -24,7 +21,7 @@ def get_user_role(self, user: User, project: Project) -> Optional[str]:
2421
try:
2522
return project.organisation.get_user_role(user)
2623
except (
27-
AttributeError
24+
AttributeError
2825
): # In case user is AnonymousUser or organisation method fails
2926
return None
3027

@@ -38,7 +35,7 @@ def can_edit(self, user: User, project: Project) -> bool:
3835
return role in [ROLE_ADMIN, ROLE_PROJECT_MANAGER]
3936

4037
def can_create(self, user: User, organisation: Organisation) -> bool:
41-
""" Needs to be at least a member of an organisation to create a project """
38+
"""Needs to be at least a member of an organisation to create a project"""
4239
role = organisation_service.get_user_role(user, organisation)
4340
return role in [ROLE_ADMIN, ROLE_PROJECT_MANAGER]
4441

@@ -62,7 +59,7 @@ def get_project(self, user: User, project: Project) -> Project:
6259

6360
@requires_permission("create", obj_param="organisation")
6461
def create_project(
65-
self, user: User, name: str, organisation: Organisation, description: str = None
62+
self, user: User, name: str, organisation: Organisation, description: str = None
6663
) -> Project:
6764
"""Create a new project"""
6865
if not self.can_create(user, organisation):

home/templates/home/password_reset_confirm.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
{% if field.field.required %}required{% endif %} />
3636
</div>
3737
{% endfor %}
38-
<button type="submit" class="btn btn-primary w-100">Send Password Reset Email</button>
38+
<button type="submit" class="btn btn-primary w-100">Save password</button>
3939
</form>
4040
<div class="text-center mt-2 small-text" style="font-size: 0.7rem;">
4141
<a href="{% url 'login' %}">Already have an account? Login here</a>

0 commit comments

Comments
 (0)