PageRenderTime 29ms CodeModel.GetById 0ms RepoModel.GetById 1ms app.codeStats 0ms

/demisauce/demisauce/controllers/account.py

https://github.com/araddon/demisauce
Python | 618 lines | 611 code | 7 blank | 0 comment | 22 complexity | 1c54c408f807e084c0e590a52e044cc9 MD5 | raw file
  1. import logging
  2. import tornado
  3. import json
  4. from tornado.options import options
  5. import tornado.escape
  6. from datetime import datetime, timedelta
  7. from sqlalchemy.sql import and_, or_, not_, func, select
  8. from demisauce import model
  9. from demisauce.model import meta
  10. from demisauce.model.site import Site
  11. from demisauce.model.activity import Activity
  12. from demisauce.model.user import Person, Group, PersonValidation, \
  13. SignupForm, PersonEditValidation, InviteForm, GroupForm
  14. from demisauce.lib import QueryDict, scheduler
  15. from demisauce.model.activity import Activity, add_activity
  16. from formencode import Invalid, validators
  17. from formencode.validators import *
  18. import formencode, urllib
  19. import demisaucepy.cache_setup
  20. from demisaucepy.cache import cache
  21. from demisauce.controllers import BaseHandler, RestMixin, SecureController, \
  22. send_emails, requires_admin
  23. from gearman.task import Task
  24. log = logging.getLogger("demisauce")
  25. def google_auth_url(return_url):
  26. import urllib
  27. from gdata import auth
  28. url = urllib.urlencode({'url':return_url})
  29. next = '%s/user/googleauth?%s' % (options.base_url,url)
  30. scope = 'http://www.google.com/m8/feeds'
  31. auth_sub_url = auth.GenerateAuthSubUrl(next,scope,secure=False,session=True)
  32. return auth_sub_url
  33. def compute_userhash():
  34. if 'HTTP_USER_AGENT' in request.environ and 'REMOTE_ADDR' in request.environ:
  35. hash = request.environ['HTTP_USER_AGENT'] + request.environ['REMOTE_ADDR']
  36. import hashlib
  37. return hashlib.md5(hash + config['demisauce.apikey']).hexdigest()
  38. else:
  39. return None
  40. class PasswordChangeValidation(formencode.Schema):
  41. allow_extra_fields = True
  42. filter_extra_fields = False
  43. password = formencode.All(validators.NotEmpty())
  44. password1 = formencode.All(validators.NotEmpty(),validators.MinLength(5))
  45. password2 = formencode.All(validators.NotEmpty(),validators.MinLength(5))
  46. chained_validators = [validators.FieldsMatch('password1', 'password2')]
  47. class AccountController(RestMixin,BaseHandler):
  48. requires_auth = False
  49. def validate(self,id="0"):
  50. 'for validating'
  51. if self.user and self.user.is_authenticated:
  52. user = Person.saget(self.user.id)
  53. if isinstance(user.extra_json,(dict)) and 'wordpress_user_id' in user.extra_json:
  54. self.write(user.extra_json['wordpress_user_id'])
  55. log.debug(user.extra_json['wordpress_user_id'])
  56. self.set_status(200)
  57. else:
  58. self.set_status(403)
  59. def options(self,action="",id=""):
  60. log.debug("in Account api OPTIONS action=%s" % action)
  61. if action in ['pre_init_user','init_user']:
  62. return
  63. else:
  64. raise tornado.web.HTTPError(405)
  65. def googleauth(self,id=0):
  66. """
  67. User is coming in from google, should have an auth token
  68. """
  69. # NEED SITE???? Or does that not make sense?
  70. import gdata
  71. import gdata.contacts
  72. import gdata.contacts.service
  73. authsub_token = self.get_argument("token")
  74. log.info('calling gdata_authsubtoke = %s' % (authsub_token))
  75. #TODO: upgrade to gdata 1.2+ which breaks this
  76. gd_client = gdata.contacts.service.ContactsService()
  77. gd_client.auth_token = authsub_token
  78. gd_client.UpgradeToSessionToken()
  79. query = gdata.contacts.service.ContactsQuery()
  80. query.max_results = 2
  81. feed = gd_client.GetContactsFeed(query.ToUri())
  82. email = feed.author[0].email.text
  83. name = feed.author[0].name.text
  84. user = meta.DBSession.query(Person).filter_by(
  85. email=email.lower()).first()
  86. if not user:
  87. user = Person(site_id=1,email=email,displayname=name)
  88. user.authn = 'google'
  89. user.save()
  90. log.info('creating a google user')
  91. self.set_current_user(user,is_authenticated = True,islogon=True)
  92. expires_seconds = 60*60*24*31
  93. self.set_cookie('dsuserkey', user.user_uniqueid,expires_days=31)
  94. if 'url' in self.request.arguments:
  95. url = request.GET['url']
  96. self.redirect(str(url))
  97. self.render('/comment/comment_login.html')
  98. def index(self,id=0):
  99. if not self.user:
  100. return self.redirect('/user/signin')
  101. self.render('/user/settings.html')
  102. def inviteusers(self,id=0):
  103. self.render('/user/inviteusers.html')
  104. def inviteusers_POST(self,id=0):
  105. """
  106. admin is sending out a number of invites to users
  107. """
  108. raise Exception("not implemented")
  109. if 'emails' in self.request.arguments:
  110. emails = self.get_argument("emails")
  111. delay = 4
  112. from demisauce.lib import scheduler
  113. for email in emails.split(','):
  114. email = email.strip().lower()
  115. user = Person.by_email(self.user.site_id,email)
  116. if user is None:
  117. user = Person(site_id=c.site_id,email=email, displayname=email)
  118. user.save()
  119. #send emails
  120. url2 = urllib.quote_plus('/user/viewh/%s' % (user.hashedemail))
  121. dnew = {}
  122. dnew['link'] = '%s/user/verify?unique=%s&node=%s&return_url=%s' %\
  123. (base_url(),user.user_uniqueid,user.id,url2)
  124. dnew['from'] = self.user.displayname
  125. a = Activity(site_id=user.site_id,person_id=user.id,activity='sending email invite')
  126. a.ip = self.request.remote_ip
  127. a.ref_url = 'account admin invite'
  128. a.category = 'account'
  129. a.save()
  130. scheduler.add_interval_task(send_emails,0,('invitation_to_demisauce',[user.email],dnew) , initialdelay=delay)
  131. delay += 3
  132. return 'from form %s' % emails
  133. return 'error'
  134. def site_signup(self,id=''):
  135. if self.user:
  136. self.add_alert('Already signed in.')
  137. #redirect_wsave(action='index')
  138. elif 'invitecode' in self.request.arguments:
  139. self.user = meta.DBSession.query(Person).filter_by(
  140. user_uniqueid=self.get_argument('invitecode')).first()
  141. invitecode = self.get_argument('invitecode')
  142. form = InviteForm(QueryDict(self.request.arguments))
  143. self.render('/user/sitesignup.html',invitecode=invitecode,form=form)
  144. def site_signup_POST(self,id=0):
  145. """
  146. User is signing up
  147. """
  148. user = meta.DBSession.query(Person).filter_by(
  149. user_uniqueid=self.get_argument('invitecode').lower()).first()
  150. if user is None:
  151. self.add_error("We were not able to verify this invite, please \
  152. try again or enter your email in the top form for the waiting list.")
  153. form = InviteForm(QueryDict(self.request.arguments))
  154. if form and form.validate():
  155. user.set_password(form.password.data)
  156. user.site.name = form.sitename.data
  157. user.displayname = form.displayname.data
  158. user.verified = True
  159. user.isadmin = True
  160. user.save()
  161. model.setup_site(user)
  162. self.set_current_user(user,is_authenticated=True,islogon=True)
  163. self.add_alert('Account was created')
  164. return self.redirect('/home/index?msg=Account+was+created')
  165. else:
  166. self.add_error("errors in form")
  167. self.render('/user/sitesignup.html',form=form)
  168. def verify(self,id=0):
  169. if self.user:
  170. #h.add_alert('Already signed in.')
  171. redirect_wsave(controller='home',action='index')
  172. # destination included?
  173. if 'return_url' in request.params:
  174. # Remember where we came from so that the user can be sent there
  175. # after a successful login
  176. session['return_url'] = request.params['return_url']
  177. session.save()
  178. if 'unique' in request.params:
  179. user = meta.DBSession.query(Person).filter_by(
  180. user_uniqueid=request.params['unique'].lower()).first()
  181. if user is None:
  182. self.add_error("That link does not appear to be valid,\
  183. please contact the person that invited you or sign up.")
  184. return redirect_wsave("/user/signup" )
  185. return self.signup()
  186. elif user.verified == True:
  187. # this user already registered
  188. self.add_alert('Already verified account')
  189. return redirect_wsave("/user/signin" )
  190. else:
  191. self.user = user
  192. self.render('/user/verify.html')
  193. def verify_POST(self,id=0):
  194. """
  195. User has selected to enter a username pwd
  196. This is a "mini" form, signup is full one
  197. """
  198. if 'unique' in request.params:
  199. user = meta.DBSession.query(Person).filter_by(
  200. user_uniqueid=request.params['unique'].lower()).first()
  201. # TODO should we validate a time stamp?
  202. if user is None:
  203. self.add_error("We were not able to verify this invite, please try again")
  204. elif 'password' in self.form_result:
  205. user.displayname = self.form_result['displayname']
  206. user.set_password(self.form_result['password'])
  207. user.verified = True
  208. user.waitinglist = False
  209. response.set_cookie('dsuserkey', user.user_uniqueid,
  210. expires=datetime.today() + timedelta(days=31))
  211. self.start_session(user)
  212. user.save()
  213. else:
  214. self.add_error("You did not submit a password, please try again.")
  215. return self.returnurl_orgoto(controller='home',action='index')
  216. else:
  217. self.add_error("You need to enter an email and password to signin.")
  218. self.render('/user/signin.html')
  219. def verifycontinue(self,id=0):
  220. if 'unique' in request.params:
  221. user = meta.DBSession.query(Person).filter_by(
  222. user_uniqueid=request.params['unique'].lower()).first()
  223. # TODO should we validate a time stamp?
  224. if user is None:
  225. self.add_error("Whoops, there was an error, please click on the \
  226. link in the email again.")
  227. return self.verify()
  228. else:
  229. self.start_session(user)
  230. return self.redirect("/")
  231. def signup(self,id=0):
  232. user = self.get_current_user()
  233. form = SignupForm()
  234. if user:
  235. self.add_alert('Already signed in.')
  236. #redirect_wsave(action='index')
  237. self.render('/user/signup.html',form=form)
  238. def interest(self,id=0):
  239. """
  240. User has selected to enter an email to be on waitinglist
  241. """
  242. log.debug(self.request.arguments)
  243. form = SignupForm(QueryDict(self.request.arguments))
  244. log.debug(form.data)
  245. if 'email' in self.request.arguments and form.validate():
  246. user = meta.DBSession.query(Person).filter_by(
  247. email=self.get_argument("email").lower()).first()
  248. if user is None:
  249. new_email = form.email.data.lower()
  250. site = Site(name=new_email,email=new_email)
  251. site.save()
  252. user = Person(site_id=site.id,email=new_email,
  253. displayname=new_email)
  254. user.slug = user.hashedemail
  255. user.save()
  256. a = Activity(site_id=user.site_id,person_id=user.id,activity='Signup Interest Form')
  257. #a.ref_url = 'comment url'
  258. a.ip = self.request.remote_ip
  259. a.category = 'account'
  260. a.save()
  261. link = '%s/user/verify?unique=%s&node=%s&return_url=%s' %\
  262. (options.base_url,
  263. user.user_uniqueid,
  264. user.id,
  265. urllib.quote_plus('/user/viewh/%s' % (user.hashedemail)))
  266. json_dict = {
  267. 'emails':[user.email],
  268. 'template_name':'thank_you_for_registering_with_demisauce',
  269. 'template_data':{
  270. 'link':link,
  271. 'displayname':user.displayname,
  272. 'email':user.email,
  273. 'title':'welcome'
  274. }
  275. }
  276. self.db.gearman_client.do_task(Task("email_send",json.dumps(json_dict), background=True))
  277. self.add_alert("Thank You!")
  278. self.redirect("/")
  279. return self.render('/user/signup.html',form=form)
  280. def signin(self,id=0):
  281. log.info('made it to account signin?' )
  282. email = None
  283. if self.get_current_user():
  284. return self.redirect("/home/index")
  285. elif 'dsuserkey' in self.cookies:
  286. user = meta.DBSession.query(Person).filter_by(
  287. user_uniqueid=self.get_cookie('dsuserkey').lower()).first()
  288. if user:
  289. a = Activity(site_id=user.site_id,person_id=user.id,activity='Logging In')
  290. #a.ref_url = 'comment url'
  291. a.category = 'account'
  292. a.ip = self.request.remote_ip
  293. self.set_current_user(user)
  294. return self.redirect('/home/default')
  295. if 'email' in self.cookies:
  296. email = self.get_cookie('email').lower()
  297. googleurl = google_auth_url('%s/user/usersettings' % options.base_url)
  298. self.render('/user/signin.html',google_auth_url=googleurl,email=email)
  299. def signin_POST(self,id=0):
  300. log.info('made it to account signin_POST?' )
  301. if 'email' in self.request.arguments:
  302. user = meta.DBSession.query(Person).filter_by(
  303. email=self.get_argument('email').lower()).first()
  304. if user is None:
  305. self.add_error("We were not able to verify that email\
  306. or password, please try again")
  307. elif 'password' in self.request.arguments:
  308. if user.is_authenticated(self.get_argument('password')):
  309. a = Activity(site_id=user.site_id,person_id=user.id,activity='Logging In')
  310. #a.ref_url = 'comment url'
  311. a.category = 'account'
  312. a.ip = self.request.remote_ip
  313. a.save()
  314. remember_me = False
  315. if 'remember_me' in self.request.arguments:
  316. remember_me = True
  317. self.set_current_user(user,is_authenticated = True,remember_me=remember_me,islogon=True)
  318. return self.redirect("/dashboard")
  319. else:
  320. self.add_error("We were not able to verify that \
  321. email or password, please try again")
  322. else:
  323. self.add_error("You did not submit a password, please try again.")
  324. else:
  325. self.add_error("You need to enter an email and password to signin.")
  326. self.render('/user/signin.html')
  327. def logout(self,id=0):
  328. if not self.user:
  329. self.redirect("/")
  330. self.clear_cookie('dsuserkey')
  331. self.clear_cookie('dsuser')
  332. self.redirect("/")
  333. def handshake(self,id=0):
  334. if 'token' in request.params and 'site_slug' in request.params:
  335. # start a handshake, to figure out if we know this user.
  336. site = Site.by_slug(str(request.params['site_slug']))
  337. if site and site.id > 0:
  338. # lookup user? how?
  339. expire_seconds = 60*60*24*31
  340. #TODO: verify that url it came from is in site config
  341. response.set_cookie('dsu', user.public_token(),path='/',
  342. expires=expire_seconds, secure=False)
  343. return ''
  344. elif 'usertoken' in request.params:
  345. pass
  346. """
  347. if apiuser == None and 'token' in request.params:
  348. url = 'http://%s/%s?' % (request.environ['HTTP_HOST'],request.environ['PATH_INFO'])
  349. return_url = urllib.urlencode({'return_url':url})
  350. url = '%s?token_response=%s&%s' % ('http://demisauce.test:8001/handshake/initial',request.params['token'],return_url)
  351. #urllib.urlencode({'return_url':'http://localhost:4951/user/handshake'})
  352. print 'redirecting for handshake url=%s' % url
  353. # http://demisauce.test:8001/handshake/initial?return_url=http%3A%2F%2Flocalhost%3A4951%2Faccount%2Fhandshake&token=yourtoken
  354. #redirect_to('http://demisauce.test:8001/handshake/initial?return_url=http%3A%2F%2Flocalhost%3A4951%2Faccount%2Fhandshake&token=%s' % apiuser.hashed_email)
  355. return redirect_to(url)
  356. """
  357. def edit(self,id=0):
  358. if not self.user.isadmin and int(id) != self.user.id:
  359. return self.redirect("/home/index")
  360. person = meta.DBSession.query(Person).filter_by(
  361. site_id=self.user.site_id, id=id).first()
  362. self.render('/user/edit.html',person=person)
  363. def account_edit(self,id=0):
  364. """
  365. User has selected to update profile
  366. """
  367. if self.user and self.has_args('email','id'):
  368. id = int(self.get_argument('id'))
  369. if id == self.user.id or self.user.isadmin:
  370. user = Person.get(self.user.site_id,id)
  371. user.displayname = self.get_argument('displayname')
  372. user.set_email(self.get_argument('email'))
  373. user.url = self.get_argument('url')
  374. user.save()
  375. if id == self.user.id:
  376. self.set_current_user(user)
  377. self.render('/user/settings.html',person=user)
  378. def change_pwd(self,id=0):
  379. if self.user:
  380. user = meta.DBSession.query(Person).filter_by(
  381. email=self.user.email.lower()).first()
  382. person = user
  383. if user.hashed_password == None or user.is_authenticated(self.get_argument('password')):
  384. #a = Activity(site_id=user.site_id,person_id=user.id,activity='Changing Password',category='account')
  385. #a.save()
  386. add_activity(user,activity='Changing Password',category='account')
  387. user.set_password(self.get_argument('password1'))
  388. user.save()
  389. self.add_alert("Your Password was updated")
  390. else:
  391. self.add_error("We were not able to verify the \
  392. existing password, please try again")
  393. self.render('/user/settings.html',person=person)
  394. @requires_admin
  395. def usersettings(self,id=0):
  396. if not self.user:
  397. redirect_to(controller='home', action='index', id=None)
  398. else:
  399. log.debug('getting user.id = %s site_id=%s' % (self.user.id,self.user.site_id))
  400. person = meta.DBSession.query(Person).filter_by(
  401. site_id=self.user.site_id, id=self.user.id).first()
  402. return self._view(person,getcomments=True)
  403. def _view(self,person,getcomments=False):
  404. if person:
  405. helptickets = None #person.help_tickets()
  406. activities_by_day = Activity.stats_by_person(person.site_id,person.id)
  407. activity_count = len(activities_by_day)
  408. if self.user is None:
  409. pass
  410. elif self.user is not None and self.user.issysadmin:
  411. pass
  412. elif self.user is not None and self.user.isadmin:
  413. pass
  414. else:
  415. if self.user.site_id == person.site_id:
  416. pass
  417. else:
  418. person = None
  419. else:
  420. pass #TODO: raise error, or bad page
  421. self.render('/user/settings.html',person=person,
  422. activities_by_day=activities_by_day,activity_count=activity_count)
  423. def viewh(self,id='blah'):
  424. person = meta.DBSession.query(Person).filter_by(hashedemail=id).first()
  425. return self._view(person,True)
  426. @requires_admin
  427. def view(self,id=0):
  428. if not self.user:
  429. self.redirect('/')
  430. if self.user.issysadmin and id > 0:
  431. person = Person.get(-1,id)
  432. elif id > 0:
  433. person = Person.get(self.user.site_id,id)
  434. return self._view(person,True)
  435. def view_mini(self,id=0):
  436. person = None
  437. if id > 0:
  438. person = Person.get(self.user.site_id,id)
  439. self.render('/user/profile_mini.html',person=person)
  440. class GroupController(RestMixin,BaseHandler):
  441. def index(self,id=0):
  442. return self.viewlist()
  443. def ajaxget(self,id=''):
  444. if 'q' in self.request.arguments:
  445. q = self.get_argument("q")
  446. pl = meta.DBSession.query(Person).filter(or_(
  447. Person.displayname.like('%' + q + '%'),
  448. Person.email.like('%' + q + '%'))).limit(20)
  449. else:
  450. pl = meta.DBSession.query(Person).limit(20)
  451. s = ''
  452. for p in pl:
  453. s += "%s|%s\n" % (p.displayname,p.email)
  454. self.write(s)
  455. def viewlist(self,id=0):
  456. item = None
  457. groups = Group.by_site(self.user.site_id)
  458. temp = """
  459. filter = 'all'
  460. if 'filter' in request.params:
  461. filter = request.params['filter']
  462. page = 1
  463. if 'page' in request.params:
  464. page = int(request.params['page'])
  465. c.groups = webhelpers.paginate.Page(
  466. Group.by_site(self.user.site_id),
  467. page=page,items_per_page=5)
  468. ${h.dspager(c.groups)}
  469. groups = h.dspager(groups)
  470. """
  471. self.render('/user/group.html',action='list',groups=groups)
  472. def view(self,id=0):
  473. item = Group.get(self.user.site_id,id)
  474. if not item or not item.site_id == self.user.site_id:
  475. item = None
  476. self.render('user/group.html',action='view',item=item)
  477. def addedit(self,id=0):
  478. return self.viewlist(id)
  479. def addedit_post(self,id=''):
  480. g = None
  481. form = GroupForm(QueryDict(self.request.arguments))
  482. print form.data
  483. if form and form.validate():
  484. if 'id' in self.request.arguments and self.get_argument("id") != '0':
  485. g = Group.get(self.user.site_id,int(self.get_argument("id")))
  486. g.name = form.name.data
  487. else:
  488. g = Group(site_id=self.user.site_id,name=form.name.data)
  489. newtogroup, newtosite = g.add_memberlist(form.members.data)
  490. g.save()
  491. #return 'newtogroup= %s, \n newtosite=%s' % (newtogroup, newtosite)
  492. return self.viewlist()
  493. #@rest.dispatch_on(POST="group_popup_submit")
  494. def popup(self,id=0):
  495. item = Group()
  496. self.render('/user/group_popup.html',action='edit',item=item)
  497. def popup_view(self,id=0):
  498. item = Group.get(self.user.site_id,id)
  499. if not item.site_id == self.user.site_id:
  500. item = None
  501. self.render('/user/group_popup.html',action='view',item=item)
  502. #@validate(schema=GroupFormValidation(), form='popup')
  503. def popup_post(self,id=''):
  504. g = None
  505. form = GroupForm(QueryDict(self.request.arguments))
  506. if form and form.validate():
  507. if 'id' in self.request.arguments and self.get_argument("id") != '0':
  508. g = Group.get(self.user.site_id,int(self.get_argument("id")))
  509. g.name = form.name.data
  510. else:
  511. g = Group(site_id=self.user.site_id,name=form.name.data)
  512. newtogroup, newtosite = g.add_memberlist(form.members.data)
  513. g.save()
  514. #return 'newtogroup= %s, \n newtosite=%s' % (newtogroup, newtosite)
  515. self.popup_view(g.id)
  516. def edit(self,id=0):
  517. item = Group.get(self.user.site_id,id)
  518. if not item or not item.site_id == self.user.site_id:
  519. item = None
  520. log.debug(item.members)
  521. for m in item.members:
  522. log.debug(m)
  523. self.render('/user/group.html',action='edit',item=item)
  524. _controllers = [
  525. (r"/user/group/(.*?)/(.*?)/", GroupController),
  526. (r"/user/group/(.*?)/(.*?)", GroupController),
  527. (r"/user/group/(.*?)", GroupController),
  528. (r"/user/(.*?)/(.*?)/", AccountController),
  529. (r"/user/(.*?)/(.*?)", AccountController),
  530. (r"/user/(.*?)", AccountController),
  531. ]