def resend_create(self, workspace_id): #verify email valid and send invitation mail if 'email' in request.params: if request.params['email'] == '': return render('invitation/resend_show.mako') user = User.get_by_lower_email(int(workspace_id), request.params['email']) if (user): # Instantiate a Kcd client. invitees = [] invitee = WorkspaceInvitee() invitee.email_address = user.email invitee.send_mail = True invitees.append(invitee) message = "click on the link to join the teambox" kc = KcdClient(get_cached_kcd_external_conf_object()) #TODO handle kcd errors, render confirmation messages kc.invite_users(workspace_id, message, invitees) ui_info(message="You have been re-invited to the Teambox, please check you email and follow instructions.") return render('invitation/resend_success.mako') else: #please contact ws owner ui_error(message="No invitation to this teambox had been sent to this email address." + \ " If you were not invited to this teambox, please contact the teambox owner.") return render('invitation/resend_show.mako') pass else: abort(403)
def save(self): kc = KcdClient(get_cached_kcd_external_conf_object()) # TODO: check for status code from Kcd, and handle errors kc.save_notification_policy(self._workspace_id, self._user_id, self._new_notif_policy) self._notif_policy = self._new_notif_policy pass
def _request_common(self, workspace_id): # Check that the user is logged. if not session['user']: log.error("_request_common(): user is not logged.") abort(404) # Instantiate a Kcd client in the context-global variable. c.pubws_kc = KcdClient(get_cached_kcd_external_conf_object())
def login(self, workspace_id): # Get kcd database password. from kwmo.lib.config import get_cached_kcd_external_conf_object expected_passwd = get_cached_kcd_external_conf_object().db_passwd if request.params.has_key('stamp') \ and re.match(r"^\d+$", request.params['stamp']) \ and request.params.has_key('hash'): # Get the provided parameters. stamp = int(request.params['stamp']) hex_hash = request.params['hash'] # Make sure the stamp is in sync with the local server... the hash is good for 5 minutes. hash_timeout_secs = 300 if abs(int(time.time()) - stamp) > hash_timeout_secs: log.warning( "teambox_admin.login: Bad time stamp or servers time is out of sync." ) return abort(403) # Generate the local hash. md5 = hashlib.md5() md5.update(str(stamp)) md5.update(expected_passwd) expected_hex_hash = md5.digest().encode('hex') # Compare the provided hash and the generated one. if hex_hash == expected_hex_hash: # Login as user 1 (the workspace creator) in read-only mode. user_id = 1 session_timeout_secs = 1800 # 30 minutes session['admin'] = True session['expiration_time'] = int( time.time()) + session_timeout_secs session['mode'] = MODE_WS session['user_id'] = user_id session['user'] = User.get_by(workspace_id=workspace_id, id=user_id).to_dict() c.perms.addRole('roadmin') session.save() # Redirect to teambox. redirect_to("teambox_admin", workspace_id=workspace_id) else: log.debug("teambox_admin.login: Bad admin password.") return abort(403) else: log.debug("teambox_admin.login: Bad parameters.") return abort(404)
def login(self, workspace_id): # Get kcd database password. from kwmo.lib.config import get_cached_kcd_external_conf_object expected_passwd = get_cached_kcd_external_conf_object().db_passwd if request.params.has_key('stamp') \ and re.match(r"^\d+$", request.params['stamp']) \ and request.params.has_key('hash'): # Get the provided parameters. stamp = int(request.params['stamp']) hex_hash = request.params['hash'] # Make sure the stamp is in sync with the local server... the hash is good for 5 minutes. hash_timeout_secs = 300 if abs(int(time.time()) - stamp) > hash_timeout_secs: log.warning("teambox_admin.login: Bad time stamp or servers time is out of sync.") return abort(403) # Generate the local hash. md5 = hashlib.md5() md5.update(str(stamp)) md5.update(expected_passwd) expected_hex_hash = md5.digest().encode('hex') # Compare the provided hash and the generated one. if hex_hash == expected_hex_hash: # Login as user 1 (the workspace creator) in read-only mode. user_id = 1 session_timeout_secs = 1800 # 30 minutes session['admin'] = True session['expiration_time'] = int(time.time()) + session_timeout_secs session['mode'] = MODE_WS session['user_id'] = user_id session['user'] = User.get_by(workspace_id=workspace_id, id=user_id).to_dict() c.perms.addRole('roadmin') session.save() # Redirect to teambox. redirect_to("teambox_admin", workspace_id=workspace_id) else: log.debug("teambox_admin.login: Bad admin password.") return abort(403) else: log.debug("teambox_admin.login: Bad parameters.") return abort(404)
def get(self, workspace_id, email_id): # Return a rendered template #return render('/credentials_file.mako') # or, return a response response.content_type = "application/wsl" filename = "kwmo_creds.wsl" # Temporarily disabled - need to be debugged. if request.params.has_key('interactive') and str(request.params.get('interactive')) == "1": filename = c.workspace.name + ".wsl" response.headers['Content-disposition'] = 'attachment; filename="%s"' % ( filename.encode('latin1') ) #fix for IE response.headers['Pragma'] = 'public' response.headers['Cache-Control'] = 'max-age-0' errorStr = None #ws = Workspace.get_by(id= workspace_id) ws = c.workspace invitation = Invitation.get_by(email_id = email_id) if (ws and invitation): user = User.get_by(id = invitation.user_id, workspace=ws) if(user and ws.id==invitation.kws_id): c.invitation = invitation c.user = user c.workspace = ws conf = get_cached_kcd_external_conf_object() c.kcd_host = conf.kcd_host c.kcd_port = conf.kcd_port if ('password' in request.params): c.password = request.params['password'] if ('user_id' in session): c.password = session['password'] else: errorStr = "User was not invited to this workspace" else: errorStr = "Invalid email_id or workspace_id" if errorStr: c.errorStr = errorStr return render('credentials_file/error.mako') else: return render('credentials_file/get.mako')
def chat_request_result(self, workspace_id, req_id): workspace_id = int(workspace_id) req_id = int(req_id) req_start_time = request.params['req_start_time'] # Do some checks and initialization. self._check_public(workspace_id) self._request_common(workspace_id) # Get the request. req = ChatRequest.get_by(workspace_id=workspace_id, request_id=req_id) if req: # Check request status. if req.accepted: # Modify permissions. self._set_chat_requests_perms(False) self._set_chat_perms(True) # Save session. session.save() log.debug("chat_request_result(): accepted.") return {"result": "ok"} # Enable when debugging to enable automatic chat acceptation. if 0: from kanp import KANP_MINOR from pylons import config kc = KcdClient(get_cached_kcd_external_conf_object()) # This function has to be rewritten. kc.pubws_chat_request_accept(workspace_id, user_id, KANP_MINOR, req_id) else: # Bad request ID or kwsfetcher has not yet fetched the request. pass log.debug("chat_request_result(): pending, chat_req_id='%s', req_start_time='%s'." \ % ( str(req_id), str(req_start_time) ) ) return { "result": "pending", "chat_req_id": req_id, 'req_start_time': req_start_time }
def _invite_and_login(self, usr, workspace_id, password): invitation = Invitation.get_by(kws_id=workspace_id, inviting_user_id=0, user_id=usr.user_id) if invitation: email_id = invitation.email_id else: invitees = [] invitee = WorkspaceInvitee() invitee.email_address = usr.email invitee.send_mail = False invitees.append(invitee) kc = KcdClient(get_cached_kcd_external_conf_object()) #TODO handle kcd errors ws_url, invitees_result = kc.invite_users(workspace_id, '', invitees) email_id = invitees_result[0].email_id redirect_to(url('invite_create',workspace_id=workspace_id, email_id=email_id, password=password))
def post_message(self, workspace_id): workspace_id = int(workspace_id) # Get ajax parameters. channel_id = int(request.params['channel_id']) message = request.params['message'] #.encode('latin1') if not c.perms.hasPerm('chat.post.channel.%i' % (channel_id)): log.error("Chat post denied: user has not the right permissions.") raise KAjaxViewException("Chat post denied.") user_id = session['user_id'] log.debug("Chat post request: workspace_id=%i channel_id=%i user_id=%i" % \ ( workspace_id, channel_id, user_id ) ) # Instantiate a Kcd client. kc = KcdClient(get_cached_kcd_external_conf_object()) # Post the message. kc.post_chat_msg_request(workspace_id, channel_id, user_id, message) if 0: # Get first update directly (not finished: need other motifications at client side # so the update is not shown twice. state_req_id = int(request.params['state_req_id']) last_evt_chat_id = int(request.params['last_evt_chat_id']) time.sleep(0.5) # Wait for kwsfetcher to fetch the message. flags = (StateRequest.STATE_FORCE_SYNC | StateRequest.STATE_WANT_CHAT) params = { 'req_id': state_req_id, 'chat_channel_id': channel_id, 'last_evt_chat_id': last_evt_chat_id } updater_state_dict = state_request_get(c, session, flags, params) return {'updater': updater_state_dict} return {}
def chat_request_result(self, workspace_id, req_id): workspace_id = int(workspace_id) req_id = int(req_id) req_start_time = request.params['req_start_time'] # Do some checks and initialization. self._check_public(workspace_id) self._request_common(workspace_id) # Get the request. req = ChatRequest.get_by(workspace_id=workspace_id, request_id=req_id) if req: # Check request status. if req.accepted: # Modify permissions. self._set_chat_requests_perms(False) self._set_chat_perms(True) # Save session. session.save() log.debug("chat_request_result(): accepted.") return { "result" : "ok" } # Enable when debugging to enable automatic chat acceptation. if 0: from kanp import KANP_MINOR from pylons import config kc = KcdClient(get_cached_kcd_external_conf_object()) # This function has to be rewritten. kc.pubws_chat_request_accept(workspace_id, user_id, KANP_MINOR, req_id) else: # Bad request ID or kwsfetcher has not yet fetched the request. pass log.debug("chat_request_result(): pending, chat_req_id='%s', req_start_time='%s'." \ % ( str(req_id), str(req_start_time) ) ) return { "result" : "pending", "chat_req_id" : req_id, 'req_start_time' : req_start_time }
def post_message(self, workspace_id): workspace_id = int(workspace_id) # Get ajax parameters. channel_id = int(request.params['channel_id']) message = request.params['message'] #.encode('latin1') if not c.perms.hasPerm('chat.post.channel.%i' % (channel_id)): log.error("Chat post denied: user has not the right permissions.") raise KAjaxViewException("Chat post denied.") user_id = session['user_id'] log.debug("Chat post request: workspace_id=%i channel_id=%i user_id=%i" % \ ( workspace_id, channel_id, user_id ) ) # Instantiate a Kcd client. kc = KcdClient(get_cached_kcd_external_conf_object()) # Post the message. kc.post_chat_msg_request(workspace_id, channel_id, user_id, message) if 0: # Get first update directly (not finished: need other motifications at client side # so the update is not shown twice. state_req_id = int(request.params['state_req_id']) last_evt_chat_id = int(request.params['last_evt_chat_id']) time.sleep(0.5) # Wait for kwsfetcher to fetch the message. flags = ( StateRequest.STATE_FORCE_SYNC | StateRequest.STATE_WANT_CHAT ) params = { 'req_id' : state_req_id, 'chat_channel_id' : channel_id, 'last_evt_chat_id' : last_evt_chat_id } updater_state_dict = state_request_get(c, session, flags, params) return { 'updater' : updater_state_dict } return {}
def show(self, workspace_id, email_id): workspace_id = int(workspace_id) email_id = int(email_id) # Set logout url. c.logout_url = url('teambox_pubws_logout', workspace_id=workspace_id, email_id=email_id) # Check if the workspace is public. self._check_public(workspace_id) if 'email_id' in session and session['email_id'] != email_id: # User is logged but wants to access a different email. Reinit session. log.debug("Reinitializing session because user is using another email id: previous='%s', new='%s'." \ % ( str(session['email_id']), str(email_id) ) ) init_session(c.workspace, reinit=True) notif = request.GET.get('notif', 0) if notif: # This is the sender (user 1)... [re-]login automatically. log.debug( "User is accessing a public workspace using a notification link... automatically log user in." ) user = User.get_by(workspace_id=workspace_id, id=1) log.debug( "Reinitializing session because user is logging as user 1 (notif management)." ) init_session(c.workspace, reinit=True) self._login(user) c.notif_flag = True else: if 'user' in session and session['user'] and session['user'][ 'id'] == 1: # Sender is logged (as a sender) but he's using a regular skurl link: logout. log.debug( "Reinitializing session because user was logged as user 1 but is using a regular skurl link." ) init_session(c.workspace, reinit=True) if not c.perms.hasRole('skurl'): # Give skurl role, if not already done. c.perms.addRole('skurl') # Save session. session.save() if not 'email_id' in session: # Set email information in session. # Instantiate a Kcd client. kc = KcdClient(get_cached_kcd_external_conf_object()) # Check that email ID is valid. email_info = kc.pubws_get_email_info(workspace_id, email_id) if not email_info: log.debug("PubWS: invalild email ID: %i" % (email_id)) abort(404) # Get the email sender. sender_user = User.get_by(workspace_id=workspace_id, id=1) sender = kbase.PropStore() sender.name = sender_user.real_name sender.email = sender_user.email # Get the email recipients (list of PropStores, having name and email keys). raw_recipients = kc.pubws_get_eid_recipient_identities( workspace_id, email_id) # Strip sender email from recipients, if needed. recipients = [] for recipient in raw_recipients: if recipient.email != sender.email: recipients.append(recipient) # Merge sender and recipients. identities = [sender] + recipients # Set needed informations in session. session['email_id'] = email_id session['email_info'] = email_info.to_dict() session['identities'] = map(lambda x: x.to_dict(), identities) session.save() # Get informations that will be published in the template. c.dyn_version = 15 c.email_info = session['email_info'] c.json_email_info_str = simplejson.dumps(c.email_info) c.identities = session['identities'] c.json_identities_str = simplejson.dumps(c.identities) # Check if a chat request was accepted lately (delay is hardcoded in accepted_lately()). c.user_id = None if 'user_id' in session and session['user_id']: c.user_id = session['user_id'] if ChatRequest.accepted_lately(workspace_id, session['user_id']): # Deny chat requests and allow chat since a request was accepted lately. self._set_chat_requests_perms(False) self._set_chat_perms(True) else: # Allow chat requests and deny chat since no request was accepted lately. self._set_chat_requests_perms(True) self._set_chat_perms(False) # Allow workspace creation request. self._set_ws_creation_requests_perms(True) # Save session. session.save() c.base_url_paths = kurl.get_base_url_paths( 'teambox_updater', 'teambox_post_chat', 'teambox_download', 'teambox_upload', 'teambox_pubws_set_identity', 'teambox_pubws_chat_request', 'teambox_pubws_chat_request_result', 'teambox_pubws_kfsup_request', 'teambox_pubws_kfsdown_request', 'teambox_pubws_create_request') # Get first update directly. flags = (StateRequest.STATE_FORCE_SYNC | StateRequest.STATE_WANT_PERMS | StateRequest.STATE_WANT_MEMBERS | StateRequest.STATE_WANT_KFS | StateRequest.STATE_WANT_PUBWS_INFO) params = {} if 'user_id' in session and session['user_id']: flags |= StateRequest.STATE_WANT_CHAT params['chat_channel_id'] = session['user_id'] updater_state_dict = state_request_get(c, session, flags, params) c.updater_state_json = simplejson.dumps(updater_state_dict) return render('/teambox/pubwsshow.mako')
def pb_set_identity(self, workspace_id): import select from kcd_lib import WorkspaceInvitee workspace_id = int(workspace_id) # Get the workspace. if not c.workspace.public: log.warning("pb_set_identity: Workspace %i is not public." % (workspace_id)) abort(404) # Get POST parameters. identity_id = request.params['identity_id'] identity_id = int(identity_id) # Shortcuts identity = session['identities'][identity_id] log.debug("Recipient: %s" % (str(identity))) if identity_id == 0: # This is the sender (user 1). user = User.get_by(workspace_id=workspace_id, id=1) self._login(user) log.debug("Found matching user(0): '%s'." % (str(user))) return {'result': 'ok', 'user': session['user']} # This is a real recipient... try to get the user. user = User.get_by(workspace_id=workspace_id, email=identity['email']) if user: self._login(user) log.debug("Found matching user(1): '%s'." % (str(user))) return {'result': 'ok', 'user': session['user']} # Instantiate a Kcd client. kc = KcdClient(get_cached_kcd_external_conf_object()) # Invite user. invitee = WorkspaceInvitee(real_name=identity['name'], email_address=identity['email']) junk_url, invitees = kc.invite_users(workspace_id, "empty message", [invitee]) if invitees[0].error: log.debug("User could not be invited: '%s'." % (str(invitees[0].error))) raise Exception('Internal error.') # Get user. If not present, retry a few times, until new user is fetched by kwsfetcher or until timeout. wait_seconds = 0.5 timeout_seconds = 8 time_started = time.time() while 1: # Get user, if it exists (fetched by kwsfetcher). user = User.get_by(workspace_id=workspace_id, email=identity['email']) if user: self._login(user) log.debug("Found matching user (2): '%s'." % (str(user))) return {'result': 'ok', 'user': session['user']} # Check for timeout. if time.time() > time_started + timeout_seconds: break # Wait select.select([], [], [], wait_seconds) # Reached timeout. log.error( "Error: reached end of pb_set_identity(). KWSFetcher might be too loaded or down." ) raise Exception('Temporary server error: please try again later.')
def _upload(self, workspace_id): workspace_id = int(workspace_id) # Shortcuts share_id = 0 user_id = session['user']['id'] user_email = session['user']['email'] client_random_id = None # Permissions verification log.debug(str(c.perms.to_dict())) if not c.perms.hasPerm('kfs.upload.share.%i' % (share_id)): log.error("Upload denied: user has not the right permissions.") return abort(403) email_id = 0 parent_inode_id = None parent_commit_id = None filename = None inode_id = None commit_id = None if c.workspace.public: email_id = session['email_id'] email_date = session['email_info']['date'] email_subject = session['email_info']['subject'] kc = KcdClient(get_cached_kcd_external_conf_object()) kcd_dir = kc.kcd_kfs_create_skurl_directories( workspace_id, share_id, user_id, user_email, email_id, email_date, email_subject) parent_inode_id = kcd_dir.inode parent_commit_id = kcd_dir.commit_id else: inode_id = request.GET.get('inode_id', None) client_random_id = request.GET['client_random_id'] log.debug("about to upload a file with client_random_id %i" % (int(client_random_id))) if inode_id: # Updating a file. inode_id = long(inode_id) node = KcdKwsKfsCurrentView.get_by(kws_id=workspace_id, share_id=share_id, inode=inode_id) if not node: raise Exception("File does not exist.") filename = node.entry_name commit_id = node.commit_id else: # Get current kfs_dir object from request. # (It must be sent in the url AND NOT in the posted data for asynchroneous upload to work.) kfs_dir_json = request.GET['kfs_dir'] kfs_dir_dict = simplejson.loads(kfs_dir_json) assert kfs_dir_dict['workspace_id'] == workspace_id assert kfs_dir_dict['share_id'] == share_id # Get the dir node. kcd_dir = KcdKwsKfsCurrentView.get_by( kws_id=workspace_id, share_id=share_id, inode=kfs_dir_dict['inode_id']) parent_inode_id = kcd_dir.inode parent_commit_id = kcd_dir.commit_id # Helper function what will be used later in the asynchronous upload. # Get node by name: kfs_get_node_by_name = lambda x: KcdKwsKfsCurrentView.query.filter( and_(KcdKwsKfsCurrentView.kws_id == workspace_id, KcdKwsKfsCurrentView.share_id == share_id, KcdKwsKfsCurrentView.parent_inode == parent_inode_id, KcdKwsKfsCurrentView.entry_name == x)).first() # Set upload failure: set_upload_failure = None if client_random_id is not None: self.upload_status = KfsUploadStatus.create_save( workspace_id, share_id, user_id, client_random_id) set_upload_failure = lambda e: self.upload_status.update_status_faliure( e) #TODO: lamda function that should be used to update the progress of the uploaded file(bytes written+status) #kfs_update_progess_status = lambda num_bytes_written, status: self.upload_status.update(num_bytes_written, status) # Asynchronously upload files to KCD. kcd_conf = get_cached_kcd_external_conf_object() if c.workspace.public: # Virtual skurl file upload limit is 50MB but the only available size is the POST size. # POSTs up to 60MB are allowed. if 'CONTENT_LENGTH' in request.environ and int( request.environ['CONTENT_LENGTH']) > 60 * 1024 * 1024: log.debug("File upload too big: %i bytes." % (int(request.environ['CONTENT_LENGTH']))) # Read wsgi.input, otherwise it doesn't work. # FIXME: stop connection here and warn user (using Ajax?) # Can we render (reliably) before stdin is read? Seems not, to re-test. FieldStorage(fp=request.environ['wsgi.input'], environ=request.environ) return simplejson.dumps({ "result": "error", "error": "File is too big: limit is 50MB." }) fu = KFSWSGIFilesUpload(kcd_conf, request.environ, workspace_id, email_id, share_id, user_id, parent_inode_id, parent_commit_id, filename, inode_id, commit_id, kfs_get_node_by_name, set_upload_failure) fs = fu.run() return simplejson.dumps({"result": "ok"})
def download(self, workspace_id): workspace_id = int(workspace_id) # Shortcuts share_id = 0 user_id = session['user']['id'] kcd_conf = get_cached_kcd_external_conf_object() # Permissions verification if not c.perms.hasPerm('kfs.download.share.%i' % (share_id)): log.error("File download denied: user has not the right permissions.") # FIXME download permission error: get rid of 403 error: send an errror file? return abort(403) # Get kfs_file object from request. web_kfs_file_json = request.params.get('kfs_file') web_kfs_file_dict = simplejson.loads(web_kfs_file_json) web_kfs_file = WebKFSFile().from_dict(web_kfs_file_dict) assert web_kfs_file.workspace_id == workspace_id assert web_kfs_file.share_id == share_id # Get the kfs node associted to it. kfs_node = KfsNode.get_by(workspace_id=workspace_id, share_id=web_kfs_file.share_id, inode_id=web_kfs_file.inode_id) if c.workspace.public and not c.is_admin: # Check that the user has rights to download from this path. kfs_dir = kfs_node.parent if not kfs_dir: raise Exception("Public workspace file download: bad directory(0).") if kfs_dir.name == "Original attachments": kfs_dir = kfs_dir.parent expected_dir_name = get_kfs_skurl_subject(session['email_info']['date'], session['email_info']['subject']) if kfs_dir.name != expected_dir_name: raise Exception("Public workspace file download: bad directory(1).") kfs_dir_parent = kfs_dir.parent if not kfs_dir_parent: raise Exception("Public workspace file download: bad directory(2).") if kfs_dir_parent.parent_inode_id != KFS_ROOT_INODE_ID: raise Exception("Public workspace file download: bad directory(3)."); identities_emails = map(lambda x: x['email'], session['identities']) if kfs_dir_parent.name not in identities_emails: raise Exception("Public workspace file download: bad directory(4)."); # Get download mode. mode = request.params.get('mode', 'save') ctype = None if mode == 'open': # Guest mime type import mimetypes ctype, cencoding = mimetypes.guess_type(kfs_node.name, False) # not strict #ctype, cencoding = mimetypes.guess_type(kfs_node.name, True) # strict if not ctype: # Download mime type ctype, cencoding = ('application/octet-stream', None) kfs_files = [kfs_node.to_dict()] # Set the content type and the headers. response.headers['Content-Type'] = ctype #if cencoding: # response.headers['Content-Encoding'] = cencoding response.headers['Content-disposition'] = str('attachment; filename="%s"' % ( kfs_node.name.encode('latin1') )) response.headers['Content-Transfer-Encoding'] = 'binary' # Use a custom header that will be replaced in a middleware (workaround for # the Content-Length header being dropped somewhere in pylons). response.headers['X-Content-Length'] = str(kfs_node.file_size) # These headers are necessary for the download to work on IE. response.headers['Cache-Control'] = 'maxage=3600' response.headers['Pragma'] = 'public' if self.send_notification: # Send download notification to KCD. pubws_email_id = 0 if c.workspace.public: pubws_email_id = session['email_id'] kc = KcdClient(kcd_conf) try: kc.send_download_notification(workspace_id, user_id, kfs_node.share_id, kfs_node.inode_id, kfs_node.commit_id, pubws_email_id) log.debug(("Sent download notification: workspace_id=%i, user_id=%i, share_id=%i" + \ ", inode_id=%i, commit_id=%i, pubws_email_id=%i.") % \ ( workspace_id, user_id, kfs_node.share_id, kfs_node.inode_id, kfs_node.commit_id, pubws_email_id ) ) except Exception, e: log.error("Sending download notification failed: '%s'." % ( str(e) ) )