Skip to content

Commit

Permalink
feat: Support userActivationSettings parameter in RPC method `activ…
Browse files Browse the repository at this point in the history
…ate_survey`
  • Loading branch information
edgarrmondragon committed Nov 14, 2023
1 parent 3ddeedc commit 400020c
Show file tree
Hide file tree
Showing 15 changed files with 127 additions and 36 deletions.
2 changes: 1 addition & 1 deletion .changes/unreleased/Added-20231028-222932.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
kind: Added
body: Support `DestSurveyID` parameter to RPC method `copy_survey`
body: Support `DestSurveyID` parameter in RPC method `copy_survey`
time: 2023-10-28T22:29:32.491728-06:00
custom:
Issue: "1016"
5 changes: 5 additions & 0 deletions .changes/unreleased/Added-20231109-165350.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: Added
body: Support `userActivationSettings` parameter in RPC method `activate_survey`
time: 2023-11-09T16:53:50.378464-06:00
custom:
Issue: "1026"
5 changes: 5 additions & 0 deletions .changes/unreleased/Fixed-20231109-165446.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: Fixed
body: Update `types.YesNo` to include inherited (`I`) values
time: 2023-11-09T16:54:46.179939-06:00
custom:
Issue: "1026"
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[flake8]
select = DAR
select = DOC
docstring_style=google
max-line-length = 88
strictness = short
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ repos:
hooks:
- id: flake8
additional_dependencies:
- darglint==1.8.1
- pydoclint==0.3.8

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.6.1
rev: v1.7.0
hooks:
- id: mypy
additional_dependencies:
Expand All @@ -66,7 +66,7 @@ repos:
- id: validate_manifest

- repo: https://github.com/hadialqattan/pycln
rev: v2.3.0
rev: v2.4.0
hooks:
- id: pycln
args: [--all]
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ Python.
<!-- start integration status -->
| | **PostgreSQL** | **MySQL** |
| - |:--: | :-: |
| 6.3.3 |||
| 6.3.1 |||
| 6.3.0 |||
| 6.2.11 |||
| 5.6.44 |||
| 5.6.43 |||
| 5.6.42 |||
| 5.6.41 |||
| 5.6.40 |||
<!-- end integration status -->

