Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

327 řádky
8.6 KiB

  1. import webnotes
  2. form = webnotes.form
  3. session = webnotes.session
  4. sql = webnotes.conn.sql
  5. out = webnotes.response
  6. from webnotes.utils import cint
  7. # Get, scrub metadata
  8. # ====================================================================
  9. def get_sql_tables(q):
  10. if q.find('WHERE') != -1:
  11. tl = q.split('FROM')[1].split('WHERE')[0].split(',')
  12. elif q.find('GROUP BY') != -1:
  13. tl = q.split('FROM')[1].split('GROUP BY')[0].split(',')
  14. else:
  15. tl = q.split('FROM')[1].split('ORDER BY')[0].split(',')
  16. return [t.strip().strip('`')[3:] for t in tl]
  17. def get_parent_dt(dt):
  18. pdt = ''
  19. if sql('select name from `tabDocType` where istable=1 and name="%s"' % dt):
  20. import webnotes.model.meta
  21. return webnotes.model.meta.get_parent_dt(dt)
  22. return pdt
  23. def get_sql_meta(tl):
  24. std_columns = {
  25. 'owner':('Owner', '', '', '100'),
  26. 'creation':('Created on', 'Date', '', '100'),
  27. 'modified':('Last modified on', 'Date', '', '100'),
  28. 'modified_by':('Modified By', '', '', '100')
  29. }
  30. meta = {}
  31. for dt in tl:
  32. meta[dt] = std_columns.copy()
  33. # for table doctype, the ID is the parent id
  34. pdt = get_parent_dt(dt)
  35. if pdt:
  36. meta[dt]['parent'] = ('ID', 'Link', pdt, '200')
  37. # get the field properties from DocField
  38. res = sql("select fieldname, label, fieldtype, options, width from tabDocField where parent='%s'" % dt)
  39. for r in res:
  40. if r[0]:
  41. meta[dt][r[0]] = (r[1], r[2], r[3], r[4]);
  42. # name
  43. meta[dt]['name'] = ('ID', 'Link', dt, '200')
  44. return meta
  45. # Additional conditions to fulfill match permission rules
  46. # ====================================================================
  47. def getmatchcondition(dt, ud, ur):
  48. res = sql("SELECT `role`, `match` FROM tabDocPerm WHERE parent = '%s' AND (`read`=1) AND permlevel = 0" % dt)
  49. cond = []
  50. for r in res:
  51. if r[0] in ur: # role applicable to user
  52. if r[1]:
  53. defvalues = ud.get(r[1],['_NA'])
  54. for d in defvalues:
  55. cond.append('`tab%s`.`%s`="%s"' % (dt, r[1], d))
  56. else: # nomatch i.e. full read rights
  57. return ''
  58. return ' OR '.join(cond)
  59. def add_match_conditions(q, tl, ur, ud):
  60. sl = []
  61. for dt in tl:
  62. s = getmatchcondition(dt, ud, ur)
  63. if s:
  64. sl.append(s)
  65. # insert the conditions
  66. if sl:
  67. condition_st = q.find('WHERE')!=-1 and ' AND ' or ' WHERE '
  68. condition_end = q.find('ORDER BY')!=-1 and 'ORDER BY' or 'LIMIT'
  69. condition_end = q.find('GROUP BY')!=-1 and 'GROUP BY' or condition_end
  70. if q.find('ORDER BY')!=-1 or q.find('LIMIT')!=-1 or q.find('GROUP BY')!=-1: # if query continues beyond conditions
  71. q = q.split(condition_end)
  72. q = q[0] + condition_st + '(' + ' OR '.join(sl) + ') ' + condition_end + q[1]
  73. else:
  74. q = q + condition_st + '(' + ' OR '.join(sl) + ')'
  75. return q
  76. # execute server-side script from Search Criteria
  77. # ====================================================================
  78. def exec_report(code, res, colnames=[], colwidths=[], coltypes=[], coloptions=[], filter_values={}, query='', from_export=0):
  79. col_idx, i, out, style, header_html, footer_html, page_template = {}, 0, None, [], '', '', ''
  80. for c in colnames:
  81. col_idx[c] = i
  82. i+=1
  83. # load globals (api)
  84. from webnotes import *
  85. from webnotes.utils import *
  86. from webnotes.model.doc import *
  87. from webnotes.model.doclist import getlist
  88. from webnotes.model.db_schema import updatedb
  89. from webnotes.model.code import get_obj
  90. set = webnotes.conn.set
  91. sql = webnotes.conn.sql
  92. get_value = webnotes.conn.get_value
  93. convert_to_lists = webnotes.conn.convert_to_lists
  94. NEWLINE = '\n'
  95. exec str(code)
  96. if out!=None:
  97. res = out
  98. return res, style, header_html, footer_html, page_template
  99. # ====================================================================
  100. def guess_type(m):
  101. """
  102. Returns fieldtype depending on the MySQLdb Description
  103. """
  104. import MySQLdb
  105. if m in MySQLdb.NUMBER:
  106. return 'Currency'
  107. elif m in MySQLdb.DATE:
  108. return 'Date'
  109. else:
  110. return 'Data'
  111. def build_description_simple():
  112. colnames, coltypes, coloptions, colwidths = [], [], [], []
  113. for m in webnotes.conn.get_description():
  114. colnames.append(m[0])
  115. coltypes.append(guess_type[m[0]])
  116. coloptions.append('')
  117. colwidths.append('100')
  118. return colnames, coltypes, coloptions, colwidths
  119. # ====================================================================
  120. def build_description_standard(meta, tl):
  121. desc = webnotes.conn.get_description()
  122. colnames, coltypes, coloptions, colwidths = [], [], [], []
  123. # merged metadata - used if we are unable to
  124. # get both the table name and field name from
  125. # the description - in case of joins
  126. merged_meta = {}
  127. for d in meta:
  128. merged_meta.update(meta[d])
  129. for f in desc:
  130. fn, dt = f[0], ''
  131. if '.' in fn:
  132. dt, fn = fn.split('.')
  133. if (not dt) and merged_meta.get(fn):
  134. # no "AS" given, find type from merged description
  135. desc = merged_meta[fn]
  136. colnames.append(desc[0] or fn)
  137. coltypes.append(desc[1] or '')
  138. coloptions.append(desc[2] or '')
  139. colwidths.append(desc[3] or '100')
  140. elif meta.get(dt,{}).has_key(fn):
  141. # type specified for a multi-table join
  142. # usually from Report Builder
  143. desc = meta[dt][fn]
  144. colnames.append(desc[0] or fn)
  145. coltypes.append(desc[1] or '')
  146. coloptions.append(desc[2] or '')
  147. colwidths.append(desc[3] or '100')
  148. else:
  149. # nothing found
  150. # guess
  151. colnames.append(fn)
  152. coltypes.append(guess_type(f[1]))
  153. coloptions.append('')
  154. colwidths.append('100')
  155. return colnames, coltypes, coloptions, colwidths
  156. # Entry Point - Run the query
  157. # ====================================================================
  158. @webnotes.whitelist(allow_guest=True)
  159. def runquery(q='', ret=0, from_export=0):
  160. import webnotes.utils
  161. formatted = cint(form.getvalue('formatted'))
  162. # CASE A: Simple Query
  163. # --------------------
  164. if form.getvalue('simple_query') or form.getvalue('is_simple'):
  165. if not q: q = form.getvalue('simple_query') or form.getvalue('query')
  166. if q.split()[0].lower() != 'select':
  167. raise Exception, 'Query must be a SELECT'
  168. as_dict = cint(form.getvalue('as_dict'))
  169. res = sql(q, as_dict = as_dict, as_list = not as_dict, formatted=formatted)
  170. # build colnames etc from metadata
  171. colnames, coltypes, coloptions, colwidths = [], [], [], []
  172. # CASE B: Standard Query
  173. # -----------------------
  174. else:
  175. if not q: q = form.getvalue('query')
  176. tl = get_sql_tables(q)
  177. meta = get_sql_meta(tl)
  178. q = add_match_conditions(q, tl, webnotes.user.roles, webnotes.user.get_defaults())
  179. # replace special variables
  180. q = q.replace('__user', session['user'])
  181. q = q.replace('__today', webnotes.utils.nowdate())
  182. res = sql(q, as_list=1, formatted=formatted)
  183. colnames, coltypes, coloptions, colwidths = build_description_standard(meta, tl)
  184. # run server script
  185. # -----------------
  186. style, header_html, footer_html, page_template = '', '', '', ''
  187. if form.has_key('sc_id') and form.getvalue('sc_id'):
  188. sc_id = form.getvalue('sc_id')
  189. from webnotes.model.code import get_code
  190. sc_details = webnotes.conn.sql("select module, standard, server_script from `tabSearch Criteria` where name=%s", sc_id)[0]
  191. if sc_details[1]!='No':
  192. code = get_code(sc_details[0], 'Search Criteria', sc_id, 'py')
  193. else:
  194. code = sc_details[2]
  195. if code:
  196. filter_values = form.has_key('filter_values') and eval(form.getvalue('filter_values','')) or {}
  197. res, style, header_html, footer_html, page_template = exec_report(code, res, colnames, colwidths, coltypes, coloptions, filter_values, q, from_export)
  198. out['colnames'] = colnames
  199. out['coltypes'] = coltypes
  200. out['coloptions'] = coloptions
  201. out['colwidths'] = colwidths
  202. out['header_html'] = header_html
  203. out['footer_html'] = footer_html
  204. out['page_template'] = page_template
  205. if style:
  206. out['style'] = style
  207. # just the data - return
  208. if ret==1:
  209. return res
  210. out['values'] = res
  211. # return num of entries
  212. qm = form.has_key('query_max') and form.getvalue('query_max') or ''
  213. if qm and qm.strip():
  214. if qm.split()[0].lower() != 'select':
  215. raise Exception, 'Query (Max) must be a SELECT'
  216. if not form.has_key('simple_query'):
  217. qm = add_match_conditions(qm, tl, webnotes.user.roles, webnotes.user.defaults)
  218. out['n_values'] = webnotes.utils.cint(sql(qm)[0][0])
  219. @webnotes.whitelist()
  220. def runquery_csv():
  221. global out
  222. # run query
  223. res = runquery(from_export = 1)
  224. q = form.getvalue('query')
  225. rep_name = form.getvalue('report_name')
  226. if not form.has_key('simple_query'):
  227. # Report Name
  228. if not rep_name:
  229. rep_name = get_sql_tables(q)[0]
  230. if not rep_name: rep_name = 'DataExport'
  231. # Headings
  232. heads = []
  233. rows = [[rep_name], out['colnames']] + out['values']
  234. from cStringIO import StringIO
  235. import csv
  236. f = StringIO()
  237. writer = csv.writer(f)
  238. for r in rows:
  239. for i in xrange(len(r)):
  240. if type(r[i]) is unicode:
  241. r[i] = r[i].encode('utf-8')
  242. writer.writerow(r)
  243. f.seek(0)
  244. out['result'] = f.read()
  245. out['type'] = 'csv'
  246. out['doctype'] = rep_name