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/__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)
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.
- # MSGreg
- 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")]'
-
+
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"],