Skip to content

Commit e7307bb

Browse files
committed
Merge branch 'master' into feature/advanced_search/join_attrs
2 parents 4535603 + c749c69 commit e7307bb

File tree

20 files changed

+365
-416
lines changed

20 files changed

+365
-416
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@
1111

1212
### Fixed
1313

14+
## v3.82.0
15+
16+
### Added
17+
* Enable to check verification error details on webhooks by users.
18+
Contributed by @syucream
19+
20+
### Changed
21+
* Use enum on the job status.
22+
Contributed by @syucream
23+
1424
## v3.81.0
1525

1626
### Changed

acl/api_v2/views.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from drf_spectacular.utils import OpenApiParameter, extend_schema
77
from rest_framework import generics, mixins, viewsets
88
from rest_framework.permissions import BasePermission, IsAuthenticated
9+
from rest_framework.request import Request
910
from rest_framework.response import Response
1011

1112
from acl.api_v2.serializers import ACLHistorySerializer, ACLSerializer
@@ -18,7 +19,7 @@
1819

1920

2021
class ACLPermission(BasePermission):
21-
def has_object_permission(self, request, view, obj):
22+
def has_object_permission(self, request: Request, view, obj) -> bool:
2223
user: User = request.user
2324
permisson = {
2425
"retrieve": ACLType.Readable,
@@ -50,7 +51,7 @@ def get_queryset(self):
5051
"""Unnecessary in this serializer"""
5152
pass
5253

53-
def get(self, request, pk: int):
54+
def get(self, request: Request, pk: int) -> Response:
5455
acl = ACLBase.objects.filter(id=pk).first()
5556
if not acl:
5657
raise Http404

airone/lib/job.py

+17-17
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,24 @@ def may_schedule_until_job_is_ready(
1010
@functools.wraps(func)
1111
def wrapper(kls, job_id: int):
1212
job = Job.objects.get(id=job_id)
13-
if job.proceed_if_ready():
14-
# update Job status from PREPARING to PROCEEDING
15-
job.update(JobStatus.PROCESSING.value)
1613

17-
try:
18-
# running Job processing
19-
ret: JobStatus | tuple[int, str] | None = func(kls, job)
20-
except Exception:
21-
ret = JobStatus.ERROR
14+
if not job.proceed_if_ready():
15+
return
16+
# update Job status from PREPARING to PROCEEDING
17+
job.update(JobStatus.PROCESSING.value)
2218

23-
# update Job status after finishing Job processing
24-
if isinstance(ret, JobStatus):
25-
job.update(status=ret.value)
26-
elif (
27-
isinstance(ret, tuple) and isinstance(ret[0], JobStatus) and isinstance(ret[1], str)
28-
):
29-
job.update(status=ret[0].value, text=ret[1])
30-
elif not job.is_canceled():
31-
job.update(JobStatus.DONE.value)
19+
try:
20+
# running Job processing
21+
ret: JobStatus | tuple[JobStatus, str] | None = func(kls, job)
22+
except Exception:
23+
ret = JobStatus.ERROR
24+
25+
# update Job status after finishing Job processing
26+
if isinstance(ret, JobStatus):
27+
job.update(status=ret.value)
28+
elif isinstance(ret, tuple) and isinstance(ret[0], JobStatus) and isinstance(ret[1], str):
29+
job.update(status=ret[0].value, text=ret[1])
30+
elif not job.is_canceled():
31+
job.update(JobStatus.DONE.value)
3232

3333
return wrapper

dashboard/tasks.py

+10-20
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import csv
22
import io
33
import json
4-
from typing import Any, Optional
4+
from typing import Any
55

66
import yaml
77
from django.conf import settings
88
from natsort import natsorted
99

1010
from airone.celery import app
11+
from airone.lib.job import may_schedule_until_job_is_ready
1112
from airone.lib.types import AttrTypeValue
1213
from entry.models import Entry
13-
from job.models import Job, JobStatus
14+
from job.models import Job
1415

1516

16-
def _csv_export(job: Job, values, recv_data: dict, has_referral: bool) -> Optional[io.StringIO]:
17+
def _csv_export(job: Job, values, recv_data: dict, has_referral: bool) -> io.StringIO | None:
1718
output = io.StringIO(newline="")
1819
writer = csv.writer(output)
1920

@@ -102,7 +103,7 @@ def _csv_export(job: Job, values, recv_data: dict, has_referral: bool) -> Option
102103
return output
103104

104105

105-
def _yaml_export(job: Job, values, recv_data: dict, has_referral: bool) -> Optional[io.StringIO]:
106+
def _yaml_export(job: Job, values, recv_data: dict, has_referral: bool) -> io.StringIO | None:
106107
output = io.StringIO()
107108

108109
def _get_attr_value(atype: int, value: dict):
@@ -163,22 +164,15 @@ def _get_attr_value(atype: int, value: dict):
163164

164165

165166
@app.task(bind=True)
166-
def export_search_result(self, job_id):
167-
job = Job.objects.get(id=job_id)
168-
169-
if not job.proceed_if_ready():
170-
return
171-
172-
# set flag to indicate that this job starts processing
173-
job.update(JobStatus.PROCESSING.value)
174-
167+
@may_schedule_until_job_is_ready
168+
def export_search_result(self, job: Job):
175169
user = job.user
176170
recv_data = json.loads(job.params)
177171

178172
# Do not care whether the "has_referral" value is
179173
has_referral: bool = recv_data.get("has_referral", False)
180-
referral_name: Optional[str] = recv_data.get("referral_name")
181-
entry_name: Optional[str] = recv_data.get("entry_name")
174+
referral_name: str | None = recv_data.get("referral_name")
175+
entry_name: str | None = recv_data.get("entry_name")
182176
if has_referral and referral_name is None:
183177
referral_name = ""
184178

@@ -191,15 +185,11 @@ def export_search_result(self, job_id):
191185
referral_name,
192186
)
193187

194-
io_stream: Optional[io.StringIO] = None
188+
io_stream: io.StringIO | None = None
195189
if recv_data["export_style"] == "yaml":
196190
io_stream = _yaml_export(job, resp["ret_values"], recv_data, has_referral)
197191
elif recv_data["export_style"] == "csv":
198192
io_stream = _csv_export(job, resp["ret_values"], recv_data, has_referral)
199193

200194
if io_stream:
201195
job.set_cache(io_stream.getvalue())
202-
203-
# update job status and save it except for the case that target job is canceled.
204-
if not job.is_canceled():
205-
job.update(JobStatus.DONE.value)

entity/api_v2/serializers.py

+13-13
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ class Meta:
5959
read_only_fields = ["is_verified"]
6060
extra_kwargs = {"url": {"required": False}}
6161

62-
def validate_id(self, id: Optional[int]):
62+
def validate_id(self, id: int | None):
6363
entity: Entity = self.parent.parent.instance
6464
if id is not None and not entity.webhooks.filter(id=id).exists():
6565
raise ObjectNotExistsError("Invalid id(%s) object does not exist" % id)
6666

6767
return id
6868

69-
def validate(self, webhook):
69+
def validate(self, webhook: dict):
7070
# case create Webhook
7171
if "id" not in webhook and "url" not in webhook:
7272
raise RequiredParameterError("id or url field is required")
@@ -95,13 +95,13 @@ class Meta:
9595
"note",
9696
]
9797

98-
def validate_type(self, type):
98+
def validate_type(self, type: int | None):
9999
if type not in AttrTypeValue.values():
100100
raise ObjectNotExistsError("attrs type(%s) does not exist" % type)
101101

102102
return type
103103

104-
def validate(self, attr):
104+
def validate(self, attr: dict):
105105
referral = attr.get("referral", [])
106106

107107
if attr["type"] & AttrTypeValue["object"] and not len(referral):
@@ -130,21 +130,21 @@ class Meta:
130130
]
131131
extra_kwargs = {"name": {"required": False}, "type": {"required": False}}
132132

133-
def validate_id(self, id):
133+
def validate_id(self, id: int):
134134
entity: Entity = self.parent.parent.instance
135135
entity_attr: Optional[EntityAttr] = entity.attrs.filter(id=id, is_active=True).first()
136136
if not entity_attr:
137137
raise ObjectNotExistsError("Invalid id(%s) object does not exist" % id)
138138

139139
return id
140140

141-
def validate_type(self, type):
141+
def validate_type(self, type: int | None):
142142
if type not in AttrTypeValue.values():
143143
raise ObjectNotExistsError("attrs type(%s) does not exist" % type)
144144

145145
return type
146146

147-
def validate(self, attr):
147+
def validate(self, attr: dict):
148148
# case update EntityAttr
149149
if "id" in attr:
150150
entity_attr = EntityAttr.objects.get(id=attr["id"])
@@ -207,14 +207,14 @@ def _update_or_create(
207207
user: User,
208208
entity_id: Optional[int],
209209
validated_data: EntityCreateData | EntityUpdateData,
210-
):
210+
) -> Entity:
211211
is_toplevel_data = validated_data.pop("is_toplevel", None)
212212
attrs_data = validated_data.pop("attrs")
213213
webhooks_data = validated_data.pop("webhooks")
214214

215215
entity: Entity
216216
entity, is_created_entity = Entity.objects.get_or_create(
217-
id=entity_id, created_user=user, defaults={**validated_data}
217+
id=entity_id, defaults={**validated_data}
218218
)
219219
if not is_created_entity:
220220
# record history for specific fields on update
@@ -347,7 +347,7 @@ class Meta:
347347
fields = ["id", "name", "note", "is_toplevel", "attrs", "webhooks"]
348348
extra_kwargs = {"note": {"write_only": True}}
349349

350-
def validate_name(self, name):
350+
def validate_name(self, name: str):
351351
if Entity.objects.filter(name=name, is_active=True).exists():
352352
raise DuplicatedObjectExistsError("Duplication error. There is same named Entity")
353353

@@ -399,7 +399,7 @@ class Meta:
399399
fields = ["id", "name", "note", "is_toplevel", "attrs", "webhooks"]
400400
extra_kwargs = {"name": {"required": False}, "note": {"write_only": True}}
401401

