From 49ea46ae568ea7059e9ee2a2f431f826b1c0698d Mon Sep 17 00:00:00 2001 From: Diogo Lemos Date: Thu, 9 Apr 2020 16:10:51 +0100 Subject: [PATCH 1/3] fix authentication logic --- bggcli/ui/loginpage.py | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/bggcli/ui/loginpage.py b/bggcli/ui/loginpage.py index 73aea55..5b5203d 100644 --- a/bggcli/ui/loginpage.py +++ b/bggcli/ui/loginpage.py @@ -5,7 +5,6 @@ Selenium Page Object to bind the login page and perform authentication """ -#import urllib2 try: from urllib.parse import quote except: @@ -36,9 +35,9 @@ def authenticate(self, login, password): Logger.info(" (already logged) [done]", append=True) return True - self.update_text(self.driver.find_element_by_id("login_username"), login) - self.update_text(self.driver.find_element_by_id("login_password"), password) - self.driver.find_element_by_xpath("//div[@class='menu_login']//input[@type='submit']")\ + self.update_text(self.driver.find_element_by_id("username"), login) + self.update_text(self.driver.find_element_by_id("password"), password) + self.driver.find_element_by_xpath("//*[@class='forum_table']//input[@type='Submit']") \ .click() if self.is_authenticated(login): @@ -51,22 +50,18 @@ def authenticate(self, login, password): def is_authenticated(self, login): try: - self.driver.find_element_by_xpath("//div[@class='menu_login']//a[@href='/user/%s']" - % quote(login)) + self.driver.find_element_by_xpath("//*[contains(@class, 'dropdown-menu')]//a[lowercase(@href)='/user/%s']" + % quote(login.lower())) + return True except NoSuchElementException: - # try: # BGG 2018 style when on a boardgame page. - # # - # self.driver.find_element_by_xpath("//button[@login-required]") - # return False - # except NoSuchElementException: - # return True - try: # BGG 2018, when on a boardgame page. - # - self.driver.find_element_by_xpath("//span[@class='hidden-md hidden-lg' and contains(text(),'{}')]".format(quote(login))) + try: + # Admin access is only shown for logged in users + self.driver.find_element_by_xpath("//*[contains(@show-access, 'admin_login')]") + return True except NoSuchElementException: return False # 'span[starts-with(@ng-show,"colltoolbarctrl.collection.items.length") and contains(text(),"In Collection")]' - + From b26769847affff0b804f2751910df5804bf98c68 Mon Sep 17 00:00:00 2001 From: Diogo Lemos Date: Thu, 9 Apr 2020 16:12:48 +0100 Subject: [PATCH 2/3] fix wishlist,own,wanttobuy,wanttoplay --- bggcli/__init__.py | 22 ++++++------- bggcli/ui/gamepage.py | 76 ++++++++++++++++++++++++------------------- 2 files changed, 53 insertions(+), 45 deletions(-) diff --git a/bggcli/__init__.py b/bggcli/__init__.py index 30f8a80..ad977fa 100644 --- a/bggcli/__init__.py +++ b/bggcli/__init__.py @@ -13,14 +13,14 @@ "changed and bggcli must be updated, or the site is down for " \ "maintenance." -BGG_SUPPORTED_FIELDS = ['objectname', 'objectid', 'rating', 'own', - 'fortrade', 'want', 'wanttobuy', 'wanttoplay', 'prevowned', - 'preordered', 'wishlist', 'wishlistpriority', 'wishlistcomment', - 'comment', 'conditiontext', 'haspartslist', 'wantpartslist', - 'publisherid', 'imageid', 'year', 'language', 'other', 'pricepaid', - 'pp_currency', 'currvalue', 'cv_currency', 'acquisitiondate', - 'acquiredfrom', 'quantity', 'privatecomment', - '_versionid'] +# BGG_SUPPORTED_FIELDS = ['objectname', 'objectid', 'rating', 'own', +# 'fortrade', 'want', 'wanttobuy', 'wanttoplay', 'prevowned', +# 'preordered', 'wishlist', 'wishlistpriority', 'wishlistcomment', +# 'comment', 'conditiontext', 'haspartslist', 'wantpartslist', +# 'publisherid', 'imageid', 'year', 'language', 'other', 'pricepaid', +# 'pp_currency', 'currvalue', 'cv_currency', 'acquisitiondate', +# 'acquiredfrom', 'quantity', 'privatecomment', +# '_versionid'] BGG_SUPPORTED_FIELDS = ['own', 'want', 'wanttobuy', 'wanttoplay', 'prevowned', @@ -28,15 +28,15 @@ 'fortrade', 'conditiontext', # these must be in this order 'wishlist', 'wishlistpriority', 'wishlistcomment', # these must be in this order 'comment', 'rating', - 'pricepaid', 'currvalue', + 'pricepaid', 'currvalue', 'acquisitiondate', 'acquiredfrom', 'quantity', 'privatecomment', 'haspartslist', 'wantpartslist','publisherid', 'imageid', 'year', 'language', 'other', #'cv_currency', 'pp_currency', - 'objectname', + 'objectname', 'objectid', '_versionid', 'invlocation' ] - + # More fields in the add/edit collection dialog: # Inventory Date # Inventory Location diff --git a/bggcli/ui/gamepage.py b/bggcli/ui/gamepage.py index d00ba73..7df8c48 100644 --- a/bggcli/ui/gamepage.py +++ b/bggcli/ui/gamepage.py @@ -1,7 +1,6 @@ #!/usr/local/bin/python # -*- coding: utf-8 -*- -# Updated for BGG 2018 """ bgg.gamepage ~~~~~~~~~~~~ @@ -20,12 +19,14 @@ from bggcli.ui import BasePage from bggcli.util.logger import Logger import traceback + + def in_private_info_popup(func): """ Ensure the Private Info popup is displayed when updating its attributes """ # Not verified for BGG 2018 - + def _wrapper(self, *args, **kwargs): try: self.itemEl \ @@ -97,14 +98,14 @@ def goto(self, game_attrs): # Verified BGG 2018 def update(self, game_attrs): #Logger.info("update()", append=True, break_line=True) - + # First, see if objectid exists. id = game_attrs.get('objectid',None) - + # if objectid doesn't exist, find it via the name: # this doesn't work at the moment. All the work is done in updateid() if id is None: - pass + pass return self.updateid(game_attrs) def notincollection(self): @@ -116,7 +117,7 @@ def notincollection(self): return button1 except NoSuchElementException: return False - + def openeditform(self): button = self.notincollection() if button: @@ -139,14 +140,14 @@ def openeditform(self): ) Logger.info("Click. ", append=True, break_line=False) button.click() - + clickable = self.driver.find_element_by_xpath( '//span[@class="collection-dropdown-item-edit" and //button[contains(text(),"Edit")]]') Logger.info("Click col'n dropdown. ", append=True, break_line=False) clickable.click() - + Logger.info("form...", append=True, break_line=False) - + self.itemEl = self.wait.until(EC.element_to_be_clickable( (By.XPATH, "//div[@class='modal-content']"))) @@ -157,9 +158,9 @@ def updateid(self, game_attrs): :param game_attrs: Game attributes as a dictionary """ - # General use of Selenium is + # General use of Selenium is # A) goto page, - # B) find element using xpath expression, then + # B) find element using xpath expression, then # C) take action related to the element. # # Flow of this function is: @@ -176,22 +177,22 @@ def updateid(self, game_attrs): # means that to set wishlistpriority, then # wishlist must equal 1. # 6) Finally, find the form element and submit it. - - + + #Logger.info("updateid()", append=True, break_line=True) #Logger.info("{} {}, ".format(game_attrs.get('objectid',''),game_attrs.get('objectname','')), append=True, break_line=True) - + self.goto(game_attrs) - + Logger.info("page, ", append=False, break_line=False) - + self.openeditform() - + # Open advanced data entry panel. # Advanced (private info, parts exchange) Logger.info("Advanced button...", append=True, break_line=False) self.wait.until(EC.element_to_be_clickable( - (By.XPATH, + (By.XPATH, "//a[starts-with(@class,'toggler-caret') and starts-with(@ng-click,'editctrl.showvars.showAdvanced')]" ))) try: @@ -206,7 +207,7 @@ def updateid(self, game_attrs): # Customize Game Info (title, image) Logger.info("Custom button...", append=True, break_line=False) self.wait.until(EC.element_to_be_clickable( - (By.XPATH, + (By.XPATH, "//a[starts-with(@class,'toggler-caret') and starts-with(@ng-click,'editctrl.showvars.showCustom')]" ))) try: @@ -217,29 +218,34 @@ def updateid(self, game_attrs): # custom = self.wait.until(EC.element_to_be_clickable( # (By.XPATH, ".//a[starts-with(@ng-click,'editctrl.showvars.showCustom')]"))) # custom.click() - + # Logger.info("Name field...", append=True, break_line=False) nickname = self.wait.until(EC.element_to_be_clickable( (By.XPATH, './/input[@ng-model="editctrl.editdata.item.textfield.customname.value"]'))) - + # self.itemEl = self.wait.until(EC.element_to_be_clickable( # (By.XPATH, "//form[@name='collectioneditorform']"))) # Fill all provided values using dynamic invocations 'fill_[fieldname]' dependencies = { + 'wishlist': {'wishlist': 1}, 'wishlistpriority':{'wishlist':1}, 'wishlistcomment':{'wishlist':1}, - 'conditiontext':{'fortrade':1} + 'conditiontext':{'fortrade':1}, + 'wanttoplay':{'wanttoplay': 1}, + 'wanttobuy': {'wanttobuy': 1}, + 'own': {'own': 1}, } # 'fortrade', 'conditiontext', # these must be in this order # 'wishlist', 'wishlistpriority', 'wishlistcomment', # these must be in this order - + Logger.info("Updating fields: ", append=True, break_line=False) try: for key in BGG_SUPPORTED_FIELDS: dontdo = 0 + if key in game_attrs: value = game_attrs[key] if value is not None: @@ -252,9 +258,11 @@ def updateid(self, game_attrs): #print '{}={}?'.format(k,v), if str(game_attrs[k]) != str(v): dontdo = 1 - if dontdo: - continue - getattr(self, "fill_%s" % key)(value) + if dontdo: + continue + + getattr(self, "fill_%s" % key)(value) + except: Logger.info("\nEXCEPTION.", append=True, break_line=True) traceback.print_exc() @@ -264,7 +272,7 @@ def updateid(self, game_attrs): Logger.info("Form? ", append=True, break_line=False) form = self.itemEl.find_element_by_xpath(".//form[@name='collectioneditorform']") # action=selenium.interactions.Actions(driver); - # import selenium.webdriver.common.actions.pointer_actions + # import selenium.webdriver.common.actions.pointer_actions # selenium.webdriver.common.actions.pointer_actions().click(savebutton) #Logger.info("submitting, ", append=True, break_line=False) form.submit() ; @@ -289,7 +297,7 @@ def updateid(self, game_attrs): else: self.wait.until(EC.element_to_be_clickable( (By.XPATH, ".//td[@class='collection_versionmod editfield']"))) - + return True # Not verified BGG 2018 @@ -307,10 +315,10 @@ def delete(self, game_attrs): Logger.info(" (not in collection)", append=True, break_line=False) return # Not in collection self.openeditform() - + more = self.driver.find_element_by_xpath("//button[@uib-tooltip='More options']'") more.click() - + # del_button = self.driver.find_element_by_xpath('//button[ng-click="editctrl.deleteItem(editctrl.editdata.item)"]') del_button.click() @@ -346,7 +354,7 @@ def hover (self,element): #element = wd.find_element_by_link_text(self.locator) hov = ActionChains(self.driver).move_to_element(element) hov.perform() - + # Verified BGG 2018 def fill_rating(self, value): # hover over a star, then the input box will appear. Then fill the box @@ -356,11 +364,11 @@ def fill_rating(self, value): star.location_once_scrolled_into_view self.hover(star) # - + # self.update_text(self.wait.until( EC.element_to_be_clickable((By.XPATH, '//input[@ng-model="editctrl.editdata.item.rating"]'))), value) - + # td = self.driver.find_element_by_xpath("//td[contains(@id, 'CEcell_rating')]") # td.click() @@ -470,7 +478,7 @@ def fill_year(self, value): #@in_version_popup def fill_language(self, value): # - + self.update_select(self.itemEl.find_element_by_xpath('//select[@ng-model="editctrl.editdata.item.languageid"]'), value, by_text=True) From 3176cafe5e79cd9b0202af1424ee149c7cfbd397 Mon Sep 17 00:00:00 2001 From: Diogo Lemos Date: Thu, 9 Apr 2020 17:21:55 +0100 Subject: [PATCH 3/3] Fix pypi version --- README.rst | 6 +++--- bggcli/version.py | 2 +- setup.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index fe55763..9c5989d 100644 --- a/README.rst +++ b/README.rst @@ -35,11 +35,11 @@ Warning: Installation ============ -Python 3.6 is required. +Python 3.6 or 3.7 is required. :: - pip install bggcli[2018] + pip install bggcli2018 Usage @@ -142,4 +142,4 @@ Links Final note (by Sylvain Francois) ========== -Does it really deserve such a development? Probably not, but my second goal was to discover the Python ecosystem! \ No newline at end of file +Does it really deserve such a development? Probably not, but my second goal was to discover the Python ecosystem! diff --git a/bggcli/version.py b/bggcli/version.py index c073460..a57ff2b 100644 --- a/bggcli/version.py +++ b/bggcli/version.py @@ -1 +1 @@ -VERSION = '1.-' +VERSION = '1.1' diff --git a/setup.py b/setup.py index b0945e2..a0cf856 100644 --- a/setup.py +++ b/setup.py @@ -23,14 +23,14 @@ def run_tests(self): author='Greg Smith , Sylvain Francois ', author_email='ecomputerd@yahoo.com', classifiers=[ - "Development Status :: 4 - Beta", + "Development Status :: 5 - Beta", "Environment :: Console", "Intended Audience :: End Users/Desktop", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", - "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", "Topic :: Games/Entertainment :: Board Games" ], cmdclass={'test': PyTest}, @@ -45,7 +45,7 @@ def run_tests(self): keywords='bgg boardgamegeek', license='MIT', long_description=long_description, - name='bggcli[2018]', + name='bggcli2018', packages=find_packages(), py_modules=['bggcli'], tests_require=["pytest"],