Commit 499ff32a authored by Eelco van der Wel's avatar Eelco van der Wel :speech_balloon:
Browse files

Merge branch 'revert-3bf9897c' into 'dev'

Revert "cvu with error message"

See merge request plugins/gmail!3
parents 3bf9897c 75196a00
Pipeline #3469 passed with stages
in 2 minutes and 46 seconds
Showing with 76 additions and 182 deletions
+76 -182
......@@ -10,21 +10,8 @@
layout: [
{ section: username, fields: identifier, exclude: labels }
{ section: password, fields: secret, exclude: labels }
{ section: error }
{ section: login }
]
error {
showTitle: false
HStack {
show: showError
Text {
text: "SomeError"
font: 16 semibold
color: #f00
}
}
}
login {
showTitle: false
......@@ -35,7 +22,7 @@
padding: 20 0 20 0
onPress: [
setProperty {
subject: {{.~account}}
subject: {{.view}}
property: "status"
value: "ready"
}
......@@ -59,4 +46,4 @@
}
}
}
}
}
\ No newline at end of file
......@@ -38,25 +38,11 @@ class PasswordAuthenticator:
self.pluginRun = pluginRun
self.isTest = False
def set_login_error(self, cvu_item, error_message=None):
cvu_string: str = cvu_item.definition
if error_message:
cvu_string = cvu_string.replace("show: showError", "show: true")
cvu_string = cvu_string.replace('text: "SomeError"', f'text: "{error_message}"')
cvu_string
else:
cvu_string = cvu_string.replace("show: showError", "show: false")
cvu_item.definition = cvu_string
return cvu_item
def authenticate(self, plugin):
self.request_user_credentials()
login_success = False
for tries_remaining in range(self.MAX_LOGIN_ATTEMPTS):
for _ in range(self.MAX_LOGIN_ATTEMPTS):
username, password = self.poll_credentials()
print(username, password)
try:
......@@ -66,12 +52,6 @@ class PasswordAuthenticator:
except Exception as e:
print(e)
print("Login failed, invalid credentials.")
cvu = self.pluginRun.get_edges("view")[0]
cvu = self.set_login_error(cvu, error_message=f"Invalid credentials, {tries_remaining} attempts remaining.")
self.client.update_item(cvu)
self.pluginRun.status = RUN_USER_ACTION_NEEDED
self.client.update_item(self.pluginRun)
login_success = False
if not login_success:
......@@ -81,7 +61,6 @@ class PasswordAuthenticator:
def request_user_credentials(self):
cvu = get_cvu(LOGIN_CVU)
cvu = self.set_login_error(cvu, error_message=None)
self.client.create(cvu)
self.pluginRun.add_edge("view", cvu)
self.client.create_edge(self.pluginRun.get_edges("view")[0])
......
%% Cell type:code id: tags:
```
``` python
%load_ext autoreload
%autoreload 2
# default_exp authenticator
```
%% Cell type:code id: tags:
```
``` python
# export
# hide
import abc
from time import sleep
from pathlib import Path
from pymemri.data.basic import read_file
from pymemri.plugin.states import RUN_USER_ACTION_NEEDED, RUN_USER_ACTION_COMPLETED
from pymemri.data.schema import CVUStoredDefinition
import time
import gmail_importer
```
%% Cell type:code id: tags:
```
``` python
# export
LOGIN_CVU = "passwordAuth.cvu"
CVU_BASE_PATH = Path(gmail_importer.__file__).parent.parent / "cvu"
def get_cvu(name, base_path=CVU_BASE_PATH):
path = Path(base_path) / name
cvu_str = read_file(path)
return CVUStoredDefinition(definition=cvu_str, name=name, externalId=name)
```
%% Cell type:markdown id: tags:
## Password Authenticator
Password Authenticator provides an easy interface to setup standard username-password authentication with 3rd party services.
Simply calling `authenticate()` should load the related account with required credentials.
Inheriting class should implement:
- get_token() that tests username-password combination or gets a new session token to be used for future calls
%% Cell type:code id: tags:
```
``` python
# export
# hide
class PasswordAuthenticator:
MAX_LOGIN_ATTEMPTS = 10
SLEEP_INTERVAL = 1.0
MAX_POLL_TIME = 1000
def __init__(self, client, pluginRun):
self.client = client
self.pluginRun = pluginRun
self.isTest = False
def set_login_error(self, cvu_item, error_message=None):
cvu_string: str = cvu_item.definition
if error_message:
cvu_string = cvu_string.replace("show: showError", "show: true")
cvu_string = cvu_string.replace('text: "SomeError"', f'text: "{error_message}"')
cvu_string
else:
cvu_string = cvu_string.replace("show: showError", "show: false")
cvu_item.definition = cvu_string
return cvu_item
def authenticate(self, plugin):
self.request_user_credentials()
login_success = False
for tries_remaining in range(self.MAX_LOGIN_ATTEMPTS):
for _ in range(self.MAX_LOGIN_ATTEMPTS):
username, password = self.poll_credentials()
print(username, password)
try:
plugin.login(username, password)
login_success = True
break
except Exception as e:
print(e)
print("Login failed, invalid credentials.")
cvu = self.pluginRun.get_edges("view")[0]
cvu = self.set_login_error(cvu, error_message=f"Invalid credentials, {tries_remaining} attempts remaining.")
self.client.update_item(cvu)
self.pluginRun.status = RUN_USER_ACTION_NEEDED
self.client.update_item(self.pluginRun)
login_success = False
if not login_success:
self.pluginRun.status = "error"
self.client.update_item(self.pluginRun)
raise RuntimeError("Reached max login attempts.")
def request_user_credentials(self):
cvu = get_cvu(LOGIN_CVU)
cvu = self.set_login_error(cvu, error_message=None)
self.client.create(cvu)
self.pluginRun.add_edge("view", cvu)
self.client.create_edge(self.pluginRun.get_edges("view")[0])
self.pluginRun.status = RUN_USER_ACTION_NEEDED
self.client.update_item(self.pluginRun)
def poll_credentials(self):
# request username and password from the user client
# WAIT HERE = BLOCK
start_time = time.time()
while True:
if time.time() - start_time > self.MAX_POLL_TIME:
raise RuntimeError("Stop polling, max time reached.")
print("polling for credentials...")
sleep(self.SLEEP_INTERVAL)
self.pluginRun = self.client.get(self.pluginRun.id)
if self.pluginRun.status == RUN_USER_ACTION_COMPLETED:
account = self.pluginRun.account[0]
return account.identifier, account.secret
```
%% Cell type:code id: tags:
```
``` python
from pymemri.plugin.pluginbase import PluginBase
from pymemri.plugin.schema import PluginRun, Account
from pymemri.pod.client import PodClient
import threading
class MyAuthenticatedPlugin(PluginBase):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.logged_in = False
self.authenticator = PasswordAuthenticator(kwargs["client"], kwargs["pluginRun"])
def login(self, username, password):
if not (username=="username" and password=="password"):
raise ValueError("Wrong credentials.")
def run(self):
self.authenticator.authenticate(self)
self.logged_in = True
print("done!")
def add_to_schema(self):
pass
pod_client = PodClient()
run = PluginRun("", "", "")
account = Account(service="myAuthenticatedPlugin")
run.add_edge("account", account)
run.status = "start"
pod_client.create(run)
pod_client.create(account)
pod_client.create_edge(run.get_edges("account")[0])
```
%% Output
True
%% Cell type:code id: tags:
```
``` python
# Create Plugin
plugin = MyAuthenticatedPlugin(client=pod_client, pluginRun=run)
```
%% Cell type:code id: tags:
```
``` python
# Start plugin in background thread
def run_thread():
plugin.run()
assert plugin.logged_in
thread = threading.Thread(target=run_thread)
thread.start()
```
%% Output
<Response [400]> b'Failure: Property externalId not defined in Schema (attempted to use it for json value "passwordAuth.cvu")'
<Response [404]> b'Endpoint not found'
polling for credentials...
polling for credentials...
polling for credentials...
polling for credentials...
polling for credentials...
polling for credentials...
polling for credentials...
%% Cell type:code id: tags:
```
``` python
# Enter password and check if plugin is authenticated
def simulate_enter_password(pod_client, run_id):
run = pod_client.get(run_id)
account = run.account[0]
username = "username"
password = "password"
account.identifier = username
account.secret = password
run.status = "ready"
pod_client.update_item(account)
pod_client.update_item(run)
simulate_enter_password(pod_client, run.id)
time.sleep(4)
assert plugin.logged_in
```
%% Output
username password
done!
%% Cell type:code id: tags:
```
a = "1234"
b = a.replace("4", "5")
b
```
%% Output
'1235'
%% Cell type:code id: tags:
```
run.view
```
%% Output
[CVUStoredDefinition (#c1618a8e06821e359a6ed2628e26f942),
CVUStoredDefinition (#2f180ce9b41e6ee863f17f003706280c)]
%% Cell type:code id: tags:
```
``` python
```
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment