Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add client.submissions.edit to edit an existing submission #19

Merged
merged 7 commits into from
Jan 24, 2023
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ with Client() as client:
forms = client.forms.list()
submissions = client.submissions.list(form_id=next(forms).xmlFormId)
form_data = client.submissions.get_table(form_id="birds", project_id=8)
comments = client.submissions.list_comments(form_id=next(forms).xmlFormId, instance_id="uuid:...")
```

**👉 Looking for more advanced examples? You can find detailed Jupyter notebooks, scripts, and webinars [here](examples).**
Expand All @@ -96,15 +97,21 @@ The `Client` is specific to a configuration and cache file. These approximately
Available methods on `Client`:

- Projects
- get
- list
- list: Read all Project details.
- get: Read Project details.
- Forms
- get
- list
- list: Read all Form details.
- get: Read Form details.
- Submissions
- get
- list
- get_table
- list: Read all Submission metadata.
- get: Read Submission metadata.
- get_table: Read Submission data.
- create: Create a Submission.
- edit: Edit a submission, and optionally comment on it.
- review: Update Submission metadata (review state), and optionally comment on it.
- list_comments: Read Comment data for a Submission.
- add_comment: Create a Comment for a Submission.

- *for additional requests*
- get
- post
Expand Down
8 changes: 7 additions & 1 deletion pyodk/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import logging

__version__ = "0.1.0"
from pyodk import errors
from pyodk.client import Client

__all__ = (
"Client",
"errors",
)


logging.getLogger(__name__).addHandler(logging.NullHandler())
1 change: 1 addition & 0 deletions pyodk/__version__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "0.1.0"
1 change: 1 addition & 0 deletions pyodk/_endpoints/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__all__ = tuple()
4 changes: 2 additions & 2 deletions pyodk/endpoints/auth.py → pyodk/_endpoints/auth.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import logging
from typing import Optional

from pyodk import config
from pyodk._utils import config
from pyodk._utils.session import Session
from pyodk.errors import PyODKError
from pyodk.session import Session

log = logging.getLogger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion pyodk/endpoints/bases.py → pyodk/_endpoints/bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from pydantic import BaseModel

from pyodk.session import Session
from pyodk._utils.session import Session


class Model(BaseModel):
Expand Down
113 changes: 113 additions & 0 deletions pyodk/_endpoints/comments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import logging
from datetime import datetime
from typing import List, Optional

from pyodk._endpoints import bases
from pyodk._utils import validators as pv
from pyodk._utils.session import Session
from pyodk.errors import PyODKError

log = logging.getLogger(__name__)


class Comment(bases.Model):
body: str
actorId: int
createdAt: datetime


class URLs(bases.Model):
class Config:
frozen = True

list: str = "projects/{project_id}/forms/{form_id}/submissions/{instance_id}/comments"
post: str = "projects/{project_id}/forms/{form_id}/submissions/{instance_id}/comments"


class CommentService(bases.Service):
__slots__ = (
"urls",
"session",
"default_project_id",
"default_form_id",
"default_instance_id",
)

def __init__(
self,
session: Session,
default_project_id: Optional[int] = None,
default_form_id: Optional[str] = None,
default_instance_id: Optional[str] = None,
urls: URLs = None,
):
self.urls: URLs = urls if urls is not None else URLs()
self.session: Session = session
self.default_project_id: Optional[int] = default_project_id
self.default_form_id: Optional[str] = default_form_id
self.default_instance_id: Optional[str] = default_instance_id

def list(
self,
form_id: Optional[str] = None,
project_id: Optional[int] = None,
instance_id: Optional[str] = None,
) -> List[Comment]:
"""
Read all Comment details.

:param form_id: The xmlFormId of the Form being referenced.
:param project_id: The id of the project the Submissions belong to.
:param instance_id: The instanceId of the Submission being referenced.
"""
try:
pid = pv.validate_project_id(project_id, self.default_project_id)
fid = pv.validate_form_id(form_id, self.default_form_id)
iid = pv.validate_instance_id(instance_id, self.default_instance_id)
except PyODKError as err:
log.error(err, exc_info=True)
raise err

response = self.session.response_or_error(
method="GET",
url=self.urls.list.format(project_id=pid, form_id=fid, instance_id=iid),
logger=log,
)
data = response.json()
return [Comment(**r) for r in data]

def post(
self,
comment: str,
project_id: Optional[int] = None,
form_id: Optional[str] = None,
instance_id: Optional[str] = None,
) -> Comment:
"""
Create a Comment.

:param comment: The text of the comment.
:param project_id: The id of the project this form belongs to.
:param form_id: The xmlFormId of the Form being referenced.
:param instance_id: The instanceId of the Submission being referenced.
"""
try:
pid = pv.validate_project_id(project_id, self.default_project_id)
fid = pv.validate_form_id(form_id, self.default_form_id)
iid = pv.validate_instance_id(instance_id, self.default_instance_id)
comment = pv.wrap_error(
validator=pv.v.str_validator, key="comment", value=comment
)
json = {"body": comment}
except PyODKError as err:
log.error(err, exc_info=True)
raise err

response = self.session.response_or_error(
method="POST",
url=self.urls.post.format(project_id=pid, form_id=fid, instance_id=iid),
logger=log,
json=json,
)
data = response.json()
return Comment(**data)
29 changes: 13 additions & 16 deletions pyodk/endpoints/forms.py → pyodk/_endpoints/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
from datetime import datetime
from typing import List, Optional

from pyodk import validators as pv
from pyodk.endpoints import bases
from pyodk._endpoints import bases
from pyodk._utils import validators as pv
from pyodk._utils.session import Session
from pyodk.errors import PyODKError
from pyodk.session import Session

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -34,6 +34,7 @@ class Config:
list: str = "projects/{project_id}/forms"
get: str = "projects/{project_id}/forms/{form_id}"


class FormService(bases.Service):
__slots__ = ("urls", "session", "default_project_id", "default_form_id")

Expand All @@ -51,19 +52,18 @@ def __init__(

def list(self, project_id: Optional[int] = None) -> List[Form]:
"""
Read the details of all Forms.
Read all Form details.

:param project_id: The id of the project the forms belong to.
"""
try:
pid = pv.validate_project_id(
project_id=project_id, default_project_id=self.default_project_id
)
pid = pv.validate_project_id(project_id, self.default_project_id)
except PyODKError as err:
log.error(err, exc_info=True)
raise err
else:
response = self.session.get_200_or_error(
response = self.session.response_or_error(
method="GET",
url=self.urls.list.format(project_id=pid),
logger=log,
)
Expand All @@ -76,23 +76,20 @@ def get(
project_id: Optional[int] = None,
) -> Form:
"""
Read the details of a Form.
Read Form details.

:param form_id: The id of this form as given in its XForms XML definition.
:param project_id: The id of the project this form belongs to.
"""
try:
pid = pv.validate_project_id(
project_id=project_id, default_project_id=self.default_project_id
)
fid = pv.validate_form_id(
form_id=form_id, default_form_id=self.default_form_id
)
pid = pv.validate_project_id(project_id, self.default_project_id)
fid = pv.validate_form_id(form_id, self.default_form_id)
except PyODKError as err:
log.error(err, exc_info=True)
raise err
else:
response = self.session.get_200_or_error(
response = self.session.response_or_error(
method="GET",
url=self.urls.get.format(project_id=pid, form_id=fid),
logger=log,
)
Expand Down
23 changes: 13 additions & 10 deletions pyodk/endpoints/projects.py → pyodk/_endpoints/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
from datetime import datetime
from typing import List, Optional

from pyodk import validators as pv
from pyodk.endpoints import bases
from pyodk._endpoints import bases
from pyodk._utils import validators as pv
from pyodk._utils.session import Session
from pyodk.errors import PyODKError
from pyodk.session import Session

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -48,27 +48,30 @@ def __init__(

def list(self) -> List[Project]:
"""
Read the details of all projects.
Read Project details.
"""
response = self.session.get_200_or_error(url=self.urls.list, logger=log)
response = self.session.response_or_error(
method="GET",
url=self.urls.list,
logger=log,
)
data = response.json()
return [Project(**r) for r in data]

def get(self, project_id: Optional[int] = None) -> Project:
"""
Read the details of a Project.
Read all Project details.

:param project_id: The id of the project to read.
"""
try:
pid = pv.validate_project_id(
project_id=project_id, default_project_id=self.default_project_id
)
pid = pv.validate_project_id(project_id, self.default_project_id)
except PyODKError as err:
log.error(err, exc_info=True)
raise err
else:
response = self.session.get_200_or_error(
response = self.session.response_or_error(
method="GET",
url=self.urls.get.format(project_id=pid),
logger=log,
)
Expand Down
Loading