2 # Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
4 # This file is part of SiteCorePy.
6 # SiteCorePy is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the
8 # Free Software Foundation, either version 2 of the License, or (at your
9 # option) any later version.
11 # SiteCorePy is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with SiteCorePy. If not, see <http://www.gnu.org/licenses/>.
19 """A Python_ interface to SiteCore_ via WebDriver_.
21 Because I like my wrists too much to enter data by hand.
23 Note that WebDriver is currently being merged into Selenium_.
25 .. _Python: http://www.python.org/
26 .. _SiteCore: http://www.sitecore.net/
27 .. _WebDriver: http://code.google.com/p/selenium/
28 .. _Selenium: http://code.google.com/p/selenium/
36 from selenium.firefox.webdriver import WebDriver
37 except ImportError, e:
38 WebDriver = e # allow some functionality without selenium
40 def get_logger(verbose=0):
41 verbosities = [ # in order of decreasing severity
48 logger = logging.getLogger('sitecore')
49 if verbose >= len(verbosities):
51 logger.setLevel(verbosities[verbose])
52 # create console handler and set the same level
53 ch = logging.StreamHandler()
54 ch.setLevel(verbosities[verbose])
56 formatter = logging.Formatter(
57 '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
59 ch.setFormatter(formatter)
65 class SiteCoreConnection (object):
66 def __init__(self, url, verbose=0):
67 if isinstance(WebDriver, ImportError):
68 raise WebDriver # *now* require sitecore
70 self.logger = get_logger(verbose)
74 'Start a single Firefox instance'
75 self.logger.info('starting Firefox')
80 'Stop the Firefox instance'
81 self.logger.info('stopping Firefox')
84 def login(self, username=None, password=None):
86 username = getpass.getpass('username: ')
88 password = getpass.getpass('password: ')
89 self.logger.info('logging in as %s' % username)
90 uname = self.w.find_element_by_id('Login_UserName')
91 uname.send_keys(username)
92 pword = self.w.find_element_by_id('Login_Password')
93 pword.send_keys(password)
94 submit = self.w.find_element_by_id('Login_Login')
99 time.sleep(self.wait_time)
101 def find_nav_section(self, section):
102 self.logger.info('finding nav section %s' % section)
103 nav_bar = self.w.find_element_by_xpath("//tr[@id='ContentTreeHolder']")
104 link = nav_bar.find_element_by_link_text(section)
105 link_id = link.get_attribute('id')
106 img_id = link_id.replace('_Node_', '_Glyph_')
107 img = nav_bar.find_element_by_id(img_id)
108 div = nav_bar.find_element_by_xpath("//img[@id='%s']/.." % img_id)
109 return (div, img, link)
111 def expand_nav_section(self, section):
112 div,img,link = self.find_nav_section(section)
113 src = img.get_attribute('src')
114 if 'collapse' in src:
115 self.logger.info('nav section %s already expanded' % section)
116 return # already expanded, no further action needed.
117 self.logger.info('nav section %s already expanded' % section)
118 assert 'expand' in src, src
119 self.logger.info('expanding nav section %s' % section)
121 time.sleep(self.wait_time)
123 def open_nav_section(self, section):
124 div,img,link = self.find_nav_section(section)
125 self.logger.info('opening nav section %s' % section)
127 time.sleep(self.wait_time)
129 def lock_section(self):
130 self.w.find_element_by_link_text('Lock and Edit').click()
131 time.sleep(self.wait_time)
133 def save_section(self):
134 self.logger.info('saving current section')
135 self.w.find_element_by_link_text('Save').click()
136 time.sleep(self.wait_time)
138 def publish_section(self, message):
140 self.logger.info('publishing current section')
141 self.w.find_element_by_link_text('Review').click()
142 time.sleep(self.wait_time)
143 self.w.find_element_by_link_text('Approve for publication').click()
144 time.sleep(self.wait_time)
145 windows = self.w.get_window_handles()
146 current_window = self.w.get_current_window_handle()
147 self.logger.info('handling popup %s (from %s)'
148 % (current_window, windows))
149 #self.w.switch_to_window(name)
150 a = self.w.switch_to_active_element()
151 a.send_keys(message+'\n')
153 def find_field(self, field):
154 self.logger.info('finding %s field' % field)
155 # found id start by manually focusing in the element and running
156 # >>> a = s.w.switch_to_active_element()
157 # >>> a.get_attribute('id')
158 # FIELD*, but the number * changes between sessions/versions
160 for tag in ['input', 'textarea']:
161 fields.extend([f for f in self.w.find_elements_by_tag_name(tag)
162 if f.get_attribute('id').startswith('FIELD')])
165 granddad = f.find_element_by_xpath('/../..')
166 if granddad.get_text() == field:
170 raise KeyError(field)