Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

288 строки
8.5 KiB

  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. """
  5. Boot session from cache or build
  6. Session bootstraps info needed by common client side activities including
  7. permission, homepage, default variables, system defaults etc
  8. """
  9. import frappe, json
  10. from frappe import _
  11. import frappe.utils
  12. from frappe.utils import cint
  13. import frappe.model.meta
  14. import frappe.defaults
  15. import frappe.translate
  16. @frappe.whitelist()
  17. def clear(user=None):
  18. frappe.local.session_obj.update(force=True)
  19. frappe.local.db.commit()
  20. clear_cache(frappe.session.user)
  21. frappe.response['message'] = "Cache Cleared"
  22. def clear_cache(user=None):
  23. cache = frappe.cache()
  24. frappe.model.meta.clear_cache()
  25. cache.delete_value(["app_hooks", "installed_apps", "app_modules", "module_apps", "home_page",
  26. "time_zone"])
  27. def delete_user_cache(user):
  28. for key in ("bootinfo", "lang", "roles", "restrictions"):
  29. cache.delete_value(key + ":" + user)
  30. def clear_notifications(user=None):
  31. if frappe.flags.in_install_app!="frappe":
  32. if user:
  33. frappe.db.sql("""delete from `tabNotification Count` where owner=%s""", (user,))
  34. else:
  35. frappe.db.sql("""delete from `tabNotification Count`""")
  36. if user:
  37. delete_user_cache(user)
  38. clear_notifications(user)
  39. if frappe.session:
  40. if user==frappe.session.user and frappe.session.sid:
  41. cache.delete_value("session:" + frappe.session.sid)
  42. else:
  43. for sid in frappe.db.sql_list("""select sid from tabSessions
  44. where user=%s""", (user,)):
  45. cache.delete_value("session:" + sid)
  46. frappe.defaults.clear_cache(user)
  47. else:
  48. for sess in frappe.db.sql("""select user, sid from tabSessions""", as_dict=1):
  49. delete_user_cache(sess.user)
  50. cache.delete_value("session:" + sess.sid)
  51. clear_notifications()
  52. frappe.defaults.clear_cache()
  53. def clear_sessions(user=None, keep_current=False):
  54. if not user:
  55. user = frappe.session.user
  56. for sid in frappe.db.sql("""select sid from tabSessions where user=%s""", (user,)):
  57. if keep_current and frappe.session.sid==sid[0]:
  58. continue
  59. else:
  60. frappe.cache().delete_value("session:" + sid[0])
  61. frappe.db.sql("""delete from tabSessions where sid=%s""", (sid[0],))
  62. def get():
  63. """get session boot info"""
  64. from frappe.core.doctype.notification_count.notification_count import \
  65. get_notification_info_for_boot, get_notifications
  66. from frappe.boot import get_bootinfo, get_startup_js
  67. bootinfo = None
  68. if not getattr(frappe.conf,'disable_session_cache', None):
  69. # check if cache exists
  70. bootinfo = frappe.cache().get_value('bootinfo:' + frappe.session.user)
  71. if bootinfo:
  72. bootinfo['from_cache'] = 1
  73. bootinfo["user"]["recent"] = json.dumps(frappe.cache().get_value("recent:" + frappe.session.user))
  74. bootinfo["notification_info"].update(get_notifications())
  75. if not bootinfo:
  76. if not frappe.cache().get_stats():
  77. frappe.msgprint(_("memcached is not working / stopped. Please start memcached for best results."))
  78. # if not create it
  79. bootinfo = get_bootinfo()
  80. bootinfo["notification_info"] = get_notification_info_for_boot()
  81. frappe.cache().set_value('bootinfo:' + frappe.session.user, bootinfo)
  82. bootinfo["metadata_version"] = frappe.cache().get_value("metadata_version")
  83. if not bootinfo["metadata_version"]:
  84. bootinfo["metadata_version"] = frappe.reset_metadata_version()
  85. bootinfo["startup_js"] = get_startup_js()
  86. for hook in frappe.get_hooks("extend_bootinfo"):
  87. frappe.get_attr(hook)(bootinfo=bootinfo)
  88. return bootinfo
  89. class Session:
  90. def __init__(self, user, resume=False):
  91. self.sid = frappe.form_dict.get('sid') or frappe.request.cookies.get('sid', 'Guest')
  92. self.user = user
  93. self.data = frappe._dict({'data': frappe._dict({})})
  94. self.time_diff = None
  95. if resume:
  96. self.resume()
  97. else:
  98. self.start()
  99. # set local session
  100. frappe.local.session = self.data
  101. def start(self):
  102. """start a new session"""
  103. # generate sid
  104. if self.user=='Guest':
  105. sid = 'Guest'
  106. else:
  107. sid = frappe.generate_hash()
  108. self.data['user'] = self.user
  109. self.data['sid'] = sid
  110. self.data['data']['user'] = self.user
  111. self.data['data']['session_ip'] = frappe.get_request_header('REMOTE_ADDR')
  112. if self.user != "Guest":
  113. self.data['data']['last_updated'] = frappe.utils.now()
  114. self.data['data']['session_expiry'] = self.get_expiry_period()
  115. self.data['data']['session_country'] = get_geo_ip_country(frappe.get_request_header('REMOTE_ADDR'))
  116. # insert session
  117. if self.user!="Guest":
  118. frappe.db.begin()
  119. self.insert_session_record()
  120. # update user
  121. frappe.db.sql("""UPDATE tabUser SET last_login = %s, last_ip = %s
  122. where name=%s""", (frappe.utils.now(), frappe.get_request_header('REMOTE_ADDR'), self.data['user']))
  123. frappe.db.commit()
  124. def insert_session_record(self):
  125. frappe.db.sql("""insert into tabSessions
  126. (sessiondata, user, lastupdate, sid, status)
  127. values (%s , %s, NOW(), %s, 'Active')""",
  128. (str(self.data['data']), self.data['user'], self.data['sid']))
  129. # also add to memcache
  130. frappe.cache().set_value("session:" + self.data.sid, self.data)
  131. def resume(self):
  132. """non-login request: load a session"""
  133. import frappe
  134. data = self.get_session_record()
  135. if data:
  136. # set language
  137. self.data = frappe._dict({'data': data, 'user':data.user, 'sid': self.sid})
  138. else:
  139. self.start_as_guest()
  140. frappe.local.lang = frappe.translate.get_user_lang(self.data.user)
  141. def get_session_record(self):
  142. """get session record, or return the standard Guest Record"""
  143. from frappe.auth import clear_cookies
  144. r = self.get_session_data()
  145. if not r:
  146. frappe.response["session_expired"] = 1
  147. clear_cookies()
  148. self.sid = "Guest"
  149. r = self.get_session_data()
  150. return r
  151. def get_session_data(self):
  152. if self.sid=="Guest":
  153. return frappe._dict({"user":"Guest"})
  154. data = self.get_session_data_from_cache()
  155. if not data:
  156. data = self.get_session_data_from_db()
  157. return data
  158. def get_session_data_from_cache(self):
  159. data = frappe._dict(frappe.cache().get_value("session:" + self.sid) or {})
  160. if data:
  161. session_data = data.get("data", {})
  162. self.time_diff = frappe.utils.time_diff_in_seconds(frappe.utils.now(),
  163. session_data.get("last_updated"))
  164. expiry = self.get_expiry_in_seconds(session_data.get("session_expiry"))
  165. if self.time_diff > expiry:
  166. self.delete_session()
  167. data = None
  168. return data and data.data
  169. def get_session_data_from_db(self):
  170. rec = frappe.db.sql("""select user, sessiondata
  171. from tabSessions where sid=%s and
  172. TIMEDIFF(NOW(), lastupdate) < TIME(%s)""", (self.sid,
  173. self.get_expiry_period()))
  174. if rec:
  175. data = frappe._dict(eval(rec and rec[0][1] or '{}'))
  176. data.user = rec[0][0]
  177. else:
  178. self.delete_session()
  179. data = None
  180. return data
  181. def get_expiry_in_seconds(self, expiry):
  182. if not expiry: return 3600
  183. parts = expiry.split(":")
  184. return (cint(parts[0]) * 3600) + (cint(parts[1]) * 60) + cint(parts[2])
  185. def delete_session(self):
  186. frappe.cache().delete_value("session:" + self.sid)
  187. frappe.db.sql("""delete from tabSessions where sid=%s""", (self.sid,))
  188. def start_as_guest(self):
  189. """all guests share the same 'Guest' session"""
  190. self.user = "Guest"
  191. self.start()
  192. def update(self, force=False):
  193. """extend session expiry"""
  194. self.data['data']['last_updated'] = frappe.utils.now()
  195. self.data['data']['lang'] = unicode(frappe.lang)
  196. # update session in db
  197. time_diff = None
  198. last_updated = frappe.cache().get_value("last_db_session_update:" + self.sid)
  199. if last_updated:
  200. time_diff = frappe.utils.time_diff_in_seconds(frappe.utils.now(),
  201. last_updated)
  202. if force or (frappe.session['user'] != 'Guest' and \
  203. ((time_diff==None) or (time_diff > 1800))):
  204. # database persistence is secondary, don't update it too often
  205. frappe.db.sql("""update tabSessions set sessiondata=%s,
  206. lastupdate=NOW() where sid=%s""" , (str(self.data['data']),
  207. self.data['sid']))
  208. if frappe.form_dict.cmd not in ("frappe.sessions.clear", "logout"):
  209. frappe.cache().set_value("last_db_session_update:" + self.sid,
  210. frappe.utils.now())
  211. frappe.cache().set_value("session:" + self.sid, self.data)
  212. def get_expiry_period(self):
  213. exp_sec = frappe.defaults.get_global_default("session_expiry") or "06:00:00"
  214. # incase seconds is missing
  215. if exp_sec:
  216. if len(exp_sec.split(':')) == 2:
  217. exp_sec = exp_sec + ':00'
  218. else:
  219. exp_sec = "2:00:00"
  220. return exp_sec
  221. def get_geo_ip_country(ip_addr):
  222. try:
  223. import pygeoip
  224. except ImportError:
  225. return
  226. import os
  227. try:
  228. geo_ip_file = os.path.join(os.path.dirname(frappe.__file__), "data", "GeoIP.dat")
  229. geo_ip = pygeoip.GeoIP(geo_ip_file, pygeoip.MEMORY_CACHE)
  230. return geo_ip.country_name_by_addr(ip_addr)
  231. except Exception:
  232. return