login/logout mostly working.

master
blallo 2019-01-14 12:11:17 +01:00 committed by blallo
parent f6c55655a2
commit 23c41237ff
Signed by: blallo
GPG Key ID: 0CBE577C9B72DC3F
3 changed files with 126 additions and 72 deletions

49
LICENSE
View File

@ -1,35 +1,22 @@
GLWTS(Good Luck With That Shit) Public License
Copyright (c) Every-fucking-one, except the Author
GNU GENERAL PUBLIC LICENSE The author has absolutely no fucking clue what the code in this project does.
Version 3, 29 June 2007 It might just fucking work or not, there is no third option.
A bot to easen the daily routine with zucchetti virtual badge. Everyone is permitted to copy, distribute, modify, merge, sell, publish,
Copyleft 2019 sublicense or whatever fuck they want with this software but at their OWN RISK.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
GOOD LUCK WITH THAT SHIT PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION, AND MODIFICATION
0. You just DO WHATEVER THE FUCK YOU WANT TO as long as you NEVER LEAVE A
FUCKING TRACE TO TRACK THE AUTHOR of the original product to blame for or held
responsible.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Good luck and Godspeed.

View File

@ -3,38 +3,21 @@ Bot_Z
===== =====
.. image:: https://img.shields.io/pypi/v/bot_z.svg
:target: https://pypi.python.org/pypi/bot_z
.. image:: https://img.shields.io/travis/lbarcaroli/bot_z.svg
:target: https://travis-ci.org/lbarcaroli/bot_z
.. image:: https://readthedocs.org/projects/bot-z/badge/?version=latest
:target: https://bot-z.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
.. image:: https://pyup.io/repos/github/lbarcaroli/bot_z/shield.svg
:target: https://pyup.io/repos/github/lbarcaroli/bot_z/
:alt: Updates
A bot to easen the daily routine with zucchetti virtual badge. A bot to easen the daily routine with zucchetti virtual badge.
* Free software: GNU General Public License v3 * Free software: GLWTS public licence.
* Documentation: https://bot-z.readthedocs.io.
Features Features
-------- --------
* TODO * Login/Logout
Credits TODO
--------- ----
This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage
* Check in/out
* systemd {unit, timer}
* APIs
* ...

View File

