Skip to content

Commit 24780f9

Browse files
suricactusgounux
authored andcommitted
Merge pull request #1335 from opengisch/QF-6692-fix-empty-project-package
edit(packaging): avoid "empty project package"
1 parent 1fc7b9a commit 24780f9

File tree

2 files changed

+84
-48
lines changed

2 files changed

+84
-48
lines changed

docker-app/qfieldcloud/core/models.py

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,39 +1305,65 @@ def shared_datasets_project(self) -> Project | None:
13051305
except Project.DoesNotExist:
13061306
return None
13071307

1308-
def latest_package_job_for_user(self, user: User) -> PackageJob | None:
1309-
"""Returns the last package job for the user.
1308+
def package_jobs_for_user(self, user: User) -> PackageJobQuerySet:
1309+
"""Returns all package jobs for the user.
13101310
13111311
Args:
13121312
user: The user to check for.
13131313
13141314
Returns:
1315-
The last package job for the user.
1315+
QuerySet of all package jobs for the user.
13161316
"""
1317+
secret_filters = Q(project=self, organization=None, assigned_to=user)
1318+
13171319
if self.owner.is_organization:
1318-
secret_qs = Secret.objects.filter(
1319-
Q(organization=self.owner, assigned_to=user)
1320-
| Q(project=self, assigned_to=user)
1321-
)
1322-
else:
1323-
secret_qs = Secret.objects.filter(project=self, assigned_to=user)
1320+
secret_filters |= Q(project=None, organization=self.owner, assigned_to=user)
13241321

1325-
jobs_qs = (
1326-
self.jobs.annotate(has_user_secret=Exists(secret_qs))
1327-
.filter(Q(has_user_secret=False) | Q(triggered_by=user))
1328-
.order_by("-created_at")
1322+
secret_qs = Secret.objects.filter(secret_filters)
1323+
1324+
jobs_qs = self.jobs.filter(
1325+
type=Job.Type.PACKAGE,
1326+
)
1327+
1328+
jobs_qs = jobs_qs.annotate(has_user_secret=Exists(secret_qs)).filter(
1329+
Q(has_user_secret=False) | Q(triggered_by=user)
13291330
)
13301331

1331-
jobs_qs = jobs_qs.order_by("-created_at")
1332+
return jobs_qs
13321333

1334+
def latest_finished_package_job_for_user(self, user: User) -> PackageJob | None:
1335+
"""Returns the last finished package job for the user.
1336+
1337+
Args:
1338+
user: The user to check for.
1339+
1340+
Returns:
1341+
The last finished package job for the user.
1342+
"""
13331343
return (
1334-
jobs_qs.filter(
1335-
type=Job.Type.PACKAGE,
1344+
self.package_jobs_for_user(user)
1345+
.exclude(
1346+
status__in=[
1347+
Job.Status.PENDING,
1348+
Job.Status.QUEUED,
1349+
Job.Status.STARTED,
1350+
]
13361351
)
13371352
.order_by("-created_at")
13381353
.first()
13391354
)
13401355

1356+
def latest_package_job_for_user(self, user: User) -> PackageJob | None:
1357+
"""Returns the last package job for the user.
1358+
1359+
Args:
1360+
user: The user to check for.
1361+
1362+
Returns:
1363+
The last package job for the user.
1364+
"""
1365+
return self.package_jobs_for_user(user).order_by("-created_at").first()
1366+
13411367
def latest_package_jobs(self) -> PackageJobQuerySet:
13421368
"""Returns all the last package jobs for the users of the project.
13431369

docker-app/qfieldcloud/core/views/package_views.py

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ class LegacyLatestPackageView(views.APIView):
8888
def get(self, request, project_id):
8989
"""Get last project package status and file list."""
9090
project = Project.objects.get(id=project_id)
91-
latest_package_job = project.latest_package_job_for_user(request.user)
91+
latest_finished_package_job = project.latest_finished_package_job_for_user(
92+
request.user
93+
)
9294

9395
# Check if the project was packaged at least once
94-
if not latest_package_job:
96+
if not latest_finished_package_job:
9597
raise exceptions.InvalidJobError(
9698
"Packaging has never been triggered or successful for this project."
9799
)
@@ -107,7 +109,9 @@ def get(self, request, project_id):
107109
else:
108110
skip_metadata = bool(skip_metadata_param)
109111