402-
def validate_name(self, name):
402+
def validate_name(self, name: str):
403403
if self.instance.name != name and Entity.objects.filter(name=name, is_active=True).exists():
404404
raise DuplicatedObjectExistsError("Duplication error. There is same named Entity")
405405

@@ -630,10 +630,10 @@ class EntityImportExportRootSerializer(serializers.Serializer):
630630
Entity = EntityImportExportSerializer(many=True)
631631
EntityAttr = EntityAttrImportExportSerializer(many=True)
632632

633-
def save(self, **kwargs):
633+
def save(self, **kwargs) -> None:
634634
user: User = self.context.get("request").user
635635

636-
def _do_import(resource, iter_data):
636+
def _do_import(resource, iter_data: Any):
637637
results = []
638638
for data in iter_data:
639639
try:

entity/api_v2/views.py

+11-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from rest_framework.exceptions import ValidationError
1212
from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination
1313
from rest_framework.permissions import BasePermission, IsAuthenticated
14+
from rest_framework.request import Request
1415
from rest_framework.response import Response
1516
from rest_framework.serializers import Serializer
1617

@@ -34,7 +35,7 @@
3435

3536

3637
@http_get
37-
def history(request, pk):
38+
def history(request, pk: int) -> HttpResponse:
3839
if not Entity.objects.filter(id=pk).exists():
3940
return HttpResponse("Failed to get entity of specified id", status=400)
4041

@@ -68,7 +69,7 @@ def history(request, pk):
6869

6970

7071
class EntityPermission(BasePermission):
71-
def has_permission(self, request, view):
72+
def has_permission(self, request: Request, view) -> bool:
7273
permisson = {
7374
"list": ACLType.Readable,
7475
"create": ACLType.Writable,
@@ -82,7 +83,7 @@ def has_permission(self, request, view):
8283
view.entity = entity
8384
return True
8485

85-
def has_object_permission(self, request, view, obj):
86+
def has_object_permission(self, request: Request, view, obj) -> bool:
8687
user: User = request.user
8788
permisson = {
8889
"retrieve": ACLType.Readable,
@@ -131,7 +132,7 @@ def get_queryset(self):
131132
return Entity.objects.filter(**filter_condition).exclude(**exclude_condition)
132133

133134
@extend_schema(request=EntityCreateSerializer)
134-
def create(self, request, *args, **kwargs):
135+
def create(self, request: Request, *args, **kwargs) -> Response:
135136
user: User = request.user
136137

137138
serializer = EntityCreateSerializer(data=request.data, context={"_user": user})
@@ -143,7 +144,7 @@ def create(self, request, *args, **kwargs):
143144
return Response(status=status.HTTP_202_ACCEPTED)
144145

145146
@extend_schema(request=EntityUpdateSerializer)
146-
def update(self, request, *args, **kwargs):
147+
def update(self, request: Request, *args, **kwargs) -> Response:
147148
user: User = request.user
148149
entity: Entity = self.get_object()
149150

@@ -157,7 +158,7 @@ def update(self, request, *args, **kwargs):
157158

158159
return Response(status=status.HTTP_202_ACCEPTED)
159160

160-
def destroy(self, request, *args, **kwargs):
161+
def destroy(self, request: Request, *args, **kwargs) -> Response:
161162
user: User = request.user
162163
entity: Entity = self.get_object()
163164

@@ -197,7 +198,7 @@ def get_queryset(self):
197198
return self.queryset.filter(schema=entity)
198199

199200
@extend_schema(request=EntryCreateSerializer)
200-
def create(self, request, entity_id):
201+
def create(self, request: Request, entity_id: int) -> Response:
201202
user: User = request.user
202203
request.data["schema"] = entity_id
203204

@@ -233,7 +234,7 @@ class EntityImportAPI(generics.GenericAPIView):
233234
parser_classes = [YAMLParser]
234235
serializer_class = serializers.Serializer
235236

236-
def post(self, request):
237+
def post(self, request: Request) -> Response:
237238
import_datas = request.data
238239
serializer = EntityImportExportRootSerializer(
239240
data=import_datas, context={"request": self.request}
@@ -248,7 +249,7 @@ class EntityExportAPI(generics.RetrieveAPIView):
248249
serializer_class = EntityImportExportRootSerializer
249250
renderer_classes = [YAMLRenderer]
250251

251-
def get_object(self):
252+
def get_object(self) -> dict:
252253
user: User = self.request.user
253254
entities = get_permitted_objects(user, Entity, ACLType.Readable)
254255
attrs = get_permitted_objects(user, EntityAttr, ACLType.Readable)
@@ -282,7 +283,7 @@ def get_queryset(self):
282283
# filter only names appear in all specified entities
283284
return EntityAttr.objects.filter(parent_entity__in=entities, is_active=True)
284285

285-
def get(self, request):
286+
def get(self, request: Request) -> Response:
286287
queryset = self.get_queryset()
287288

288289
entity_ids: List[int] = list(

0 commit comments

Comments
 (0)