c11_admin.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import base64
  2. import os
  3. # import time
  4. import requests
  5. from requests_toolbelt.multipart import decoder
  6. # import pandas as pd
  7. import jinja2
  8. import json
  9. import re
  10. from bs4 import BeautifulSoup
  11. class ca_webscraper:
  12. webservice = "http://localhost:9300/bi/"
  13. templates_dir = "C:/GlobalCube/Tasks/gctools/templates"
  14. export_dir = "C:/GlobalCube/ReportOutput"
  15. log_dir = "C:/GlobalCube/Tasks/gctools/logs"
  16. credentials = '{"parameters":[{"name":"CAMNamespace","value":"CognosEx"},{"name":"h_CAM_action","value":"logonAs"},{"name":"CAMUsername","value":"Global1"},{"name":"CAMPassword","value":"Cognos#11"}]}'
  17. headers = {}
  18. caf = ""
  19. cam = ""
  20. def __init__(self):
  21. self._env = jinja2.Environment(
  22. loader=jinja2.FileSystemLoader(self.templates_dir),
  23. autoescape=jinja2.select_autoescape(['html', 'xml'])
  24. )
  25. self.template = self._env.get_template('get_report.xml')
  26. def generate_token(self, message_base64):
  27. version = "V1".encode("utf-8")
  28. header_len = 4
  29. msg = base64.b64decode(message_base64)[1:]
  30. chunks = []
  31. while len(msg) >= header_len:
  32. chunk_len = int.from_bytes(msg[:header_len], byteorder="little")
  33. msg = msg[header_len:]
  34. chunks.append(msg[:chunk_len])
  35. msg = msg[chunk_len:]
  36. return base64.b64encode(version + chunks[-1]).decode("utf-8")
  37. def login(self):
  38. self.session = requests.Session()
  39. r = self.session.get(self.webservice)
  40. self.headers = {'Content-Type': "application/json; charset=UTF-8", 'X-XSRF-TOKEN': self.session.cookies.get('XSRF-TOKEN')}
  41. r = self.session.post(self.webservice + "v1/login", data=self.credentials, headers=self.headers)
  42. self.caf = r.json()['cafContextId']
  43. self.cam = self.generate_token(r.cookies["usersessionid"])
  44. return r.status_code
  45. def report_list(self):
  46. # "v1/objects/_dot_public_folders/items"
  47. filter = "type|analysis|interactiveReport|powerPlayReport|powerPlay8Report|powerPlay8ReportView|query|report|reportTemplate"
  48. res = self.session.get(
  49. self.webservice + "v1/search/cm?fields=defaultName|id|ancestors&results=1000&query=.&hide_internal=all&filter=" + filter,
  50. headers=self.headers
  51. )
  52. # print(res.content)
  53. filename = self.log_dir + '/reports_error.log'
  54. os.makedirs(os.path.dirname(filename), exist_ok=True)
  55. with open(filename, "wb") as f:
  56. f.write(res.content)
  57. self.reports = res.json()['results']
  58. for r in self.reports:
  59. r['path'] = "/".join([a['defaultName'].replace('/', '_') for a in r['ancestors']])
  60. r['name'] = r['defaultName']
  61. del(r['ancestors'])
  62. del(r['defaultName'])
  63. filename = self.log_dir + '/config/reports.json'
  64. os.makedirs(os.path.dirname(filename), exist_ok=True)
  65. json.dump(self.reports, open(filename, 'w'), indent=2)
  66. return self.reports
  67. def export_folder(self, folder):
  68. reports = [r for r in self.reports if r['path'].startswith(folder)]
  69. for r in reports:
  70. print(r['name'])
  71. # continue
  72. path = r['path'].replace(folder, '')
  73. r['filename'] = f"{path}/{r['name']}.pdf"
  74. r['params'] = list(re.findall(r'\[([^\]]+)\]', r['filename']))
  75. for i, p in enumerate(r['params']):
  76. r['filename'] = r['filename'].replace('[' + p + ']', '{' + str(i) + '}')
  77. self.export(r, 'PDF')
  78. def export(self, report, format='XML'):
  79. headers = {
  80. 'Content-Type': 'text/xml; charset=UTF-8',
  81. 'X-XSRF-TOKEN': self.headers['X-XSRF-TOKEN'],
  82. 'X-RsCMStoreID': report['id'],
  83. 'X-UseRsConsumerMode': 'true',
  84. 'SOAPAction': 'http://www.ibm.com/xmlns/prod/cognos/reportService/202004/'
  85. }
  86. soap = self.template.render({"caf": self.caf, "cam": self.cam,
  87. "report": report, "format": 'XHTML',
  88. "prompt": 'true', "tracking": "", "params": {}})
  89. r = self.session.post(self.webservice + 'v1/reports', data=soap, headers=headers)
  90. parts = decoder.MultipartDecoder.from_response(r).parts
  91. # for i, p in enumerate(parts):
  92. # with open(f"export/{report['report']}_{i}.xml", "w") as f:
  93. # f.write(p.text.replace('\x81', ''))
  94. meta = {'required': {}, 'optional': {}}
  95. bs = BeautifulSoup(parts[1].content, 'lxml')
  96. # print(bs.prettify())
  97. for sv in bs.find_all('selectvalue'):
  98. k = sv['parameter']
  99. req = 'required' if sv['required'] == 'true' else 'optional'
  100. v = dict([(opt['usevalue'], opt['displayvalue']) for opt in sv.find_all('selectoption')])
  101. meta[req][k] = v
  102. # <selectValue specname="selectValue" parameter="p_Auswahl_Monate" range="false" required="false" hideAdornments="false" multiSelect="true" prePopulateIfParentOptional="false" selectValueUI="checkboxGroup" rowsPerPage="5000" autoSubmit="false" name="_P3591935746" style="width:100%" columnName="Alle Autoh�user" roid="i9241">
  103. # <selectChoices>
  104. # <selectOption useValue="letzte 13 Monate" displayValue="letzte 13 Monate"/>
  105. # </selectChoices>
  106. # <selectOptions>
  107. # <selectOption useValue="letzte 13 Monate" displayValue="letzte 13 Monate"/>
  108. # </selectOptions>
  109. # </selectValue>
  110. filename = self.log_dir + f"/config/{report['name']}.json"
  111. os.makedirs(os.path.dirname(filename), exist_ok=True)
  112. json.dump(meta, open(filename, 'w'), indent=2)
  113. if format == 'PDF':
  114. return self.export_pdf(report, meta)
  115. payload = json.dumps({'reportspec_stubbed': parts[2].text, 'storeid': report['id']})
  116. token = re.findall(r'<bus:authenticityToken xsi:type="xs:base64Binary">(.*)</bus:authenticityToken>', parts[0].text)[0]
  117. headers = {
  118. 'Content-Type': 'application/json; charset=UTF-8',
  119. 'X-XSRF-TOKEN': self.session.cookies.get('XSRF-TOKEN'),
  120. 'authenticityToken': token,
  121. 'X-UseRsConsumerMode': 'true',
  122. 'cafContextId': self.caf
  123. }
  124. r = self.session.post(self.webservice + 'v1/reports/unstubreport', data=payload, headers=headers)
  125. unstubbed = json.loads(r.content.decode('latin-1'))['reportspec_full']
  126. unstubbed = re.sub(r' iid="[^"]*"', '', unstubbed).replace('\x9f', '').replace('\x96', '')
  127. bs = BeautifulSoup(unstubbed, 'xml')
  128. for xa in bs.find_all('XMLAttributes'):
  129. xa.decompose()
  130. filename = self.export_dir + f"unstubbed/{report['name']}.xml"
  131. os.makedirs(os.path.dirname(filename), exist_ok=True)
  132. with open(filename, "w") as f:
  133. f.write(bs.prettify())
  134. return soap
  135. def export_pdf(self, report, meta):
  136. headers = {
  137. 'Content-Type': 'text/xml; charset=UTF-8',
  138. 'X-XSRF-TOKEN': self.headers['X-XSRF-TOKEN'],
  139. 'X-RsCMStoreID': report['id'],
  140. 'X-UseRsConsumerMode': 'true',
  141. 'SOAPAction': 'http://www.ibm.com/xmlns/prod/cognos/reportService/202004/'
  142. }
  143. if len(report['params']) == 0:
  144. params = {}
  145. filename = report['filename']
  146. self.request_file(report, headers, params, filename)
  147. return True
  148. if len(report['params']) == 1:
  149. params = {}
  150. filename = report['filename'].format('0')
  151. self.request_file(report, headers, params, filename)
  152. key1 = report['params'][0]
  153. for k1, v1 in meta['optional'][key1].items():
  154. filename = report['filename'].format(v1)
  155. params = {key1: {k1: v1}}
  156. self.request_file(report, headers, params, filename)
  157. return True
  158. if len(report['params']) == 2:
  159. key1, key2 = report['params']
  160. for k1, v1 in meta['optional'][key1].items():
  161. for k2, v2 in meta['optional'][key2].items():
  162. filename = report['filename'].format(v1, v2)
  163. params = {key1: {k1: v1}, key2: {k2: v2}}
  164. self.request_file(report, headers, params, filename)
  165. return True
  166. def request_file(self, report, headers, params, filename):
  167. soap = self.template.render({"caf": self.caf, "cam": self.cam,
  168. "report": report, "format": 'PDF',
  169. "prompt": 'false', "tracking": "", "params": params}).encode("utf-8")
  170. try:
  171. r = self.session.post(self.webservice + 'v1/reports', data=soap, headers=headers)
  172. except UnicodeEncodeError:
  173. filename = self.log_dir + '/' + os.path.basename(filename) + '.log'
  174. os.makedirs(os.path.dirname(filename), exist_ok=True)
  175. with open(filename, "w") as f:
  176. f.write(soap)
  177. return False
  178. if r.status_code == 200:
  179. parts = decoder.MultipartDecoder.from_response(r).parts
  180. filename = self.export_dir + filename
  181. os.makedirs(os.path.dirname(filename), exist_ok=True)
  182. with open(filename, "wb") as f:
  183. f.write(parts[1].content)
  184. else:
  185. filename = self.log_dir + '/' + os.path.basename(filename) + '.log'
  186. os.makedirs(os.path.dirname(filename), exist_ok=True)
  187. with open(filename, "wb") as f:
  188. f.write(r.content)
  189. return True
  190. def admin(self):
  191. r = self.session.get(self.webservice + "v1/disp?m_p_owner=&changed_m_p_owner=0&changed_genprop=0&so.select=&so.return.m=portal%2Fproperties_general.xts&so.defaultLocation=&so.defaultObject=&ro_name=false&origDefLang=de&m_email=&m_defaultName=&m_t_default_name_de=CARLO_F_Belege&m_t_default_description_de=&m_t_default_screenTip_de=&ifrmcmd=save&m_p_disabled=false&m_p_hidden=false&icon_radio=standard&m_transloc=de&pty_activeLang=de&pty_deactivLang=&pty_del=&pty_add=&pty_name=CARLO_F_Belege&pty_scrt=&pty_desc=&m_new_class=&b_action=xts.run&sharedPagesChanged=&from_tool=true&backURL=%2Fbi%2Fv1%2Fdisp%3Fb_action%3Dxts.run%26m%3Dportal%2Flegacy_tools%2Ftools_directory.xts%26m_pathID%3Di339AF66BADEC411E943590402582B75B%26m_path%3DCAMID%28%2522%253a%2522%29%252fdataSource%255b%2540name%253d%2527CARLO_F_Belege%2527%255d%26tool_tab%3Dd&m_selectedPage=&m_classSubtype=&m_obj=CAMID%28%22%3A%22%29%2FdataSource%5B%40name%3D%27CARLO_F_Belege%27%5D%2FdataSourceConnection%5B%40name%3D%27CARLO_F_Belege%27%5D&b_report_type=&encoding=UTF-8&m=portal%2Fproperties_connection.xts&m_class=dataSourceConnection&m_name=CARLO_F_Belege&ui.cafcontextid=CAFW000000a0Q0FGQTYwMDAwMDAwMDlBaFFBQUFERWpZV1g4bEExbmlJd29ualF1cEgwWVVTeGtnY0FBQUJUU0VFdE1qVTJJQUFBQUxha3gqeHQ5TXN3Ukw2dGhjMTJVRzN1NVhaMWVzNU5FLXRvWXI1VzlwYTE0NDI0NzN8cHM_&m_path=CAMID%28%22%3A%22%29%2FdataSource%5B%40name%3D%27CARLO_F_Belege%27%5D&cmd=&m_location=&reportLocation=&ps_nav_op=maintain&ps_nav_stack=&ps_nav_source=portal%2Fproperties_general.xts")
  192. print(r.cookies.keys())
  193. # CRN=http%3A%2F%2Fdeveloper.cognos.com%2Fceba%2Fconstants%2FbiDirectionalOptionEnum%23biDirectionalFeaturesEnabled%3Dfalse%26http%3A%2F%2Fdeveloper.cognos.com%2Fceba%2Fconstants%2FsystemOptionEnum%23accessibilityFeatures%3Dfalse%26skin%3Dcorporate%26contentLocale%3Dde-de%26showHiddenObjects%3Dfalse%26showWelcomePage%3Dtrue%26backgroundSessionLogging%3D1970-01-01%2B00%253A00%253A00%26showOptionSummary%3Dtrue%26productLocale%3Dde%26listViewSeparator%3Dnone%26showHints%3DhideAll%26timeZoneID%3DEurope%252FBerlin%26linesPerPage%3D15%26displayMode%3Dlist%26automaticPageRefresh%3D30%26format%3DHTML%26columnsPerPage%3D3%26;
  194. # cea-ssa=false;
  195. # userCapabilities=f%3Bfdbffc6d%3Bf07c1faf%3Bff27defa%26AwcAAABTSEEtMjU2FAAAAMSNhZfyUDWeIjCieNC6kfRhRLGSDPui1gb2UKZPMWVW5x3QHrHM%2BIVk5gFTzsNq1oOMioU%3D;
  196. # userCapabilitiesEx=603%3Bf%3Bfdbffc6d%3Bf07c1faf%3Bff27defa%26AhQAAADEjYWX8lA1niIwonjQupH0YUSxkgcAAABTSEEtMjU2IAAAAMI%2BRz7opwjhYGXonwHJpD3Ya1agg0lFOa1JK%2FkZiDTS;
  197. # caf=CAFW000000e0Q0FGQTYwMDAwMDAwM2FBaFFBQUFERWpZV1g4bEExbmlJd29ualF1cEgwWVVTeGtnY0FBQUJUU0VFdE1qVTJJQUFBQUY3d3JJLW1zREhXcnQtT0VWLUhhKjF0c01TZFVrWlB0aXNYdEVJOUcqZm40NDI0NzN8MTAxOjc5ZTJiNDdhLTIyNjgtZDcxYS1jMGIxLWYwMDYyY2QxYWQwZTozNDAxNTQ5MzI1;
  198. # cc_session=s_cc:|s_conf:na|s_sch:td|s_hd:sa|s_serv:na|s_disp:na|s_set:|s_dep:na|s_dir:na|s_sms:dd|s_ct:sa|s_cs:sa|s_so:sa|e_hp:CAMID(*22CognosEx*3au*3auid*3dglobal1*22)|e_proot:Team*20Content|prootid:i1F610DE4196544319A27C5709282EF95|e_mroot:Eigene*20Ordner|mrootid:iBAA3C16EC2D743B7B221BBFCDBC625D7|e_mrootpath:CAMID(*22CognosEx*3au*3auid*3dglobal1*22)*2ffolder*5b*40name*3d*27Eigene*20Ordner*27*5d|e_user:Global*20Cube|e_tenantID:|e_tenantDisplayName:|e_showTenantInfo:false|e_isSysAdmin:true|e_isTenantAdmin:false|e_isImpersonating:false|cl:de-de|dcid:i1F610DE4196544319A27C5709282EF95|show_logon:false|uig:|ui:|rsuiprofile:all|lch:f|lca:f|ci:f|write:true|eom:0|pp:3401549325;
  199. # up=H4sIAAAAAAAAAFWQ204CMRCGX4X0GuIuF5rlDgXEBBQUgxIT0sOwW2k7mx4UNL67sxgRk0ma+Tr5+nc+WdQWVujgZsB6bJg81vBydgneaMfaLGzp6LFHF8E7qCw0cIPe8kh4vJhOqBdcbkuPyakHCEGjm2BZalfSRF5cZJ0sp2plWe9QjbXC97F2MdBEpRX0jSGaAvhbboHgtUHBTU4w7usGcCnJHwlUaGHGywZSR7x5Umij434EPCYPZN1wE6DNdOg7dHuL6Y/VHlWScYKSm0ai4BhIKXB34hVkPFEomtnNu4UTtvi4fyrP1aLO+XJerLq7t2c7CtP5ek0Kae0MfeTmJ5jQA+3JRNvg5jfY0HFhQB3lCjY8mfjv062rJJpIEmnn7jRn5xBV8AAL2MWjnu76KSL7+gaz/bFgzAEAAA==;
  200. # MRUStorage=%7B%22xQ29nbm9zRXg6dTp1aWQ9Z2xvYmFsMQ__%22%3Atrue%7D;
  201. # usersessionid=AggAAADOAvteAAAAAAoAAAAPMXuCsi7eLj2GFAAAAMSNhZfyUDWeIjCieNC6kfRhRLGSBwAAAFNIQS0yNTYgAAAAxhTjzCpYnRF3ryJ/z/gpU9G5UeFYyp1vKc/PjuCT/r4=;
  202. # cam_passport=MTsxMDE6NzllMmI0N2EtMjI2OC1kNzFhLWMwYjEtZjAwNjJjZDFhZDBlOjM0MDE1NDkzMjU7MDszOzA7
  203. if __name__ == '__main__':
  204. caws = ca_webscraper()
  205. caws.login()
  206. caws.report_list()
  207. caws.export_folder('Team Content/ReportOutput')