## Installation
Expand Down
9 changes: 4 additions & 5 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,12 @@ target-version = "py38"
[tool.ruff.lint]
explicit-preview-rules = false
ignore = [
"ANN101", # missing-type-self
"DJ", # flake8-django
"FIX002", # line-contains-todo
"ANN101", # missing-type-self
"DJ", # flake8-django
"FIX002", # line-contains-todo
"COM812", # missing-trailing-comma
"ISC001", # single-line-implicit-string-concatenation
"D107", # undocumented-public-init
]
preview = true
select = [
Expand Down
19 changes: 16 additions & 3 deletions src/citric/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ def __init__(
requests_session: requests.Session | None = None,
auth_plugin: str = "Authdb",
) -> None:
"""Create a LimeSurvey Python API client."""
self.__session = self.session_class(
url,
username,
Expand Down Expand Up @@ -169,20 +168,34 @@ def get_fieldmap(self, survey_id: int) -> dict[str, t.Any]:
"""
return self.session.get_fieldmap(survey_id)

def activate_survey(self, survey_id: int) -> types.OperationStatus:
def activate_survey(
self,
survey_id: int,
*,
user_activation_settings: types.SurveyUserActivationSettings | None = None,
) -> types.OperationStatus:
"""Activate a survey.
Calls :rpc_method:`activate_survey`.
Args:
survey_id: ID of survey to be activated.
user_activation_settings: Optional user activation settings.
Returns:
Status and plugin feedback.
.. versionadded:: 0.0.1
"""
return self.session.activate_survey(survey_id)
activation_settings = (
{
key: "Y" if value else "N"
for key, value in user_activation_settings.items()
}
if user_activation_settings
else None
)
return self.session.activate_survey(survey_id, activation_settings)

def activate_tokens(
self,
Expand Down
13 changes: 5 additions & 8 deletions src/citric/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ class ResponseMismatchError(Exception):


class LimeSurveyError(Exception):
"""Basic exception raised by LimeSurvey."""
"""Basic exception raised by LimeSurvey.
def __init__(self, message: str) -> None:
"""Create a generic error for the LimeSurvey RPC API.
Args:
message: Exception message. By default none, and a generic message is used.
"""

Args:
message: Exception message. By default none, and a generic message is used.
"""
def __init__(self, message: str) -> None:
super().__init__(message)


Expand All @@ -31,15 +30,13 @@ class RPCInterfaceNotEnabledError(LimeSurveyError):
"""RPC interface not enabled on LimeSurvey."""

def __init__(self) -> None:
"""Create a new exception."""
super().__init__("RPC interface not enabled")


class InvalidJSONResponseError(LimeSurveyError):
"""RPC interface maybe not enabled on LimeSurvey."""

def __init__(self) -> None:
"""Create a new exception."""
msg = (
"Received a non-JSON response, verify that the JSON RPC interface is "
"enabled in global settings"
Expand Down
8 changes: 6 additions & 2 deletions src/citric/method.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@


class Method(t.Generic[T]):
"""RPC method."""
"""RPC method.
Args:
caller: RPC caller function.
name: RPC method name.
"""

def __init__(self, caller: t.Callable[[str], T], name: str) -> None:
"""Instantiate an RPC method."""
self.__caller = caller
self.__name = name

Expand Down
1 change: 0 additions & 1 deletion src/citric/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ def __init__(
requests_session: requests.Session | None = None,
json_encoder: type[json.JSONEncoder] | None = None,
) -> None:
"""Create a LimeSurvey RPC session."""
self.url = url
self._session = requests_session or requests.session()
self._session.headers["User-Agent"] = self.USER_AGENT
Expand Down
23 changes: 22 additions & 1 deletion src/citric/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@
"RPCResponse",
"SetQuotaPropertiesResult",
"SurveyProperties",
"SurveyUserActivationSettings",
"CPDBParticipantImportResult",
]

Result: TypeAlias = t.Any
YesNo: TypeAlias = t.Literal["Y", "N"]
YesNo: TypeAlias = t.Literal["Y", "N", "I"]


class FileUploadResult(t.TypedDict):
Expand Down Expand Up @@ -495,3 +496,23 @@ class CPDBParticipantImportResult(t.TypedDict):

ImportCount: int
UpdateCount: int


class SurveyUserActivationSettings(t.TypedDict, total=False):
"""User settings for survey activation.
Keys:
anonymized: Whether the survey is anonymized.
datestamp: Whether the survey records dates.
ipaddr: Whether the survey records IP addresses.
ipanonymize: Whether the survey anonymizes IP addresses.
refurl: Whether the survey records referrer URLs.
savetimings: Whether the survey saves response timings.
"""

anonymized: bool
datestamp: bool
ipaddr: bool
ipanonymize: bool
refurl: bool
savetimings: bool
10 changes: 6 additions & 4 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ class MockSession(Session):
"restrictToLanguages": "en fr es",
}

def __init__(self, *args: t.Any, **kwargs: t.Any) -> None:
"""Create a mock session."""

def rpc(self, method: str, *params: t.Any) -> dict[str, t.Any]:
"""Process a mock RPC call."""
return {"method": method, "params": [*params]}
Expand Down Expand Up @@ -197,7 +194,12 @@ def client() -> t.Generator[Client, None, None]:

def test_activate_survey(client: MockClient):
"""Test activate_survey client method."""
assert_client_session_call(client, "activate_survey", 1)
assert_client_session_call(
client,
"activate_survey",
1,
user_activation_settings=None,
)


def test_activate_tokens(client: MockClient):
Expand Down
47 changes: 46 additions & 1 deletion tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def test_copy_survey_destination_id(
pytest.mark.xfail(
server_version < semver.VersionInfo.parse("6.4.0-dev"),
reason=(
"The destination_survey_id parameter is only supported in LimeSurvey "
"The destination_survey_id parameter is not supported in LimeSurvey "
f"{server_version} < 6.4.0"
),
),
Expand Down Expand Up @@ -348,6 +348,51 @@ def test_activate_survey(client: citric.Client, survey_id: int):
assert properties_after["active"] == "Y"


@pytest.mark.integration_test
def test_activate_survey_with_settings(
request: pytest.FixtureRequest,
client: citric.Client,
server_version: semver.VersionInfo,
survey_id: int,
):
"""Test whether the survey gets activated with the requested settings."""
min_version = (5, 6, 44) if server_version < (6, 0) else (6, 3, 5)
request.applymarker(
pytest.mark.xfail(
server_version < min_version,
reason=(
"The user_activation_settings parameter is not supported in LimeSurvey "
f"{server_version} < {'.'.join(str(v) for v in min_version)}"
),
),
)

properties_before = client.get_survey_properties(
survey_id,
["active", "anonymized", "ipaddr"],
)
assert properties_before["active"] == "N"
assert properties_before["anonymized"] == "N"
assert properties_before["ipaddr"] == "I"

result = client.activate_survey(
survey_id,
user_activation_settings={
"anonymized": True,
"ipaddr": False,
},
)
assert result["status"] == "OK"

properties_after = client.get_survey_properties(
survey_id,
["active", "anonymized", "ipaddr"],
)
assert properties_after["active"] == "Y"
assert properties_after["anonymized"] == "Y"

Check failure on line 392 in tests/test_integration.py

View workflow job for this annotation

GitHub Actions / integration 3.12 / 5-apache / postgres

test_activate_survey_with_settings AssertionError: assert 'N' == 'Y' - Y + N

Check failure on line 392 in tests/test_integration.py

View workflow job for this annotation

GitHub Actions / integration 3.12 / 5.6.44-231107-apache / postgres

test_activate_survey_with_settings AssertionError: assert 'N' == 'Y' - Y + N

Check failure on line 392 in tests/test_integration.py

View workflow job for this annotation

GitHub Actions / integration 3.12 / 5-apache / mysql

test_activate_survey_with_settings AssertionError: assert 'N' == 'Y' - Y + N

Check failure on line 392 in tests/test_integration.py

View workflow job for this annotation

GitHub Actions / integration 3.12 / refs/heads/develop / postgres

test_activate_survey_with_settings AssertionError: assert 'N' == 'Y' - Y + N
assert properties_after["ipaddr"] == "N"


@pytest.mark.integration_test
def test_activate_tokens(client: citric.Client, survey_id: int):
"""Test whether the participants table gets activated."""
Expand Down

0 comments on commit 400020c

Please sign in to comment.