def post(self): """ Block the given user. Request: `POST` `/users/block` Request body: {'user_id': @user_id@} """ user = _get_user(self.request.validated['user_id']) user.blocked = True # suspend account in Discourse (suspending an account prevents a login) try: client = get_discourse_client(self.request.registry.settings) block_duration = 99999 # 99999 days = 273 years client.suspend(user.id, block_duration, 'account blocked by moderator') except: log.error('Suspending account in Discourse failed: %d', user.id, exc_info=True) raise HTTPInternalServerError( 'Suspending account in Discourse failed') return {}
def post(self): request = self.request user = request.validated['user'] user.password = request.validated['password'] # The user was validated by the nonce so we can log in token = log_validated_user_i_know_what_i_do(user, request) if token: settings = request.registry.settings response = token_to_response(user, token, request) try: client = get_discourse_client(settings) r = client.redirect_without_nonce(user) response['redirect_internal'] = r except: # Since only the password is changed, any error with discourse # must not prevent login and validation. log.error( 'Error logging into discourse for %d', user.id, exc_info=True) user.clear_validation_nonce() try: DBSession.flush() except: log.warning('Error persisting user', exc_info=True) raise HTTPInternalServerError('Error persisting user') return response else: request.errors.status = 403 request.errors.add('body', 'user', 'Login failed') return None
def post(self): request = self.request username = request.validated['username'] password = request.validated['password'] user = DBSession.query(User). \ filter(User.username == username).first() token = try_login(user, password, request) if user else None if token: response = token_to_response(user, token, request) if 'discourse' in request.json: settings = request.registry.settings client = get_discourse_client(settings) try: if 'sso' in request.json and 'sig' in request.json: sso = request.json['sso'] sig = request.json['sig'] redirect = client.redirect(user, sso, sig) response['redirect'] = redirect else: r = client.redirect_without_nonce(user) response['redirect_internal'] = r except: # Any error with discourse should not prevent login log.warning('Error logging into discourse for %d', user.id, exc_info=True) return response else: request.errors.status = 403 request.errors.add('body', 'user', 'Login failed') return None
def post(self): request = self.request username = request.validated['username'] password = request.validated['password'] user = DBSession.query(User). \ filter(User.username == username).first() token = try_login(user, password, request) if user else None if token: response = token_to_response(user, token, request) if 'discourse' in request.json: settings = request.registry.settings client = get_discourse_client(settings) try: if 'sso' in request.json and 'sig' in request.json: sso = request.json['sso'] sig = request.json['sig'] redirect = client.redirect(user, sso, sig) response['redirect'] = redirect else: r = client.redirect_without_nonce(user) response['redirect_internal'] = r except: # Any error with discourse should not prevent login log.warning( 'Error logging into discourse for %d', user.id, exc_info=True) return response else: request.errors.status = 403 request.errors.add('body', 'user', 'Login failed') return None
def post(self): request = self.request user = request.validated['user'] user.password = request.validated['password'] # The user was validated by the nonce so we can log in token = log_validated_user_i_know_what_i_do(user, request) if token: settings = request.registry.settings response = token_to_response(user, token, request) try: client = get_discourse_client(settings) r = client.redirect_without_nonce(user) response['redirect_internal'] = r except: # Since only the password is changed, any error with discourse # must not prevent login and validation. log.error('Error logging into discourse for %d', user.id, exc_info=True) user.clear_validation_nonce() try: DBSession.flush() except: log.warning('Error persisting user', exc_info=True) raise HTTPInternalServerError('Error persisting user') return response else: request.errors.status = 403 request.errors.add('body', 'user', 'Login failed') return None
def collection_post(self): settings = self.request.registry.settings locale = self.request.validated['locale'] title = "{}_{}".format(locale.document_id, locale.lang) content = '<a href="{}">{}</a>'.format( self.request.referer, locale.title) category = settings['discourse.category'] # category could be id or name try: category = int(category) except: pass client = get_discourse_client(settings) try: response = client.client.create_post(content, title=title, category=category) except: raise HTTPInternalServerError('Error with Discourse') if "topic_id" in response: document_topic = DocumentTopic(topic_id=response['topic_id']) locale.document_topic = document_topic update_cache_version_direct(locale.document_id) DBSession.flush() return response
def post(self): request = self.request username = request.validated["username"] password = request.validated["password"] user = DBSession.query(User).filter(User.username == username).first() token = try_login(user, password, request) if user else None if token: response = token_to_response(user, token, request) if "discourse" in request.json: settings = request.registry.settings client = get_discourse_client(settings) try: if "sso" in request.json and "sig" in request.json: sso = request.json["sso"] sig = request.json["sig"] redirect = client.redirect(user, sso, sig) response["redirect"] = redirect else: r = client.redirect_without_nonce(user) response["redirect_internal"] = r except: # Any error with discourse should not prevent login log.warning("Error logging into discourse for %d", user.id, exc_info=True) return response else: request.errors.status = 403 request.errors.add("body", "user", "Login failed") return None
def post(self): """ Unblock the given user. Request: `POST` `/users/unblock` Request body: {'user_id': @user_id@} """ user = _get_user(self.request.validated['user_id']) user.blocked = False # Make sure the rate limiting counter is reset # (it might be the reason the user was blocked): user.ratelimit_times = 0 # unsuspend account in Discourse try: client = get_discourse_client(self.request.registry.settings) client.unsuspend(user.id) except: log.error('Unsuspending account in Discourse failed: %d', user.id, exc_info=True) raise HTTPInternalServerError( 'Unsuspending account in Discourse failed') return {}
def get(self): settings = self.request.registry.settings userid = self.request.authenticated_userid client = get_discourse_client(settings) d_username = client.get_username(userid) messages = client.client.private_messages_unread(d_username) count = len(messages['topic_list']['topics']) link = '%s/users/%s/messages' % (client.discourse_public_url, d_username) return {link: link, count: count}
def get(self): settings = self.request.registry.settings userid = self.request.authenticated_userid client = get_discourse_client(settings) d_username = client.get_username(userid) messages = client.client.private_messages_unread(d_username) count = len(messages['topic_list']['topics']) link = '%s/users/%s/messages' % ( client.discourse_public_url, d_username) return {link: link, count: count}
def post(self): request = self.request userid = request.authenticated_userid result = {"user": userid} remove_token(extract_token(request)) if "discourse" in request.json: try: settings = request.registry.settings client = get_discourse_client(settings) result["logged_out_discourse_user"] = client.logout(userid) except: # Any error with discourse should not prevent logout log.warning("Error logging out of discourse for %d", userid, exc_info=True) return result
def post(self): user = self.request.validated['sso_user'] token = log_validated_user_i_know_what_i_do(user, self.request) response = token_to_response(user, token, self.request) if 'discourse' in self.request.json: client = get_discourse_client(self.request.registry.settings) try: r = client.redirect_without_nonce(user) response['redirect_internal'] = r except Exception: # Any error with discourse should not prevent login log.warning('Error logging into discourse for %d', user.id, exc_info=True) return response
def collection_post(self): settings = self.request.registry.settings locale = self.request.validated['locale'] document = self.request.validated['document'] document_type = association_keys_for_types[document.type] document_path = "/{}/{}/{}".format(document_type, locale.document_id, locale.lang) content = '<a href="https://www.camptocamp.org{}">{}</a>'.format( document_path, locale.title or document_path) category = settings['discourse.category'] # category could be id or name try: category = int(category) except Exception: pass client = get_discourse_client(settings) try: title = "{}_{}".format(locale.document_id, locale.lang) response = client.client.create_post(content, title=title, category=category) except Exception as e: log.error('Error with Discourse: {}'.format(str(e)), exc_info=True) raise HTTPInternalServerError('Error with Discourse') if "topic_id" in response: topic_id = response['topic_id'] document_topic = DocumentTopic(topic_id=topic_id) locale.document_topic = document_topic update_cache_version_direct(locale.document_id) DBSession.flush() if locale.type == document_types.OUTING_TYPE: try: self.invite_participants(client, locale, topic_id) except Exception: log.error( 'Inviting participants of outing {} failed'.format( locale.document_id), exc_info=True) return response
def post(self): request = self.request userid = request.authenticated_userid result = {'user': userid} remove_token(extract_token(request)) if 'discourse' in request.json: try: settings = request.registry.settings client = get_discourse_client(settings) result['logged_out_discourse_user'] = client.logout(userid) except: # Any error with discourse should not prevent logout log.warning('Error logging out of discourse for %d', userid, exc_info=True) return result
def post(self): request = self.request user = request.validated['user'] user.clear_validation_nonce() user.email = user.email_to_validate user.email_to_validate = None # Synchronize the new email (and other parameters) try: client = get_discourse_client(request.registry.settings) client.sync_sso(user) except: log.error('Error syncing email with discourse', exc_info=True) raise HTTPInternalServerError('Error with Discourse') try: DBSession.flush() except: log.warning('Error persisting user', exc_info=True) raise HTTPInternalServerError('Error persisting user')
def post(self): request = self.request user = request.validated['user'] user.clear_validation_nonce() user.email = user.email_to_validate user.email_to_validate = None # Synchronize the new email (and other parameters) try: client = get_discourse_client(request.registry.settings) client.sync_sso(user) except: log.error('Error syncing email with discourse', exc_info=True) raise HTTPInternalServerError('Error with Discourse') try: DBSession.flush() except: log.warning('Error persisting user', exc_info=True) raise HTTPInternalServerError('Error persisting user')
def post(self): request = self.request user = request.validated['user'] user.clear_validation_nonce() user.email_validated = True # the user profile can be indexed once the account is confirmed notify_es_syncer(self.request.registry.queue_config) # Synchronizing to Discourse is unnecessary as it will be done # during the redirect_without_nonce call below. # The user was validated by the nonce so we can log in token = log_validated_user_i_know_what_i_do(user, request) if token: response = token_to_response(user, token, request) settings = request.registry.settings try: client = get_discourse_client(settings) r = client.redirect_without_nonce(user) response['redirect_internal'] = r except: # Any error with discourse must prevent login and validation log.error('Error logging into discourse for %d', user.id, exc_info=True) raise HTTPInternalServerError('Error with Discourse') try: DBSession.flush() except: log.warning('Error persisting user', exc_info=True) raise HTTPInternalServerError('Error persisting user') return response else: request.errors.status = 403 request.errors.add('body', 'user', 'Login failed') return None
def post(self): request = self.request user = request.validated['user'] user.clear_validation_nonce() user.email_validated = True # the user profile can be indexed once the account is confirmed notify_es_syncer(self.request.registry.queue_config) # Synchronizing to Discourse is unnecessary as it will be done # during the redirect_without_nonce call below. # The user was validated by the nonce so we can log in token = log_validated_user_i_know_what_i_do(user, request) if token: response = token_to_response(user, token, request) settings = request.registry.settings try: client = get_discourse_client(settings) r = client.redirect_without_nonce(user) response['redirect_internal'] = r except: # Any error with discourse must prevent login and validation log.error( 'Error logging into discourse for %d', user.id, exc_info=True) raise HTTPInternalServerError('Error with Discourse') try: DBSession.flush() except: log.warning('Error persisting user', exc_info=True) raise HTTPInternalServerError('Error persisting user') return response else: request.errors.status = 403 request.errors.add('body', 'user', 'Login failed') return None
def setUp(self): # noqa self.original_discourse_client = get_discourse_client(self.settings) self._prefix = "/users" self._model = User BaseTestRest.setUp(self) self.set_discourse_up()
def post(self): user = self.get_user() request = self.request validated = request.validated result = {} # Before all, check whether the user knows the current password current_password = validated['currentpassword'] if not user.validate_password(current_password): request.errors.add('body', 'currentpassword', 'Invalid password') return sync_sso = False # update password if a new password is provided if 'newpassword' in validated: user.password = validated['newpassword'] # start email validation procedure if a new email is provided email_link = None if 'email' in validated and validated['email'] != user.email: user.email_to_validate = validated['email'] user.update_validation_nonce( Purpose.change_email, VALIDATION_EXPIRE_DAYS) email_service = get_email_service(self.request) nonce = user.validation_nonce settings = request.registry.settings link = settings['mail.validate_change_email_url_template'].format( '#', nonce) email_link = link result['email'] = validated['email'] result['sent_email'] = True sync_sso = True update_search_index = False if 'name' in validated: user.name = validated['name'] result['name'] = user.name update_search_index = True sync_sso = True if 'forum_username' in validated: user.forum_username = validated['forum_username'] result['forum_username'] = user.forum_username update_search_index = True sync_sso = True if 'is_profile_public' in validated: user.is_profile_public = validated['is_profile_public'] # Synchronize everything except the new email (still stored # in the email_to_validate attribute while validation is pending). if sync_sso: try: client = get_discourse_client(request.registry.settings) client.sync_sso(user) except: log.error('Error syncing with discourse', exc_info=True) raise HTTPInternalServerError('Error with Discourse') try: DBSession.flush() except: log.warning('Error persisting user', exc_info=True) raise HTTPInternalServerError('Error persisting user') if email_link: email_service.send_change_email_confirmation(user, link) if update_search_index: # when user name changes, the search index has to be updated notify_es_syncer(self.request.registry.queue_config) # also update the cache version of the user profile update_cache_version(user.profile) return result
def post(self): user = self.get_user() request = self.request validated = request.validated result = {} # Before all, check whether the user knows the current password current_password = validated['currentpassword'] if not user.validate_password(current_password): request.errors.add('body', 'currentpassword', 'Invalid password') return sync_sso = False # update password if a new password is provided if 'newpassword' in validated: user.password = validated['newpassword'] # start email validation procedure if a new email is provided email_link = None if 'email' in validated and validated['email'] != user.email: user.email_to_validate = validated['email'] user.update_validation_nonce(Purpose.change_email, VALIDATION_EXPIRE_DAYS) email_service = get_email_service(self.request) nonce = user.validation_nonce settings = request.registry.settings link = settings['mail.validate_change_email_url_template'].format( '#', nonce) email_link = link result['email'] = validated['email'] result['sent_email'] = True sync_sso = True update_search_index = False if 'name' in validated: user.name = validated['name'] result['name'] = user.name update_search_index = True sync_sso = True if 'forum_username' in validated: user.forum_username = validated['forum_username'] result['forum_username'] = user.forum_username update_search_index = True sync_sso = True if 'is_profile_public' in validated: user.is_profile_public = validated['is_profile_public'] # Synchronize everything except the new email (still stored # in the email_to_validate attribute while validation is pending). if sync_sso: try: client = get_discourse_client(request.registry.settings) client.sync_sso(user) except Exception: log.error('Error syncing with discourse', exc_info=True) raise HTTPInternalServerError('Error with Discourse') try: DBSession.flush() except Exception: log.warning('Error persisting user', exc_info=True) raise HTTPInternalServerError('Error persisting user') if email_link: email_service.send_change_email_confirmation(user, link) if update_search_index: # when user name changes, the search index has to be updated notify_es_syncer(self.request.registry.queue_config) # also update the cache version of the user profile update_cache_version(user.profile) return result
def __init__(self, *args, **kwargs): BaseTestRest.__init__(self, *args, **kwargs) self.original_discourse_client = get_discourse_client(self.settings)
def post(self): """ Synchronize user details and return authentication url. Important: Email addresses need to be validated by external site. """ request = self.request sso_key = request.validated['sso_key'] sso_external_id = request.validated['sso_external_id'] user = request.validated['sso_user'] if user is None: # create new user user = User( username=request.validated['username'], name=request.validated['name'], forum_username=request.validated['forum_username'], email=request.validated['email'], email_validated=True, # MUST be validated by external site lang=request.validated['lang'], password=generate_token() # random password ) # directly create the user profile, the document id of the profile # is the user id lang = user.lang user.profile = UserProfile( categories=['amateur'], locales=[DocumentLocale(lang=lang, title='')], ) DBSession.add(user) DBSession.flush() if sso_external_id is None: sso_external_id = SsoExternalId( domain=sso_key.domain, external_id=request.validated['external_id'], user=user, ) DBSession.add(sso_external_id) sso_external_id.token = generate_token() sso_external_id.expire = sso_expire_from_now() client = get_discourse_client(request.registry.settings) discourse_userid = call_discourse(get_discourse_userid, client, user.id) if discourse_userid is None: call_discourse(client.sync_sso, user) discourse_userid = client.get_userid(user.id) # From cache # Groups are added to discourse, not removed group_ids = [] discourse_groups = None groups = request.validated['groups'] or '' for group_name in groups.split(','): if group_name == '': continue group_id = None if discourse_groups is None: discourse_groups = call_discourse(client.client.groups) group_id = None for discourse_group in discourse_groups: if discourse_group['name'] == group_name: group_id = discourse_group['id'] if group_id is None: # If group is not found, we ignore it as we want to return # a valid token for user authentication pass else: group_ids.append(group_id) for group_id in group_ids: call_discourse(client.client.add_user_to_group, group_id, discourse_userid) return { 'url': '{}/sso-login?no_redirect&{}'.format( request.registry.settings['ui.url'], urlencode({'token': sso_external_id.token})) }