@ -1,7 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Main module.""" """
Operator is the main object that interacts with the foreign
service. It exposes methods to login, logout and check in and out.
"""
from datetime import datetime, timedelta
import logging import logging
import os import os
import time import time
@ -15,10 +19,12 @@ from selenium.common.exceptions import WebDriverException, NoSuchElementExceptio
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=os.environ.get('BOTZ_LOGLEVEL', logging.INFO),
format='%(levelname)s: [%(name)s] -> %(message)s' format='%(levelname)s: [%(name)s] -> %(message)s'
) )
m_logger = logging.getLogger(__name__)
m_logger.debug("Init at debug")
def safely(f: T.Callable) -> T.Callable: def safely(f: T.Callable) -> T.Callable:
def _protection(self, *args, **kwargs): def _protection(self, *args, **kwargs):
@ -30,11 +36,43 @@ def safely(f: T.Callable) -> T.Callable:
return _protection return _protection
def _is_present(driver: wd.Firefox, xpath: str) -> bool:
try:
driver.find_element_by_xpath(xpath)
return True
except NoSuchElementException:
return False
def is_present(driver: wd.Firefox,
xpath: str,
timeout: T.Optional[timedelta]=None
) -> bool:
"""
Helper function. If an element is present in the DOM tree,
returns true. False otherwise.
"""
if timeout is None:
return _is_present(driver, xpath)
_now = datetime.now()
_elapsed = timedelta(seconds=0)
while _elapsed < timeout:
m_logger.debug("Not yet present: %s", xpath)
if _is_present(driver, xpath):
m_logger.debug("Present: %s", xpath)
return True
time.sleep(0.5)
_elapsed = datetime.now() - _now
return False
class Operator(wd.Firefox): class Operator(wd.Firefox):
def __init__( def __init__(
self, self,
base_uri: str, base_uri: str,
name: str = None, name: str = None,
timeout: int=20,
proxy: T.Optional[T.Tuple[str, int]] = None, proxy: T.Optional[T.Tuple[str, int]] = None,
headless: bool = True, headless: bool = True,
debug: bool = False, debug: bool = False,
@ -53,6 +91,7 @@ class Operator(wd.Firefox):
self.debug = debug self.debug = debug
self.base_uri = base_uri self.base_uri = base_uri
self.timeout = timedelta(seconds=timeout)
if proxy: if proxy:
self.profile.set_preference('network.proxy.type', 1) self.profile.set_preference('network.proxy.type', 1)
@ -72,15 +111,29 @@ class Operator(wd.Firefox):
self._checked_in = False self._checked_in = False
@safely @safely
def do_login(self, user: str, password: str) -> None: def login(self, user: str, password: str, force: bool=False) -> None:
""" """
Do the login and proceed. Do the login and proceed.
""" """
if self._logged_in:
self.logger.warning("Already logged in: %s", user)
if not force:
return
self.logger.info("Forcing login: %s", user)
# Retrieve login page # Retrieve login page
#self.get('{}/jsp/login.jsp'.format(self.base_uri))
self.get(self.base_uri) self.get(self.base_uri)
_correct_url = 'cpccchk' in self.current_url
_now = datetime.now()
_elapsed = timedelta(seconds=0)
while not _correct_url:
self.logger.debug("Not yet on login page: %s", self.current_url)
time.sleep(0.5)
_correct_url = 'cpccchk' in self.current_url
_elapsed = datetime.now() - _now
if _elapsed > self.timeout:
break
self.logger.debug("After login get: %s", self.current_url) self.logger.debug("After login get: %s", self.current_url)
time.sleep(3) time.sleep(1)
# Username # Username
user_form = self.find_element_by_name('m_cUserName') user_form = self.find_element_by_name('m_cUserName')
# Password # Password
@ -91,24 +144,51 @@ class Operator(wd.Firefox):
user_form.send_keys(user) user_form.send_keys(user)
pass_form.send_keys(password) pass_form.send_keys(password)
do_it = True do_it = True
if self.debug: if self.debug and not force:
_do_it = input("Really do the login? [y/n]").lower() _do_it = input("Really do the login? [y/n] ").lower()
do_it = True if _do_it == "y" else False do_it = True if _do_it == "y" else False
if do_it: if do_it:
self.logger.debug("Before clicking: %s", self.current_url)
login_butt.submit() login_butt.submit()
self.logger.debug("After clicking: %s", self.current_url) time.sleep(5)
self.logger.debug("Login result: %s", self.title) self.logger.debug("Login result: %s", self.title)
if 'Routine window' in self.title: if 'Routine window' in self.title:
self.logger.debug("Reloading...")
self.refresh() self.refresh()
try: self.switch_to.alert.accept()
self.find_element_by_xpath('//input[contains(@value, "Accedi")]') if is_present(self, '//a[contains(@class, "imgMenu_ctrl")]', self.timeout):
# TODO: reckon a proper timeout mechanism
# based on cookie expire time
self._logged_in = True self._logged_in = True
self.logger.info("Login success for user: %s", user) self.logger.info("Login success for user: %s", user)
except NoSuchElementException as e: else:
self.logger.error("Login failed: %s", e) self.logger.error("Login failed: %s", user)
@safely
def logout(self, user: str, force: bool=False) -> None:
"""
Do the logout.
"""
if not self._logged_in:
self.logger.warning("Not yet logged in for user: %s", user)
if not force:
return
self.logger.info("Forcing logout: %s", user)
# Find the Profile menu and open it
profile_butt = self.find_element_by_xpath('//span[contains(@id, "imgNoPhotoLabel")]')
profile_butt.click()
time.sleep(1)
# Find the logout button
logout_butt = self.find_element_by_xpath('//input[@value="Logout user"]')
logout_butt.click()
if "jsp/usut_wapplogout_portlet.jsp" in self.current_url:
self.logger.info("User successfully logged out: %s", user)
else:
self.logger.warning("Logout failed: %s", user)
def logged_in(self):
"""
Check if already logged in. Checks if page is '/jsp/home.jsp'
and if login cookie is set (and not expired).
"""
pass
@safely @safely
def check_in(self, force: bool=False) -> None: def check_in(self, force: bool=False) -> None:
@ -121,6 +201,8 @@ class Operator(wd.Firefox):
self.logger.warn("Already logged in!") self.logger.warn("Already logged in!")
if not force: if not force:
return return
enter_butt = self.find_element_by_xpath('//input[@value="Entrata"]')
enter_butt.submit()
# Click the check in button and change # Click the check in button and change
# self._checked_in state in case of success # self._checked_in state in case of success
pass pass
@ -136,9 +218,11 @@ class Operator(wd.Firefox):
self.logger.warn("Not yet logged in!") self.logger.warn("Not yet logged in!")
if not force: if not force:
return return
exit_butt = self.find_element_by_xpath('//input[@value="Uscita"]')
exit_butt.submit()
# Click the check in button and change # Click the check in button and change
# self._checked_in state in case of success # self._checked_in state in case of success
pass pass
def __del__(self): def __del__(self) -> None:
self.quit() self.quit()