-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: add interface, write more tests
- Loading branch information
Showing
9 changed files
with
159 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from ckan import model | ||
from ckan.plugins.interfaces import Interface | ||
|
||
|
||
class ILetMeIn(Interface): | ||
"""Interface to do something on user login via OTL link""" | ||
|
||
def manage_user(self, user: model.User) -> model.User: | ||
"""Accept a user object that will be logged. Only Active user could be | ||
logged in, so here we could implement user re-activation, for example. | ||
The user is always exists, otherwise we are not getting here. | ||
This happend before we are checking for user state and actual login | ||
Must return a user object | ||
""" | ||
return user | ||
|
||
def before_otl_login(self, user: model.User) -> None: | ||
"""Allows to do something before we are logging in a user. | ||
Happens after all checks and `manage_user` method.""" | ||
pass | ||
|
||
def after_otl_login(self, user: model.User) -> None: | ||
"""Allows to do something after we logged in a user.""" | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,22 @@ | ||
import ckan.model as model | ||
import ckan.plugins as p | ||
import ckan.plugins.toolkit as tk | ||
|
||
import ckanext.let_me_in.utils as lmi_utils | ||
from ckanext.let_me_in.interfaces import ILetMeIn | ||
|
||
|
||
@tk.blanket.actions | ||
@tk.blanket.cli | ||
@tk.blanket.auth_functions | ||
@tk.blanket.blueprints | ||
@tk.blanket.validators | ||
class LetMeInPlugin(p.SingletonPlugin): | ||
pass | ||
p.implements(ILetMeIn, inherit=True) | ||
|
||
# ILetMeIn | ||
|
||
def after_otl_login(self, user: model.User) -> None: | ||
lmi_utils.update_user_last_active(user) | ||
|
||
tk.h.flash_success("You have been logged in.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import pytest | ||
|
||
import ckan.model as model | ||
import ckan.plugins as p | ||
from ckan.tests.helpers import call_action | ||
|
||
from ckanext.let_me_in.interfaces import ILetMeIn | ||
|
||
|
||
class TestOTLPlugin(p.SingletonPlugin): | ||
p.implements(p.IConfigurable, inherit=True) | ||
p.implements(ILetMeIn) | ||
|
||
def configure(self, _config): | ||
self.manage_user_call = 0 | ||
self.before_otl_login_call = 0 | ||
self.after_otl_login_call = 0 | ||
|
||
def manage_user(self, user: model.User) -> model.User: | ||
self.manage_user_call += 1 | ||
|
||
return user | ||
|
||
def before_otl_login(self, user: model.User) -> None: | ||
self.before_otl_login_call += 1 | ||
|
||
def after_otl_login(self, user: model.User) -> None: | ||
self.after_otl_login_call += 1 | ||
|
||
|
||
@pytest.mark.ckan_config("ckan.plugins", "let_me_in test_otl_plugin") | ||
@pytest.mark.usefixtures("non_clean_db", "with_plugins") | ||
class TestOTLInterace(object): | ||
def test_xxx(self, app, user, sysadmin): | ||
result = call_action("lmi_generate_otl", uid=user["id"]) | ||
|
||
result = app.get(result["url"], status=200) | ||
|
||
manage_user_call_total = sum( | ||
plugin.manage_user_call | ||
for plugin in p.PluginImplementations(ILetMeIn) | ||
if plugin.name == "test_otl_plugin" | ||
) | ||
|
||
before_otl_login_call_total = sum( | ||
plugin.before_otl_login_call | ||
for plugin in p.PluginImplementations(ILetMeIn) | ||
if plugin.name == "test_otl_plugin" | ||
) | ||
|
||
after_otl_login_call_total = sum( | ||
plugin.after_otl_login_call | ||
for plugin in p.PluginImplementations(ILetMeIn) | ||
if plugin.name == "test_otl_plugin" | ||
) | ||
|
||
assert manage_user_call_total == 1 | ||
assert before_otl_login_call_total == 1 | ||
assert after_otl_login_call_total == 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
from __future__ import annotations | ||
|
||
from typing import cast | ||
|
||
import pytest | ||
|
||
import ckan.model as model | ||
from ckan.tests.helpers import call_action | ||
|
||
|
||
@pytest.mark.usefixtures("non_clean_db") | ||
class TestOTLViews(object): | ||
def test_login_user_with_otl(self, app, user): | ||
otl = call_action("lmi_generate_otl", uid=user["id"]) | ||
|
||
result = app.get(otl["url"], status=200) | ||
assert "You have been logged in" in result.text | ||
|
||
result = app.get(otl["url"], status=200) | ||
assert ( | ||
"You have tried to use a one-time login link that has expired" | ||
in result.text | ||
) | ||
|
||
def test_user_login_expires_the_otl(self, app, user): | ||
"""We are not creating any entity for OTL. It expires right after the | ||
user it was created for is logged in. This triggers the update of | ||
`last_active` field and if the OTL is older than this, it will be invalidated""" | ||
otl = call_action("lmi_generate_otl", uid=user["id"]) | ||
|
||
user = cast(model.User, model.User.get(user["id"])) | ||
user.set_user_last_active() | ||
|
||
result = app.get(otl["url"], status=200) | ||
assert ( | ||
"You have tried to use a one-time login link that has expired" | ||
in result.text | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters