Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic fixes for version 2020 #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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!
Does it really deserve such a development? Probably not, but my second goal was to discover the Python ecosystem!
22 changes: 11 additions & 11 deletions bggcli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,30 @@
"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',
'preordered',
'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
Expand Down
76 changes: 42 additions & 34 deletions bggcli/ui/gamepage.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/local/bin/python
# -*- coding: utf-8 -*-

# Updated for BGG 2018
"""
bgg.gamepage
~~~~~~~~~~~~
Expand All @@ -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 \
Expand Down Expand Up @@ -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):
Expand All @@ -116,7 +117,7 @@ def notincollection(self):
return button1
except NoSuchElementException:
return False

def openeditform(self):
button = self.notincollection()
if button:
Expand All @@ -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']")))

Expand All @@ -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:
Expand All @@ -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.
#<a class="toggler-caret" ng-href="" ng-click="editctrl.showvars.showAdvanced = !editctrl.showvars.showAdvanced" ng-class="{ 'is-active': editctrl.showvars.showAdvanced }"> <span class="glyphicon glyphicon-menu-right"></span> <strong>Advanced</strong> (private info, parts exchange) </a>
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:
Expand All @@ -206,7 +207,7 @@ def updateid(self, game_attrs):
#<a class="toggler-caret" ng-href="" ng-click="editctrl.showvars.showCustom = !editctrl.showvars.showCustom" ng-class="{ 'is-active': editctrl.showvars.showCustom }"> <span class="glyphicon glyphicon-menu-right"></span> <strong>Customize Game Info</strong> (title, image) </a>
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:
Expand All @@ -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()

#<input ng-model="editctrl.editdata.item.textfield.customname.value" class="form-control ng-pristine ng-valid ng-empty ng-touched" type="text" placeholder="Gloomhaven Nickname" style="">
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:
Expand All @@ -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()
Expand All @@ -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() ;
Expand All @@ -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
Expand All @@ -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()

#<button type="button" class="btn btn-empty" ng-click="editctrl.deleteItem(editctrl.editdata.item)"> Delete from Collection </button>
del_button = self.driver.find_element_by_xpath('//button[ng-click="editctrl.deleteItem(editctrl.editdata.item)"]')
del_button.click()
Expand Down Expand Up @@ -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
Expand All @@ -356,11 +364,11 @@ def fill_rating(self, value):
star.location_once_scrolled_into_view
self.hover(star)
#<input type="text" class="form-control input-sm rating-stars-textbox ng-empty has-rating-border- ng-touched" ng-model="editctrl.editdata.item.rating" ng-show="editctrl.editdata.item.rating || overstar != null" value="" style="">

#<input type="text" class="form-control input-sm rating-stars-textbox has-rating-border- ng-touched" ng-model="editctrl.editdata.item.rating" ng-show="editctrl.editdata.item.rating || overstar != null" value="" style="">
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()

Expand Down Expand Up @@ -470,7 +478,7 @@ def fill_year(self, value):
#@in_version_popup
def fill_language(self, value):
#<select class="form-control ng-pristine ng-valid ng-empty ng-touched" ng-model="editctrl.editdata.item.languageid" ng-options="lang.languageid as lang.name for lang in editctrl.editdata.config.languages" style=""><option value="" selected="selected"></option><option label="Afrikaans" value="string:2677">Afrikaans</option><option label="Arabic" value="string:2178">Arabic</option><option label="Azerbaijani" value="string:2785">Azerbaijani</option><option label="Basque" value="string:2711">Basque</option><option label="Bengali" value="string:2787">Bengali</option><option label="Bulgarian" value="string:2675">Bulgarian</option><option label="Catalan" value="string:2179">Catalan</option><option label="Chinese" value="string:2181">Chinese</option><option label="Croatian" value="string:2656">Croatian</option><option label="Czech" value="string:2180">Czech</option><option label="Danish" value="string:2182">Danish</option><option label="Dutch" value="string:2183">Dutch</option><option label="English" value="string:2184">English</option><option label="Esperanto" value="string:2712">Esperanto</option><option label="Estonian" value="string:2185">Estonian</option><option label="Filipino" value="string:2759">Filipino</option><option label="Finnish" value="string:2186">Finnish</option><option label="French" value="string:2187">French</option><option label="Galician" value="string:2740">Galician</option><option label="German" value="string:2188">German</option><option label="Greek" value="string:2189">Greek</option><option label="Hebrew" value="string:2190">Hebrew</option><option label="Hindi" value="string:2666">Hindi</option><option label="Hungarian" value="string:2191">Hungarian</option><option label="Icelandic" value="string:2347">Icelandic</option><option label="Indonesian" value="string:2192">Indonesian</option><option label="Iranian" value="string:2696">Iranian</option><option label="Italian" value="string:2193">Italian</option><option label="Japanese" value="string:2194">Japanese</option><option label="Korean" value="string:2195">Korean</option><option label="Latin" value="string:2752">Latin</option><option label="Latvian" value="string:2196">Latvian</option><option label="Lithuanian" value="string:2197">Lithuanian</option><option label="Luxembourgish" value="string:2750">Luxembourgish</option><option label="Malay" value="string:2714">Malay</option><option label="(neutral)" value="string:2205">(neutral)</option><option label="Norwegian" value="string:2198">Norwegian</option><option label="Persian" value="string:2756">Persian</option><option label="Polish" value="string:2199">Polish</option><option label="Portuguese" value="string:2200">Portuguese</option><option label="Romanian" value="string:2201">Romanian</option><option label="Russian" value="string:2202">Russian</option><option label="Serbian" value="string:2681">Serbian</option><option label="Slovak" value="string:2206">Slovak</option><option label="Slovenian" value="string:2207">Slovenian</option><option label="Spanish" value="string:2203">Spanish</option><option label="Swedish" value="string:2204">Swedish</option><option label="Thai" value="string:2709">Thai</option><option label="Turkish" value="string:2349">Turkish</option><option label="Ukrainian" value="string:2665">Ukrainian</option><option label="Vietnamese" value="string:2738">Vietnamese</option><option label="Welsh" value="string:2653">Welsh</option></select>

self.update_select(self.itemEl.find_element_by_xpath('//select[@ng-model="editctrl.editdata.item.languageid"]'), value,
by_text=True)

Expand Down
27 changes: 11 additions & 16 deletions bggcli/ui/loginpage.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
Selenium Page Object to bind the login page and perform authentication

"""
#import urllib2
try:
from urllib.parse import quote
except:
Expand Down Expand Up @@ -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):
Expand All @@ -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.
# #<button class="btn btn-sm" type="button" login-required="">Sign In</button>
# self.driver.find_element_by_xpath("//button[@login-required]")
# return False
# except NoSuchElementException:
# return True
try: # BGG 2018, when on a boardgame page.
#<span class="hidden-md hidden-lg"> MSGreg </span>
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")]'

2 changes: 1 addition & 1 deletion bggcli/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION = '1.-'
VERSION = '1.1'
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ def run_tests(self):
author='Greg Smith <ecomputerd@yahoo.com>, Sylvain Francois <syllant@gmail.com>',
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},
Expand All @@ -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"],
Expand Down