110-
for f in get_project_package_files(project_id, str(latest_package_job.id)):
112+
for f in get_project_package_files(
113+
project_id, str(latest_finished_package_job.id)
114+
):
111115
file_data = {
112116
"name": f.name,
113117
"size": f.size,
@@ -146,18 +150,18 @@ def get(self, request, project_id):
146150
if not files:
147151
raise exceptions.InvalidJobError("Empty project package.")
148152

149-
assert latest_package_job.feedback
153+
assert latest_finished_package_job.feedback
150154

151-
feedback_version = latest_package_job.feedback.get("feedback_version")
155+
feedback_version = latest_finished_package_job.feedback.get("feedback_version")
152156

153157
# version 2 and 3 have the same format
154158
if feedback_version in ["2.0", "3.0"]:
155-
layers = latest_package_job.feedback["outputs"]["qgis_layers_data"][
156-
"layers_by_id"
157-
]
159+
layers = latest_finished_package_job.feedback["outputs"][
160+
"qgis_layers_data"
161+
]["layers_by_id"]
158162
# support some ancient QFieldCloud job data
159163
elif feedback_version is None:
160-
steps = latest_package_job.feedback.get("steps", [])
164+
steps = latest_finished_package_job.feedback.get("steps", [])
161165
layers = (
162166
steps[1]["outputs"]["layer_checks"]
163167
if len(steps) > 2 and steps[1].get("stage", 1) == 2
@@ -171,10 +175,10 @@ def get(self, request, project_id):
171175
{
172176
"files": files,
173177
"layers": layers,
174-
"status": latest_package_job.status,
175-
"package_id": latest_package_job.pk,
176-
"packaged_at": latest_package_job.project.data_last_packaged_at,
177-
"data_last_updated_at": latest_package_job.project.data_last_updated_at,
178+
"status": latest_finished_package_job.status,
179+
"package_id": latest_finished_package_job.pk,
180+
"packaged_at": latest_finished_package_job.project.data_last_packaged_at,
181+
"data_last_updated_at": latest_finished_package_job.project.data_last_updated_at,
178182
}
179183
)
180184

@@ -197,15 +201,17 @@ def get(self, request, project_id, filename):
197201
exceptions.InvalidJobError: [description]
198202
"""
199203
project = Project.objects.get(id=project_id)
200-
latest_package_job = project.latest_package_job_for_user(request.user)
204+
latest_finished_package_job = project.latest_finished_package_job_for_user(
205+
request.user
206+
)
201207

202208
# Check if the project was packaged at least once
203-
if not latest_package_job:
209+
if not latest_finished_package_job:
204210
raise exceptions.InvalidJobError(
205211
"Packaging has never been triggered or successful for this project."
206212
)
207213

208-
key = f"projects/{project_id}/packages/{latest_package_job.id}/{filename}"
214+
key = f"projects/{project_id}/packages/{latest_finished_package_job.id}/{filename}"
209215

210216
# files within attachment dirs that do not exist is the packaged files should be served
211217
# directly from the original data storage
@@ -269,17 +275,19 @@ class LatestPackageView(views.APIView):
269275
def get(self, request, project_id):
270276
"""Get last project package status and file list."""
271277
project = get_object_or_404(Project, id=project_id)
272-
latest_package_job = project.latest_package_job_for_user(request.user)
278+
latest_finished_package_job = project.latest_finished_package_job_for_user(
279+
request.user
280+
)
273281

274282
# Check if the project was packaged at least once
275-
if not latest_package_job:
283+
if not latest_finished_package_job:
276284
raise exceptions.InvalidJobError(
277285
"Packaging has never been triggered or successful for this project."
278286
)
279287

280288
files_qs = File.objects.filter(
281289
project_id=project_id,
282-
package_job=latest_package_job,
290+
package_job=latest_finished_package_job,
283291
file_type=File.FileType.PACKAGE_FILE,
284292
)
285293

@@ -298,17 +306,17 @@ def get(self, request, project_id):
298306
if not file_serializer.data:
299307
raise exceptions.InvalidJobError("Empty project package.")
300308

301-
assert latest_package_job.feedback
309+
assert latest_finished_package_job.feedback
302310

303-
feedback_version = latest_package_job.feedback.get("feedback_version")
311+
feedback_version = latest_finished_package_job.feedback.get("feedback_version")
304312
# version 2 and 3 have the same format
305313
if feedback_version in ["2.0", "3.0"]:
306-
layers = latest_package_job.feedback["outputs"]["qgis_layers_data"][
307-
"layers_by_id"
308-
]
314+
layers = latest_finished_package_job.feedback["outputs"][
315+
"qgis_layers_data"
316+
]["layers_by_id"]
309317
# support some ancient QFieldCloud job data
310318
elif feedback_version is None:
311-
steps = latest_package_job.feedback.get("steps", [])
319+
steps = latest_finished_package_job.feedback.get("steps", [])
312320
layers = (
313321
steps[1]["outputs"]["layer_checks"]
314322
if len(steps) > 2 and steps[1].get("stage", 1) == 2
@@ -322,10 +330,10 @@ def get(self, request, project_id):
322330
{
323331
"files": file_serializer.data,
324332
"layers": layers,
325-
"status": latest_package_job.status,
326-
"package_id": latest_package_job.pk,
327-
"packaged_at": latest_package_job.project.data_last_packaged_at,
328-
"data_last_updated_at": latest_package_job.project.data_last_updated_at,
333+
"status": latest_finished_package_job.status,
334+
"package_id": latest_finished_package_job.pk,
335+
"packaged_at": latest_finished_package_job.project.data_last_packaged_at,
336+
"data_last_updated_at": latest_finished_package_job.project.data_last_updated_at,
329337
}
330338
)
331339

@@ -348,10 +356,12 @@ def get(self, request, project_id, filename):
348356
exceptions.InvalidJobError: raised when packaging has never been triggered or successful for this project
349357
"""
350358
project = get_object_or_404(Project, id=project_id)
351-
latest_package_job = project.latest_package_job_for_user(request.user)
359+
latest_finished_package_job = project.latest_finished_package_job_for_user(
360+
request.user
361+
)
352362

353363
# Check if the project was packaged at least once
354-
if not latest_package_job:
364+
if not latest_finished_package_job:
355365
raise exceptions.InvalidJobError(
356366
"Packaging has never been triggered or successful for this project."
357367
)
@@ -369,7 +379,7 @@ def get(self, request, project_id, filename):
369379
project_id,
370380
filename,
371381
file_type=file_type,
372-
package_job_id=latest_package_job.id,
382+
package_job_id=latest_finished_package_job.id,
373383
)
374384

375385

0 commit comments

Comments
 (0)