Fix LOGGER -> _LOGGER typo
[sitecorepy.git] / sitecore / __init__.py
1 #!/usr/bin/env python
2 # Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
3 #
4 # This file is part of SiteCorePy.
5 #
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.
10 #
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.
15 #
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/>.
18
19 """A Python_ interface to SiteCore_ via WebDriver_.
20
21 Because I like my wrists too much to enter data by hand.
22
23 Note that WebDriver is currently being merged into Selenium_.
24
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/
29 """
30
31 import getpass
32 import logging
33 import time
34
35 try:
36     from selenium.firefox.webdriver import WebDriver
37 except ImportError, e:
38     WebDriver = e  # allow some functionality without selenium
39
40
41 _LOGGER = None
42
43 def get_logger(verbose=0):
44     global _LOGGER
45     if _LOGGER != None:
46         return _LOGGER
47     verbosities = [  # in order of decreasing severity
48         logging.CRITICAL,
49         logging.ERROR,
50         logging.WARN,
51         logging.INFO,
52         logging.DEBUG,
53         ]
54     logger = logging.getLogger('sitecore')
55     if verbose >= len(verbosities):
56         verbose = -1
57     logger.setLevel(verbosities[verbose])
58     # create console handler and set the same level
59     ch = logging.StreamHandler()
60     ch.setLevel(verbosities[verbose])
61     # create formatter
62     formatter = logging.Formatter(
63         '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
64     # add formatter to ch
65     ch.setFormatter(formatter)
66     # add ch to logger
67     logger.addHandler(ch)
68     _LOGGER = logger
69     return logger
70
71
72 class SiteCoreConnection (object):
73     def __init__(self, url, verbose=0):
74         if isinstance(WebDriver, ImportError):
75             raise WebDriver  # *now* require sitecore
76         self.url = url
77         self.logger = get_logger(verbose)
78         self.wait_time = 5
79
80     def start(self):
81         'Start a single Firefox instance'
82         self.logger.info('starting Firefox')
83         self.w = WebDriver()
84         self.w.get(self.url)
85
86     def stop(self):
87         'Stop the Firefox instance'
88         self.logger.info('stopping Firefox')
89         self.w.quit()
90
91     def login(self, username=None, password=None):
92         if username == None:
93             username = getpass.getpass('username: ')
94         if password == None:
95             password = getpass.getpass('password: ')
96         self.logger.info('logging in as %s' % username)
97         uname = self.w.find_element_by_id('Login_UserName')
98         uname.send_keys(username)
99         pword = self.w.find_element_by_id('Login_Password')
100         pword.send_keys(password)
101         submit = self.w.find_element_by_id('Login_Login')
102         submit.click()
103         del(username)
104         del(password)
105
106         time.sleep(self.wait_time)
107
108     def find_nav_section(self, section):
109         self.logger.info('finding nav section %s' % section)
110         nav_bar = self.w.find_element_by_xpath("//tr[@id='ContentTreeHolder']")
111         link = nav_bar.find_element_by_link_text(section)
112         link_id = link.get_attribute('id')
113         img_id = link_id.replace('_Node_', '_Glyph_')
114         img = nav_bar.find_element_by_id(img_id)
115         div = nav_bar.find_element_by_xpath("//img[@id='%s']/.." % img_id)
116         return (div, img, link)
117
118     def expand_nav_section(self, section):
119         div,img,link = self.find_nav_section(section)
120         src = img.get_attribute('src')
121         if 'collapse' in src:
122             self.logger.info('nav section %s already expanded' % section)
123             return  # already expanded, no further action needed.
124             self.logger.info('nav section %s already expanded' % section)
125         assert 'expand' in src, src
126         self.logger.info('expanding nav section %s' % section)
127         img.click()
128         time.sleep(self.wait_time)
129
130     def open_nav_section(self, section):
131         div,img,link = self.find_nav_section(section)
132         self.logger.info('opening nav section %s' % section)
133         link.click()
134         time.sleep(self.wait_time)
135
136     def lock_section(self):
137         self.w.find_element_by_link_text('Lock and Edit').click()
138         time.sleep(self.wait_time)
139
140     def save_section(self):
141         self.logger.info('saving current section')
142         self.w.find_element_by_id('Ribbon_Nav_HomeStrip').click()
143         time.sleep(self.wait_time)
144         self.w.find_element_by_link_text('Save').click()
145         time.sleep(self.wait_time)
146
147     def publish_section(self, message):
148         self.save_section()
149         self.logger.info('publishing current section')
150         self.w.find_element_by_link_text('Review').click()
151         time.sleep(self.wait_time)
152         self.w.find_element_by_link_text('Approve for publication').click()
153         time.sleep(self.wait_time)
154         windows = self.w.get_window_handles()
155         current_window = self.w.get_current_window_handle()
156         self.logger.info('handling popup %s (from %s)'
157                          % (current_window, windows))
158         #self.w.switch_to_window(name)
159         a = self.w.switch_to_active_element()
160         a.send_keys(message+'\n')
161
162     def find_field(self, field_regexp, name=None):
163         self.logger.info('finding %s field' % name)
164         # found id start by manually focusing in the element and running
165         #   >>> a = s.w.switch_to_active_element()
166         #   >>> a.get_attribute('id')
167         # FIELD*, but the number * changes between sessions/versions
168         fields = []
169         for tag in ['input', 'textarea', 'iframe']:
170             fields.extend([f for f in self.w.find_elements_by_tag_name(tag)
171                            if f.get_attribute('id').startswith('FIELD')])
172         match = False
173         for f in fields:
174             granddad = f.find_element_by_xpath('/../..')
175             if field_regexp.match(granddad.get_text()) != None:
176                 match = True
177                 break
178         if match != True:
179             raise KeyError(name)
180         return (granddad, f)