예제 #1
0
def request_signup_email_confirmation(user, template=None, subject=None):
    secret_info = {
        'userId': user.id,
        'email': user.email,
        'action': 'email_confirmation',
    }
    hours_duration = 24*14
    secret = Secret.create_secret(secret_info, hours_duration)
    url = '{BASEURL}/#/confirmemail?key={secret_key}'.format(
        BASEURL=config.BASEURL, secret_key=secret.key)
    if template is None:
        template = '''<p>A community share account has been created and attached to this email address.<p>

        <p>To confirm that you created the account, please click on the following link.</p>

        <p><a href={url}>{url}</a></p>

        <p>If you did not create this account, simply ignore this email.</p>
'''
    content = template.format(url=url)
    if subject is None:
        subject = 'CommunityShare Account Creation'
    email = mail.Email(
        from_address=config.DONOTREPLY_EMAIL_ADDRESS,
        to_address=user.email,
        subject=subject,
        content=content,
        new_content=content
    )
    error_message = mail.get_mailer().send(email)
    return error_message
예제 #2
0
def request_password_reset(user):
    secret_info = {
        'userId': user.id,
        'action': 'password_reset',
    }
    hours_duration = 48
    secret = Secret.create_secret(secret_info, hours_duration)
    url = '{BASEURL}/#/resetpassword?key={secret_key}'.format(
        BASEURL=config.BASEURL, secret_key=secret.key)
    content = '''<p>We received a request to reset your password for CommunityShare.</p>
    
<p>To reset your password please click on the following link and follow the instructions.</p>
    
<a href={url}>{url}</a>
    
<p>If you cannot click on the link copy it into the addressbar of your browser.</p>
'''
    content = content.format(url=url)
    email = mail.Email(
        from_address=config.DONOTREPLY_EMAIL_ADDRESS,
        to_address=user.email,
        subject='CommunityShare Password Reset Request',
        content=content,
        new_content=content,
        )
    error_message = mail.get_mailer().send(email)
    return error_message
예제 #3
0
 def setUp(self):
     data = {
         'DB_CONNECTION': 'sqlite:///{}'.format(self.SQLLITE_FILE),
         'MAILER_TYPE': 'QUEUE',
         'MAILGUN_API_KEY': 'whatever',
         'MAILGUN_DOMAIN': 'whatever',
         'LOGGING_LEVEL': 'DEBUG',
         'DONOTREPLY_EMAIL_ADDRESS': '*****@*****.**',
         'SUPPORT_EMAIL_ADDRESS': '*****@*****.**',
         'BUG_EMAIL_ADDRESS': '*****@*****.**',
         'ABUSE_EMAIL_ADDRESS': '*****@*****.**',
         'NOTIFY_EMAIL_ADDRESS': '*****@*****.**',
         'ADMIN_EMAIL_ADDRESSES': '*****@*****.**',
         'BASEURL': 'localhost:5000/',
         'S3_BUCKETNAME': os.environ['COMMUNITYSHARE_S3_BUCKETNAME'],
         'S3_KEY': os.environ['COMMUNITYSHARE_S3_KEY'],
         'S3_USERNAME': os.environ['COMMUNITYSHARE_S3_USERNAME'],
         'UPLOAD_LOCATION': os.environ['COMMUNITYSHARE_UPLOAD_LOCATION'],
         'COMMIT_HASH': 'dummy123',
         'ENCRYPTION_KEY': CryptHelper.generate_key(),
     }
     config.load_from_dict(data)
     setup.init_db()
     # Clear mail queue
     mailer = mail.get_mailer()
     while len(mailer.queue):
         mailer.pop()
     self.app = app.make_app().test_client()
예제 #4
0
 def test_password_reset(self):
     # Signup userA
     userA_id, userA_api_key, userA_email_key = self.sign_up(sample_userA)
     self.confirm_email(userA_email_key)
     rv = self.app.get('/api/requestresetpassword/{0}'.format(
         sample_userA['email']))
     assert(rv.status_code == 200)
     mailer = mail.get_mailer()
     # Check that we can authenticate with email and password
     headers = make_headers(email=sample_userA['email'], password=sample_userA['password'])
     rv = self.app.get('/api/requestapikey/', headers=headers)
     assert(rv.status_code == 200)
     # We should have one email in queue (email from password reset request)
     assert(len(mailer.queue) == 1)
     email = mailer.pop()
     links = email.find_links()
     assert(len(links)==1)
     email_key = re.search('key=(.*)', links[0]).groups()[0]
     logger.debug('email key is {0}'.format(email_key))
     # Now try to reset password
     new_password = '******'
     headers = make_headers()
     rv = self.app.post(
         '/api/resetpassword',
         data=json.dumps({'key': email_key, 'password': new_password}),
         headers=headers)
     assert(rv.status_code==200)
     # Check that we can't authenticate with email and old password
     headers = make_headers(email=sample_userA['email'], password=sample_userA['password'])
     rv = self.app.get('/api/requestapikey/', headers=headers)
     assert(rv.status_code == 401)
     # Check that we can authenticate with email and new password
     headers = make_headers(email=sample_userA['email'], password=new_password)
     rv = self.app.get('/api/requestapikey/', headers=headers)
     assert(rv.status_code == 200)
예제 #5
0
def send_conversation_message(message):
    logger.debug('send_conversation_email begins')
    error_message = ''
    sender_user = message.sender_user
    conversation = message.get_conversation()
    subject = None
    subject = conversation.title
    from_address = message.generate_from_address()
    to_address = message.receiver_user().confirmed_email
    conversation_url = '{0}/api/conversation/{1}'.format(
        config.BASEURL, conversation.id)
    content = append_conversation_link(message.content, conversation)
    logger.info('Sending conversation message with content - {}'.format(content))
    if not to_address:
        error_message = 'Recipient has not confirmed their email address'
    else:
        email = mail.Email(
            from_address=from_address,
            to_address=to_address,
            subject=subject,
            content=content,
            new_content=content
        )
        error_message = mail.get_mailer().send(email)
    return error_message
예제 #6
0
def send_event_reminder_message(event):
    share = event.share
    receivers = [share.educator, share.community_partner]
    other_users = [share.community_partner, share.educator]
    from_address = config.DONOTREPLY_EMAIL_ADDRESS
    event_details = EVENT_EDIT_TEMPLATE.format(event=event)
    url = share.conversation.get_url()
    subject = 'Reminder for Share on {}'.format(
        time_format.to_pretty(event.datetime_start))
    error_messages = []
    for receiver, other_user in zip(receivers, other_users):
        content = EVENT_REMINDER_TEMPLATE.format(
            share=share, eventdetails=event_details, url=url,
            other_user=other_user)
        to_address = receiver.confirmed_email
        if not to_address:
            logger.warning('Will not send event reminder to unconfirmed email address.')
            error_message = '{0} is not a confirmed email address'.format(
                receiver.email)
        else:
            email = mail.Email(
                from_address=from_address,
                to_address=to_address,
                subject=subject,
                content=content,
                new_content=content
            )
            error_message = mail.get_mailer().send(email)
        error_messages.append(error_message)
    combined_error_message = ', '.join(
        [e for e in error_messages if e is not None])
    return combined_error_message
예제 #7
0
 def sign_up(self, user_data):
     data = {
         'password': user_data['password'],
         'user': user_data,
         }
     serialized = json.dumps(data)
     headers = [('Content-Type', 'application/json')]
     rv = self.app.post('/api/usersignup', data=serialized, headers=headers)
     assert(rv.status_code == 200)
     data = json.loads(rv.data.decode('utf8'))
     user_id = data['data']['id']
     api_key = data['apiKey']
     authorization_header = 'Basic:api:{0}'.format(api_key)
     headers = [('Authorization', authorization_header)]
     # Create an authentication header
     # And try to retrieve user
     rv = self.app.get('/api/user/{0}'.format(user_id), headers=headers)
     assert(rv.status_code == 200)
     data = json.loads(rv.data.decode('utf8'))
     # User details should match
     compare_data(user_data, data['data'], exclusions=['password'])
     mailer = mail.get_mailer()
     # We should have one email in queue (email confimation from signup)
     assert(len(mailer.queue) == 1)
     email = mailer.pop()
     links = email.find_links()
     assert(len(links)==1)
     email_key = re.search('key=(.*)', links[0]).groups()[0]
     return user_id, api_key, email_key
예제 #8
0
def request_password_reset(user):
    secret_info = {
        'userId': user.id,
        'action': 'password_reset',
    }
    hours_duration = 48
    secret = Secret.create_secret(secret_info, hours_duration)
    url = '{BASEURL}/#/resetpassword?key={secret_key}'.format(
        BASEURL=config.BASEURL,
        secret_key=secret.key,
    )
    content = '''<p>We received a request to reset your password for CommunityShare.</p>
    
<p>To reset your password please click on the following link and follow the instructions.</p>
    
<a href={url}>{url}</a>
    
<p>If you cannot click on the link copy it into the addressbar of your browser.</p>
'''
    content = content.format(url=url)
    email = mail.Email(
        from_address=config.DONOTREPLY_EMAIL_ADDRESS,
        to_address=user.email,
        subject='CommunityShare Password Reset Request',
        content=content,
        new_content=content,
    )
    error_message = mail.get_mailer().send(email)
    return error_message
예제 #9
0
def send_conversation_message(message):
    logger.debug('send_conversation_email begins')
    error_message = ''
    sender_user = message.sender_user
    conversation = message.get_conversation()
    subject = None
    subject = conversation.title
    from_address = message.generate_from_address()
    to_address = message.receiver_user().confirmed_email
    conversation_url = '{0}/api/conversation/{1}'.format(
        config.BASEURL, conversation.id)
    content = append_conversation_link(message.content, conversation)
    logger.info(
        'Sending conversation message with content - {}'.format(content))
    if not to_address:
        error_message = 'Recipient has not confirmed their email address'
    else:
        email = mail.Email(
            from_address=from_address,
            to_address=to_address,
            subject=subject,
            content=content,
            new_content=content,
        )
        error_message = mail.get_mailer().send(email)
    return error_message
예제 #10
0
def request_signup_email_confirmation(user, template=None, subject=None):
    secret_info = {
        'userId': user.id,
        'email': user.email,
        'action': 'email_confirmation',
    }
    hours_duration = 24 * 14
    secret = Secret.create_secret(secret_info, hours_duration)
    url = '{BASEURL}/#/confirmemail?key={secret_key}'.format(
        BASEURL=config.BASEURL,
        secret_key=secret.key,
    )
    if template is None:
        template = '''<p>A community share account has been created and attached to this email address.<p>

        <p>To confirm that you created the account, please click on the following link.</p>

        <p><a href={url}>{url}</a></p>

        <p>If you did not create this account, simply ignore this email.</p>
'''
    content = template.format(url=url)
    if subject is None:
        subject = 'CommunityShare Account Creation'
    email = mail.Email(from_address=config.DONOTREPLY_EMAIL_ADDRESS,
                       to_address=user.email,
                       subject=subject,
                       content=content,
                       new_content=content)
    error_message = mail.get_mailer().send(email)
    return error_message
예제 #11
0
def request_signup_email_confirmation(user):
    secret_info = {
        'userId': user.id,
        'email': user.email,
        'action': 'email_confirmation',
    }
    hours_duration = 48
    secret = Secret.create_secret(secret_info, hours_duration)
    content = '''A community share account has been created and attached to this email address.

To confirm that you created the account, please click on the following link.

{BASEURL}/#/confirmemail?key={secret_key}

If you did not create this account, simply ignore this email.
'''
    content = content.format(BASEURL=config.BASEURL, secret_key=secret.key)
    email = mail.Email(
        from_address=config.DONOTREPLY_EMAIL_ADDRESS,
        to_address=user.email,
        subject='CommunityShare Account Creation',
        content=content,
        new_content=content
    )
    error_message = mail.get_mailer().send(email)
    return error_message
예제 #12
0
def request_password_reset(user):
    secret_info = {
        'userId': user.id,
        'action': 'password_reset',
    }
    hours_duration = 48
    secret = Secret.create_secret(secret_info, hours_duration)
    content = '''We received a request to reset your password for CommunityShare.
    
To reset your password please click on the following link and follow the instructions.
    
{BASEURL}/#/resetpassword?key={secret_key}
    
If you cannot click on the link copy it into the addressbar of your browser.
'''
    content = content.format(BASEURL=config.BASEURL, secret_key=secret.key)
    if not user.email_confirmed:
        error_message = 'The email address is not confirmed.'
    else:
        email = mail.Email(
            from_address=config.DONOTREPLY_EMAIL_ADDRESS,
            to_address=user.confirmed_email,
            subject='CommunityShare Password Reset Request',
            content=content,
            new_content=content,
        )
        error_message = mail.get_mailer().send(email)
    return error_message
예제 #13
0
def send_event_reminder_message(event):
    share = event.share
    receivers = [share.educator, share.community_partner]
    other_users = [share.community_partner, share.educator]
    from_address = config.DONOTREPLY_EMAIL_ADDRESS
    event_details = EVENT_EDIT_TEMPLATE.render(event=event)
    url = share.conversation.get_url()
    subject = 'Reminder for Share on {}'.format(
        time_format.to_pretty(event.datetime_start))
    error_messages = []
    for receiver, other_user in zip(receivers, other_users):
        content = EVENT_REMINDER_TEMPLATE.render(
            share=share,
            eventdetails=event_details,
            url=url,
            other_user=other_user,
        )
        to_address = receiver.confirmed_email
        if not to_address:
            logger.warning(
                'Will not send event reminder to unconfirmed email address.')
            error_message = '{0} is not a confirmed email address'.format(
                receiver.email)
        else:
            email = mail.Email(from_address=from_address,
                               to_address=to_address,
                               subject=subject,
                               content=content,
                               new_content=content)
            error_message = mail.get_mailer().send(email)
        error_messages.append(error_message)
    combined_error_message = ', '.join(
        [e for e in error_messages if e is not None])
    return combined_error_message
예제 #14
0
 def test_reminders(self):
     user_datas = {
         'userA': sample_userA,
         'userB': sample_userB,
     }
     user_ids, user_headers = self.create_users(user_datas)
     searchA_id, searchB_id = self.create_searches(user_ids, user_headers)
     conversation_data = self.make_conversation(
         user_headers['userA'], search_id=searchA_id, title='Trip to moon.',
         userA_id=user_ids['userA'], userB_id=user_ids['userB'])
     conversation_id = conversation_data['id']
     share_data = self.make_share(
         user_headers['userA'], conversation_id,
         educator_user_id=user_ids['userA'],
         community_partner_user_id=user_ids['userB'],
         starting_in_hours=0.5)
     mailer = mail.get_mailer()
     while mailer.queue:
         mailer.pop()
     events = EventReminder.get_oneday_reminder_events()
     assert(len(events) == 1)
     worker.work_loop(target_time_between_calls=datetime.timedelta(seconds=1),
                      max_loops=2)
     events = EventReminder.get_oneday_reminder_events()
     assert(len(events) == 0)
     # Two reminder emails should have been sent.
     assert(len(mailer.queue) == 2)
     email1 = mailer.pop()
     email2 = mailer.pop()
     expected_email_addresses = set([sample_userA['email'], sample_userB['email']])
     rcvd_email_addresses = set([email1.to_address, email2.to_address])
     assert(expected_email_addresses == rcvd_email_addresses)
예제 #15
0
def send_share_message(share, editer, new_share=False, is_confirmation=False, is_delete=False):
    receivers = [share.conversation.userA, share.conversation.userB]
    receivers = [r for r in receivers if (editer.id != r.id)]
    from_address = config.DONOTREPLY_EMAIL_ADDRESS
    event_details = "".join([EVENT_EDIT_TEMPLATE.format(event=event) for event in share.events])
    url = share.conversation.get_url()
    if is_confirmation:
        subject = "Share Details Confirmed: {0}".format(share.title)
        content = SHARE_CONFIRMATION_TEMPLATE.format(share=share, eventdetails=event_details, url=url, editer=editer)
    elif is_delete:
        subject = "Share Canceled: {0}".format(share.title)
        content = SHARE_DELETION_TEMPLATE.format(share=share, eventdetails=event_details, url=url, editer=editer)
    elif new_share:
        subject = "Share Details Suggested: {0}".format(share.title)
        content = SHARE_CREATION_TEMPLATE.format(share=share, eventdetails=event_details, url=url, editer=editer)
    else:
        subject = "Share Details Edited: {0}".format(share.title)
        content = SHARE_EDIT_TEMPLATE.format(share=share, eventdetails=event_details, url=url, editer=editer)
    error_messages = []
    for receiver in receivers:
        to_address = receiver.confirmed_email
        if not to_address:
            error_message = "{0} is not a confirmed email address".format(receiver.email)
        else:
            email = mail.Email(
                from_address=from_address, to_address=to_address, subject=subject, content=content, new_content=content
            )
            error_message = mail.get_mailer().send(email)
        error_messages.append(error_message)
    combined_error_message = ", ".join([e for e in error_messages if e is not None])
    return combined_error_message
예제 #16
0
 def test_account_deletion(self):
     user_datas = {
         'userA': sample_userA,
         'userB': sample_userB,
     }
     user_ids, user_headers = self.create_users(user_datas)
     searchA_id, searchB_id = self.create_searches(user_ids, user_headers)
     conversation_data = self.make_conversation(
         user_headers['userA'],
         search_id=searchA_id,
         title='Trip to moon.',
         userA_id=user_ids['userA'],
         userB_id=user_ids['userB'],
     )
     conversation_id = conversation_data['id']
     share_data = self.make_share(
         user_headers['userA'],
         conversation_id,
         educator_user_id=user_ids['userA'],
         community_partner_user_id=user_ids['userB'],
         starting_in_hours=0.5,
     )
     mailer = mail.get_mailer()
     while mailer.queue:
         mailer.pop()
     # userB is deleting their account
     rv = self.app.delete(
         '/api/user/{0}'.format(user_ids['userB']),
         headers=user_headers['userB'],
     )
     self.assertEqual(rv.status_code, 200)
     # Emails should have been sent to userB (confirming deletion)
     # and UserA since they had an event scheduled.
     self.assertEqual(len(mailer.queue), 2)
     # userB should not longer be able to do things.
     data = {
         'searcher_user_id': user_ids['userB'],
         'searcher_role': 'educator',
         'searching_for_role': 'partner',
         'labels': 'Whatever',
         'zipcode': 12345
     }
     serialized = json.dumps(data)
     rv = self.app.post('/api/search',
                        data=serialized,
                        headers=user_headers['userB'])
     self.assertEqual(rv.status_code, 401)
     # And we shouldn't be able to login anymore
     headers = make_headers(email=sample_userB['email'],
                            password=sample_userB['password'])
     rv = self.app.get('/api/requestapikey/', headers=headers)
     self.assertEqual(rv.status_code, 404)
예제 #17
0
 def setUp(self):
     config.load_config('./config.dev.json')
     config.MAILER_TYPE = 'QUEUE'
     config.DB_CONNECTION = 'sqlite:///{}'.format(self.SQLLITE_FILE)
     # When config.load_config is called, it sets self as the config in the
     # global store. Since we have mutated the config manually, we need to
     # re-set_config it in store.
     store.set_config(config)
     setup.init_db()
     # Clear mail queue
     mailer = mail.get_mailer()
     while len(mailer.queue):
         mailer.pop()
     self.app = app.make_app().test_client()
예제 #18
0
def send_account_deletion_message(user):
    admin_email = config.SUPPORT_EMAIL_ADDRESS
    subject = "Community Share Account Deletion"
    content = ACCOUNT_DELETION_TEMPLATE.format(admin_email=admin_email)
    to_address = user.confirmed_email
    from_address = config.SUPPORT_EMAIL_ADDRESS
    if not to_address:
        error_message = "{0} is not a confirmed email address".format(user.email)
    else:
        email = mail.Email(
            from_address=from_address, to_address=to_address, subject=subject, content=content, new_content=content
        )
        error_message = mail.get_mailer().send(email)
    return error_message
예제 #19
0
def send_partner_deletion_message(user, canceled_user, conversation):
    subject = "Community Share Account Deletion"
    url = conversation.get_url()
    content = PARTNER_DELETION_TEMPLATE.format(canceled_user=canceled_user, url=url)
    to_address = user.confirmed_email
    from_address = config.DONOTREPLY_EMAIL_ADDRESS
    if not to_address:
        error_message = "{0} is not a confirmed email address".format(receiver.email)
    else:
        email = mail.Email(
            from_address=from_address, to_address=to_address, subject=subject, content=content, new_content=content
        )
        error_message = mail.get_mailer().send(email)
    return error_message
예제 #20
0
 def setUp(self):
     config.load_config('./config.dev.json')
     config.MAILER_TYPE = 'QUEUE'
     config.DB_CONNECTION = 'sqlite:///{}'.format(self.SQLLITE_FILE)
     # When config.load_config is called, it sets self as the config in the
     # global store. Since we have mutated the config manually, we need to
     # re-set_config it in store.
     store.set_config(config)
     setup.init_db()
     # Clear mail queue
     mailer = mail.get_mailer()
     while len(mailer.queue):
         mailer.pop()
     self.app = app.make_app().test_client()
예제 #21
0
 def test_account_deletion(self):
     user_datas = {
         'userA': sample_userA,
         'userB': sample_userB,
     }
     user_ids, user_headers = self.create_users(user_datas)
     searchA_id, searchB_id = self.create_searches(user_ids, user_headers)
     conversation_data = self.make_conversation(
         user_headers['userA'],
         search_id=searchA_id,
         title='Trip to moon.',
         userA_id=user_ids['userA'],
         userB_id=user_ids['userB'],
     )
     conversation_id = conversation_data['id']
     share_data = self.make_share(
         user_headers['userA'],
         conversation_id,
         educator_user_id=user_ids['userA'],
         community_partner_user_id=user_ids['userB'],
         starting_in_hours=0.5,
     )
     mailer = mail.get_mailer()
     while mailer.queue:
         mailer.pop()
     # userB is deleting their account
     rv = self.app.delete(
         '/api/user/{0}'.format(user_ids['userB']),
         headers=user_headers['userB'],
     )
     self.assertEqual(rv.status_code, 200)
     # Emails should have been sent to userB (confirming deletion)
     # and UserA since they had an event scheduled.
     self.assertEqual(len(mailer.queue), 2)
     # userB should not longer be able to do things.
     data = {
         'searcher_user_id': user_ids['userB'],
         'searcher_role': 'educator',
         'searching_for_role': 'partner',
         'labels': 'Whatever',
         'zipcode': 12345
     }
     serialized = json.dumps(data)
     rv = self.app.post('/api/search', data=serialized, headers=user_headers['userB'])
     self.assertEqual(rv.status_code, 401)
     # And we shouldn't be able to login anymore
     headers = make_headers(email=sample_userB['email'], password=sample_userB['password'])
     rv = self.app.get('/api/requestapikey/', headers=headers)
     self.assertEqual(rv.status_code, 404)
예제 #22
0
def send_notify_share_creation(share, requester):
    to_address = config.NOTIFY_EMAIL_ADDRESS
    from_address = config.DONOTREPLY_EMAIL_ADDRESS
    event_details = "".join([EVENT_EDIT_TEMPLATE.format(event=event) for event in share.events])
    url = share.conversation.get_url()
    subject = "Share Created: {0}".format(share.title)
    content = NOTIFY_SHARE_CREATION_TEMPLATE.format(share=share, eventdetails=event_details, url=url)
    if not to_address:
        error_message = "Recipient has not confirmed their email address"
    else:
        email = mail.Email(
            from_address=from_address, to_address=to_address, subject=subject, content=content, new_content=content
        )
        error_message = mail.get_mailer().send(email)
    return error_message
예제 #23
0
def send_review_reminder_message(user, event):
    subject = "Review Community Share Event"
    url = event.get_url()
    event_details = EVENT_EDIT_TEMPLATE.format(event=event)
    content = REVIEW_REMINDER_TEMPLATE.format(url=url, share=event.share, eventdetails=event_details)
    to_address = user.confirmed_email
    from_address = config.DONOTREPLY_EMAIL_ADDRESS
    if not to_address:
        error_message = "{0} is not a confirmed email address".format(receiver.email)
    else:
        email = mail.Email(
            from_address=from_address, to_address=to_address, subject=subject, content=content, new_content=content
        )
        error_message = mail.get_mailer().send(email)
    return error_message
예제 #24
0
    def receive_email():

        logger.debug('Received an email.')

        if config.MAILER_TYPE == 'MAILGUN':
            verify = True
        else:
            verify = False
        email = Email.from_mailgun_data(request.values, verify=verify)
        logger.info('Received an email with content "{}"'.format(
            email.content))

        message = None
        message_id = Message.process_from_address(email.to_address)
        if message_id is not None:
            message = store.session.query(Message).filter_by(
                id=message_id).first()
        if message is None:
            logger.warning(
                'Received an email but did not find corresponding message.')
        else:
            logger.debug('Creating a new email to send')
            # Create a new message
            new_message = Message(
                conversation_id=message.conversation_id,
                sender_user_id=message.receiver_user().id,
                content=email.new_content,
            )
            store.session.add(new_message)
            store.session.commit()
            # Create an email to send to the recipient
            forward_to_address = message.sender_user.email
            forward_from_address = new_message.generate_from_address()
            forward_content = append_conversation_link(email.content,
                                                       message.conversation)
            forward_new_content = append_conversation_link(
                email.new_content, message.conversation)
            forward_email = Email(
                from_address=forward_from_address,
                to_address=forward_to_address,
                subject=email.subject,
                content=forward_content,
                new_content=forward_new_content,
            )
            error_message = get_mailer().send(forward_email)
        response = base_routes.make_OK_response()
        return response
예제 #25
0
def send_account_deletion_message(user):
    admin_email = config.SUPPORT_EMAIL_ADDRESS
    subject = 'Community Share Account Deletion'
    content = ACCOUNT_DELETION_TEMPLATE.render(admin_email=admin_email)
    to_address = user.confirmed_email
    from_address = config.SUPPORT_EMAIL_ADDRESS
    if not to_address:
        error_message = '{0} is not a confirmed email address'.format(
            user.email)
    else:
        email = mail.Email(from_address=from_address,
                           to_address=to_address,
                           subject=subject,
                           content=content,
                           new_content=content)
        error_message = mail.get_mailer().send(email)
    return error_message
예제 #26
0
    def receive_email():

        logger.debug('Received an email.')

        if config.MAILER_TYPE == 'MAILGUN':
            verify = True
        else:
            verify = False
        email = Email.from_mailgun_data(request.values, verify=verify)
        logger.info('Received an email with content "{}"'.format(email.content))

        message = None
        message_id = Message.process_from_address(email.to_address)
        if message_id is not None:
            message = store.session.query(Message).filter_by(id=message_id).first()
        if message is None:
            logger.warning('Received an email but did not find corresponding message.')
        else:
            logger.debug('Creating a new email to send')
            # Create a new message
            new_message = Message(
                conversation_id=message.conversation_id,
                sender_user_id=message.receiver_user().id,
                content=email.new_content,
            )
            store.session.add(new_message)
            store.session.commit()
            # Create an email to send to the recipient
            forward_to_address = message.sender_user.email
            forward_from_address = new_message.generate_from_address()
            forward_content = append_conversation_link(email.content, message.conversation)
            forward_new_content = append_conversation_link(email.new_content, message.conversation)
            forward_email = Email(
                from_address=forward_from_address,
                to_address=forward_to_address,
                subject=email.subject,
                content=forward_content,
                new_content=forward_new_content,
            )
            error_message = get_mailer().send(forward_email)
        response = base_routes.make_OK_response()
        return response
예제 #27
0
def send_partner_deletion_message(user, canceled_user, conversation):
    subject = 'Community Share Account Deletion'
    url = conversation.get_url()
    content = PARTNER_DELETION_TEMPLATE.render(canceled_user=canceled_user,
                                               url=url)
    if user is None:
        error_message = '{0} other user in share does not exist'
    else:
        to_address = user.confirmed_email
        from_address = config.DONOTREPLY_EMAIL_ADDRESS
        if not to_address:
            error_message = '{0} is not a confirmed email address'.format(
                receiver.email)
        else:
            email = mail.Email(from_address=from_address,
                               to_address=to_address,
                               subject=subject,
                               content=content,
                               new_content=content)
            error_message = mail.get_mailer().send(email)
    return error_message
예제 #28
0
 def test_password_reset(self):
     # Signup userA
     userA_id, userA_api_key, userA_email_key = self.sign_up(sample_userA)
     self.confirm_email(userA_email_key)
     rv = self.app.get('/api/requestresetpassword/{0}'.format(
         sample_userA['email']))
     self.assertEqual(rv.status_code, 200)
     mailer = mail.get_mailer()
     # Check that we can authenticate with email and password
     headers = make_headers(email=sample_userA['email'],
                            password=sample_userA['password'])
     rv = self.app.get('/api/requestapikey', headers=headers)
     self.assertEqual(rv.status_code, 200)
     # We should have one email in queue (email from password reset request)
     self.assertEqual(len(mailer.queue), 1)
     email = mailer.pop()
     links = email.find_links()
     self.assertEqual(len(links), 1)
     email_key = re.search('key=([a-zA-Z0-9]*)', links[0]).groups()[0]
     logger.debug('email key is {0}'.format(email_key))
     # Now try to reset password
     new_password = '******'
     headers = make_headers()
     rv = self.app.post('/api/resetpassword',
                        data=json.dumps({
                            'key': email_key,
                            'password': new_password,
                        }),
                        headers=headers)
     self.assertEqual(rv.status_code, 200)
     # Check that we can't authenticate with email and old password
     headers = make_headers(email=sample_userA['email'],
                            password=sample_userA['password'])
     rv = self.app.get('/api/requestapikey', headers=headers)
     self.assertEqual(rv.status_code, 401)
     # Check that we can authenticate with email and new password
     headers = make_headers(email=sample_userA['email'],
                            password=new_password)
     rv = self.app.get('/api/requestapikey', headers=headers)
     self.assertEqual(rv.status_code, 200)
예제 #29
0
 def test_reminders(self):
     user_datas = {
         'userA': sample_userA,
         'userB': sample_userB,
     }
     user_ids, user_headers = self.create_users(user_datas)
     searchA_id, searchB_id = self.create_searches(user_ids, user_headers)
     conversation_data = self.make_conversation(
         user_headers['userA'],
         search_id=searchA_id,
         title='Trip to moon.',
         userA_id=user_ids['userA'],
         userB_id=user_ids['userB'],
     )
     conversation_id = conversation_data['id']
     share_data = self.make_share(
         user_headers['userA'],
         conversation_id,
         educator_user_id=user_ids['userA'],
         community_partner_user_id=user_ids['userB'],
         starting_in_hours=0.5,
     )
     mailer = mail.get_mailer()
     while mailer.queue:
         mailer.pop()
     events = EventReminder.get_oneday_reminder_events()
     self.assertEqual(len(events), 1)
     worker.work_loop(
         target_time_between_calls=datetime.timedelta(seconds=1),
         max_loops=2)
     events = EventReminder.get_oneday_reminder_events()
     self.assertEqual(len(events), 0)
     # Two reminder emails should have been sent.
     self.assertEqual(len(mailer.queue), 2)
     email1 = mailer.pop()
     email2 = mailer.pop()
     expected_email_addresses = set(
         [sample_userA['email'], sample_userB['email']])
     rcvd_email_addresses = set([email1.to_address, email2.to_address])
     self.assertEqual(expected_email_addresses, rcvd_email_addresses)
예제 #30
0
def send_notify_share_creation(share, requester):
    to_address = config.NOTIFY_EMAIL_ADDRESS
    from_address = config.DONOTREPLY_EMAIL_ADDRESS
    event_details = ''.join(
        [EVENT_EDIT_TEMPLATE.render(event=event) for event in share.events])
    url = share.conversation.get_url()
    subject = 'Share Created: {0}'.format(share.title)
    content = NOTIFY_SHARE_CREATION_TEMPLATE.render(
        share=share,
        eventdetails=event_details,
        url=url,
    )
    if not to_address:
        error_message = 'Recipient has not confirmed their email address'
    else:
        email = mail.Email(from_address=from_address,
                           to_address=to_address,
                           subject=subject,
                           content=content,
                           new_content=content)
        error_message = mail.get_mailer().send(email)
    return error_message
예제 #31
0
def send_review_reminder_message(user, event):
    subject = 'Review Community Share Event'
    url = event.get_url()
    event_details = EVENT_EDIT_TEMPLATE.render(event=event)
    content = REVIEW_REMINDER_TEMPLATE.render(
        url=url,
        share=event.share,
        eventdetails=event_details,
    )
    to_address = user.confirmed_email
    from_address = config.DONOTREPLY_EMAIL_ADDRESS
    if not to_address:
        error_message = '{0} is not a confirmed email address'.format(
            receiver.email)
    else:
        email = mail.Email(from_address=from_address,
                           to_address=to_address,
                           subject=subject,
                           content=content,
                           new_content=content)
        error_message = mail.get_mailer().send(email)
    return error_message
예제 #32
0
    def sign_up(self, user_data):
        data = {
            'password': user_data['password'],
            'user': user_data,
        }
        serialized = json.dumps(data)
        headers = [('Content-Type', 'application/json')]
        rv = self.app.post('/api/usersignup', data=serialized, headers=headers)
        self.assertEqual(rv.status_code, 200)
        data = json.loads(rv.data.decode('utf8'))
        user_id = data['data']['id']
        api_key = data['apiKey']
        authorization_header = 'Basic:api:{0}'.format(api_key)
        headers = [('Authorization', authorization_header)]
        # Create an authentication header
        # And try to retrieve user
        rv = self.app.get('/api/user/{0}'.format(user_id), headers=headers)
        self.assertEqual(rv.status_code, 200)
        data = json.loads(rv.data.decode('utf8'))

        # User details should match
        # yapf: disable
        relevant_keys = user_data.keys() - {'password'}
        self.assertDictEqual(
            {k: v for k, v in user_data.items() if k in relevant_keys},
            {k: v for k, v in data['data'].items() if k in relevant_keys}
        )
        # yapf: enable

        mailer = mail.get_mailer()
        # We should have one email in queue (email confimation from signup)
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        links = email.find_links()
        self.assertEqual(len(links), 1)
        email_key = re.search('key=([a-zA-Z0-9]*)', links[0]).groups()[0]
        return user_id, api_key, email_key
예제 #33
0
    def sign_up(self, user_data):
        data = {
            'password': user_data['password'],
            'user': user_data,
        }
        serialized = json.dumps(data)
        headers = [('Content-Type', 'application/json')]
        rv = self.app.post('/api/usersignup', data=serialized, headers=headers)
        self.assertEqual(rv.status_code, 200)
        data = json.loads(rv.data.decode('utf8'))
        user_id = data['data']['id']
        api_key = data['apiKey']
        authorization_header = 'Basic:api:{0}'.format(api_key)
        headers = [('Authorization', authorization_header)]
        # Create an authentication header
        # And try to retrieve user
        rv = self.app.get('/api/user/{0}'.format(user_id), headers=headers)
        self.assertEqual(rv.status_code, 200)
        data = json.loads(rv.data.decode('utf8'))

        # User details should match
        # yapf: disable
        relevant_keys = user_data.keys() - {'password'}
        self.assertDictEqual(
            {k: v for k, v in user_data.items() if k in relevant_keys},
            {k: v for k, v in data['data'].items() if k in relevant_keys}
        )
        # yapf: enable

        mailer = mail.get_mailer()
        # We should have one email in queue (email confimation from signup)
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        links = email.find_links()
        self.assertEqual(len(links), 1)
        email_key = re.search('key=([a-zA-Z0-9]*)', links[0]).groups()[0]
        return user_id, api_key, email_key
예제 #34
0
 def test_one(self):
     # Make sure we get an OK when requesting index.
     rv = self.app.get('/')
     self.assertEqual(rv.status_code, 200)
     # Now try to get user from API
     # Expect forbidden (401)
     rv = self.app.get('/api/user/1')
     self.assertEqual(rv.status_code, 401)
     # Now sign up UserA
     userA_id, userA_api_key, userA_email_key = self.sign_up(sample_userA)
     # Get userA and check that email is not confirmed
     userA_headers = make_headers(userA_api_key)
     rv = self.app.get('/api/user/1', headers=userA_headers)
     self.assertEqual(rv.status_code, 200)
     data = json.loads(rv.data.decode('utf8'))['data']
     # Confirm email
     self.confirm_email(userA_email_key)
     # Get userA and check that email is confirmed
     rv = self.app.get('/api/user/1', headers=userA_headers)
     self.assertEqual(rv.status_code, 200)
     data = json.loads(rv.data.decode('utf8'))['data']
     self.assertTrue(data['email_confirmed'])
     # Sign up UserB
     userB_id, userB_api_key, userB_email_key = self.sign_up(sample_userB)
     self.confirm_email(userB_email_key)
     # Create Searches
     userB_headers = make_headers(api_key=userB_api_key)
     user_headers = {
         'userA': userA_headers,
         'userB': userB_headers,
     }
     user_ids = {'userA': userA_id, 'userB': userB_id}
     searchA_id, searchB_id = self.create_searches(user_ids, user_headers)
     # Get all the results for userA's search
     rv = self.app.get(
         '/api/search/{0}/0/results'.format(searchA_id),
         headers=user_headers['userA'],
     )
     data = json.loads(rv.data.decode('utf8'))
     searches = data['data']
     self.assertEqual(len(searches), 1)
     self.assertEqual(searches[0]['searcher_user_id'], userB_id)
     # Now userA starts a conversation with userB
     conversation_title = 'Trip to moon.'
     conversation_data = self.make_conversation(
         user_headers['userA'],
         search_id=searchA_id,
         title=conversation_title,
         userA_id=user_ids['userA'],
         userB_id=user_ids['userB'],
     )
     conversation_id = conversation_data['id']
     # And send the first message
     message_content = 'Are you interested in going to the moon?'
     rv = self.send_message(
         conversation_id=conversation_id,
         sender_user_id=userA_id,
         content=message_content,
         api_key=userA_api_key,
     )
     data = json.loads(rv.data.decode('utf8'))
     message_id = data['data']['id']
     mailer = mail.get_mailer()
     # We should have one email in queue (email about new message)
     self.assertEqual(len(mailer.queue), 1)
     email = mailer.pop()
     self.assertEqual(email.subject, conversation_title)
     self.assertTrue(email.content.startswith(message_content))
     self.assertEqual(email.to_address, sample_userB['email'])
     new_reply_content = 'Sure, sounds great!'
     reply_email = email.make_reply(new_reply_content)
     self.assertEqual(reply_email.subject, conversation_title)
     self.assertTrue(reply_email.content.startswith(new_reply_content))
     self.assertEqual(reply_email.from_address, email.to_address)
     self.assertEqual(reply_email.to_address, email.from_address)
     # That email should contain a link to the conversation
     # We're not running the javascript so we can't test it properly.
     links = email.find_links()
     self.assertEqual(len(links), 1)
     chopped_link = chop_link(links[0])
     rv = self.app.get(chopped_link)
     self.assertEqual(rv.status_code, 200)
     # Send the reply email to our email API in the form of a Mailgun
     # request.
     rv = self.app.post('/api/email', data=reply_email.make_mailgun_data())
     self.assertEqual(rv.status_code, 200)
     # It should have been forwarded to the other user.
     self.assertEqual(len(mailer.queue), 1)
     email = mailer.pop()
     self.assertEqual(email.subject, conversation_title)
     self.assertTrue(email.content.startswith(new_reply_content))
     self.assertEqual(email.to_address, sample_userA['email'])
     # And we should now have two messages in the conversation
     # We'll hit the conversation API to confirm this.
     rv = self.app.get(
         '/api/conversation/{0}'.format(conversation_id),
         headers=user_headers['userA'],
     )
     rcvd_conversation_data = json.loads(rv.data.decode('utf8'))['data']
     self.assertEqual(rcvd_conversation_data['id'], conversation_id)
     self.assertEqual(rcvd_conversation_data['title'], conversation_title)
     messages_data = rcvd_conversation_data['messages']
     self.assertEqual(len(messages_data), 2)
     self.assertEqual(messages_data[0]['content'], message_content)
     self.assertEqual(messages_data[0]['sender_user_id'], userA_id)
     self.assertEqual(messages_data[1]['content'], new_reply_content)
     self.assertEqual(messages_data[1]['sender_user_id'], userB_id)
예제 #35
0
    def test_share(self):
        # Signup users and confirm emails
        user_datas = {
            'userA': sample_userA,
            'userB': sample_userB,
            'userC': sample_userC,
        }
        user_ids, user_headers = self.create_users(user_datas)
        user_headers['noone'] = make_headers()
        searchA_id, searchB_id = self.create_searches(user_ids, user_headers)
        conversation_data = self.make_conversation(
            user_headers['userA'],
            search_id=searchA_id,
            title='Trip to moon.',
            userA_id=user_ids['userA'],
            userB_id=user_ids['userB'],
        )
        conversation_id = conversation_data['id']
        # userA creates a share
        share_data = self.make_share(
            user_headers['userA'],
            conversation_id,
            educator_user_id=user_ids['userA'],
            community_partner_user_id=user_ids['userB'],
        )
        share_id = share_data['id']
        self.assertEqual(len(share_data['events']), 1)
        # This should send an email to userB that a share has been created.
        # This also sends an email to the "notify" address.
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 2)
        email = [email for email in mailer.queue if email.to_address == sample_userB['email']][0]
        mailer.queue.pop()
        mailer.queue.pop()
        self.assertEqual(email.to_address, sample_userB['email'])

        # Check link is valid
        links = email.find_links()
        self.assertEqual(len(links), 1)
        chopped_link = chop_link(links[0])
        rv = self.app.get(chopped_link)
        self.assertEqual(rv.status_code, 200)
        # We should not be able to get this share if unauthenticated
        rv = self.app.get('/api/share/{0}'.format(share_id), headers=user_headers['noone'])
        self.assertEqual(rv.status_code, 401)
        # Logged on users can access share info
        # FIXME: Need to check if this should be more private.
        rv = self.app.get('/api/share/{0}'.format(share_id), headers=user_headers['userC'])
        self.assertEqual(rv.status_code, 200)
        # User B should be able to access it.
        rv = self.app.get('/api/share/{0}'.format(share_id), headers=user_headers['userB'])
        self.assertEqual(rv.status_code, 200)
        share_data = json.loads(rv.data.decode('utf8'))['data']
        self.assertEqual(share_data['id'], share_id)
        self.assertTrue(share_data['educator_approved'])
        self.assertFalse(share_data['community_partner_approved'])
        # Now let's edit the share.
        share_data = {
            'description': 'Is the moon made of Cheese?  There is only one way to find out!',
        }
        serialized = json.dumps(share_data)
        # Unauthenticated person should not be able to edit it.
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['noone'],
            data=serialized,
        )
        self.assertEqual(rv.status_code, 401)
        # User C should not be able to edit it.
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['userC'],
            data=serialized,
        )
        self.assertEqual(rv.status_code, 403)
        # User B should be able to edit it.
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['userB'],
            data=serialized,
        )
        self.assertEqual(rv.status_code, 200)
        data = json.loads(rv.data.decode('utf8'))['data']
        # There should still be one event there.
        self.assertEqual(len(data['events']), 1)
        event_id = data['events'][0]['id']
        # This should send an email to userA that a share has been edited.
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        self.assertEqual(email.to_address, sample_userA['email'])
        # User B edits it and adds an additional event
        existing_event = data['events'][0]
        now = datetime.datetime.utcnow()
        starting = now + datetime.timedelta(hours=3)
        ending = now + datetime.timedelta(hours=4)
        data['events'].append(
            {
                'location': 'Somewhere Else',
                'datetime_start': time_format.to_iso8601(starting),
                'datetime_stop': time_format.to_iso8601(ending),
            }
        )
        serialized = json.dumps(data)
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['userB'],
            data=serialized,
        )
        data = json.loads(rv.data.decode('utf8'))['data']
        ids = set([e['id'] for e in data['events']])
        self.assertIn(event_id, ids)
        self.assertEqual(len(ids), 2)
        self.assertEqual(rv.status_code, 200)
        # This should send an email to userA that a share has been edited.
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        self.assertEqual(email.to_address, sample_userA['email'])
        # And who has given approval is switched.
        self.assertFalse(data['educator_approved'])
        self.assertTrue(data['community_partner_approved'])
        # User A can do a put with no changes to approve.
        serialized = json.dumps(data)
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['userA'],
            data=serialized,
        )
        self.assertEqual(rv.status_code, 200)
        data = json.loads(rv.data.decode('utf8'))['data']
        self.assertTrue(data['educator_approved'])
        self.assertTrue(data['community_partner_approved'])
        # This should send an email to userB that changes have been approved.
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        self.assertEqual(email.to_address, sample_userB['email'])
        # Now userB deletes the events
        share_data = {'events': []}
        serialized = json.dumps(share_data)
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['userB'],
            data=serialized,
        )
        self.assertEqual(rv.status_code, 200)
        data = json.loads(rv.data.decode('utf8'))['data']
        self.assertEqual(len(data['events']), 0)
        # User A should have received an email
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        self.assertEqual(email.to_address, sample_userA['email'])
        # UserA cancels the share
        rv = self.app.delete('api/share/{0}'.format(share_id), headers=user_headers['userA'])
        self.assertEqual(rv.status_code, 200)
        # User B should have received an email.
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        self.assertEqual(email.to_address, sample_userB['email'])
예제 #36
0
def send_share_message(
    share,
    editer,
    new_share=False,
    is_confirmation=False,
    is_delete=False,
):
    receivers = [share.conversation.userA, share.conversation.userB]
    receivers = [r for r in receivers if (editer.id != r.id)]
    from_address = config.DONOTREPLY_EMAIL_ADDRESS
    event_details = ''.join(
        [EVENT_EDIT_TEMPLATE.render(event=event) for event in share.events])
    url = share.conversation.get_url()
    if is_confirmation:
        subject = 'Share Details Confirmed: {0}'.format(share.title)
        content = SHARE_CONFIRMATION_TEMPLATE.render(
            share=share,
            eventdetails=event_details,
            url=url,
            editer=editer,
        )
    elif is_delete:
        subject = 'Share Canceled: {0}'.format(share.title)
        content = SHARE_DELETION_TEMPLATE.render(
            share=share,
            eventdetails=event_details,
            url=url,
            editer=editer,
        )
    elif new_share:
        subject = 'Share Details Suggested: {0}'.format(share.title)
        content = SHARE_CREATION_TEMPLATE.render(
            share=share,
            eventdetails=event_details,
            url=url,
            editer=editer,
        )
    else:
        subject = 'Share Details Edited: {0}'.format(share.title)
        content = SHARE_EDIT_TEMPLATE.render(
            share=share,
            eventdetails=event_details,
            url=url,
            editer=editer,
        )
    error_messages = []
    for receiver in receivers:
        to_address = receiver.confirmed_email
        if not to_address:
            error_message = '{0} is not a confirmed email address'.format(
                receiver.email)
        else:
            email = mail.Email(from_address=from_address,
                               to_address=to_address,
                               subject=subject,
                               content=content,
                               new_content=content)
            error_message = mail.get_mailer().send(email)
        error_messages.append(error_message)
    combined_error_message = ', '.join(
        [e for e in error_messages if e is not None])
    return combined_error_message
예제 #37
0
    def test_share(self):
        # Signup users and confirm emails
        user_datas = {
            'userA': sample_userA,
            'userB': sample_userB,
            'userC': sample_userC,
        }
        user_ids, user_headers = self.create_users(user_datas)
        user_headers['noone'] = make_headers()
        searchA_id, searchB_id = self.create_searches(user_ids, user_headers)
        conversation_data = self.make_conversation(
            user_headers['userA'],
            search_id=searchA_id,
            title='Trip to moon.',
            userA_id=user_ids['userA'],
            userB_id=user_ids['userB'],
        )
        conversation_id = conversation_data['id']
        # userA creates a share
        share_data = self.make_share(
            user_headers['userA'],
            conversation_id,
            educator_user_id=user_ids['userA'],
            community_partner_user_id=user_ids['userB'],
        )
        share_id = share_data['id']
        self.assertEqual(len(share_data['events']), 1)
        # This should send an email to userB that a share has been created.
        # This also sends an email to the "notify" address.
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 2)
        email = [
            email for email in mailer.queue
            if email.to_address == sample_userB['email']
        ][0]
        mailer.queue.pop()
        mailer.queue.pop()
        self.assertEqual(email.to_address, sample_userB['email'])

        # Check link is valid
        links = email.find_links()
        self.assertEqual(len(links), 1)
        chopped_link = chop_link(links[0])
        rv = self.app.get(chopped_link)
        self.assertEqual(rv.status_code, 200)
        # We should not be able to get this share if unauthenticated
        rv = self.app.get('/api/share/{0}'.format(share_id),
                          headers=user_headers['noone'])
        self.assertEqual(rv.status_code, 401)
        # Logged on users can access share info
        # FIXME: Need to check if this should be more private.
        rv = self.app.get('/api/share/{0}'.format(share_id),
                          headers=user_headers['userC'])
        self.assertEqual(rv.status_code, 200)
        # User B should be able to access it.
        rv = self.app.get('/api/share/{0}'.format(share_id),
                          headers=user_headers['userB'])
        self.assertEqual(rv.status_code, 200)
        share_data = json.loads(rv.data.decode('utf8'))['data']
        self.assertEqual(share_data['id'], share_id)
        self.assertTrue(share_data['educator_approved'])
        self.assertFalse(share_data['community_partner_approved'])
        # Now let's edit the share.
        share_data = {
            'description':
            'Is the moon made of Cheese?  There is only one way to find out!',
        }
        serialized = json.dumps(share_data)
        # Unauthenticated person should not be able to edit it.
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['noone'],
            data=serialized,
        )
        self.assertEqual(rv.status_code, 401)
        # User C should not be able to edit it.
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['userC'],
            data=serialized,
        )
        self.assertEqual(rv.status_code, 403)
        # User B should be able to edit it.
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['userB'],
            data=serialized,
        )
        self.assertEqual(rv.status_code, 200)
        data = json.loads(rv.data.decode('utf8'))['data']
        # There should still be one event there.
        self.assertEqual(len(data['events']), 1)
        event_id = data['events'][0]['id']
        # This should send an email to userA that a share has been edited.
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        self.assertEqual(email.to_address, sample_userA['email'])
        # User B edits it and adds an additional event
        existing_event = data['events'][0]
        now = datetime.datetime.utcnow()
        starting = now + datetime.timedelta(hours=3)
        ending = now + datetime.timedelta(hours=4)
        data['events'].append({
            'location':
            'Somewhere Else',
            'datetime_start':
            time_format.to_iso8601(starting),
            'datetime_stop':
            time_format.to_iso8601(ending),
        })
        serialized = json.dumps(data)
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['userB'],
            data=serialized,
        )
        data = json.loads(rv.data.decode('utf8'))['data']
        ids = set([e['id'] for e in data['events']])
        self.assertIn(event_id, ids)
        self.assertEqual(len(ids), 2)
        self.assertEqual(rv.status_code, 200)
        # This should send an email to userA that a share has been edited.
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        self.assertEqual(email.to_address, sample_userA['email'])
        # And who has given approval is switched.
        self.assertFalse(data['educator_approved'])
        self.assertTrue(data['community_partner_approved'])
        # User A can do a put with no changes to approve.
        serialized = json.dumps(data)
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['userA'],
            data=serialized,
        )
        self.assertEqual(rv.status_code, 200)
        data = json.loads(rv.data.decode('utf8'))['data']
        self.assertTrue(data['educator_approved'])
        self.assertTrue(data['community_partner_approved'])
        # This should send an email to userB that changes have been approved.
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        self.assertEqual(email.to_address, sample_userB['email'])
        # Now userB deletes the events
        share_data = {'events': []}
        serialized = json.dumps(share_data)
        rv = self.app.put(
            '/api/share/{0}'.format(share_id),
            headers=user_headers['userB'],
            data=serialized,
        )
        self.assertEqual(rv.status_code, 200)
        data = json.loads(rv.data.decode('utf8'))['data']
        self.assertEqual(len(data['events']), 0)
        # User A should have received an email
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        self.assertEqual(email.to_address, sample_userA['email'])
        # UserA cancels the share
        rv = self.app.delete('api/share/{0}'.format(share_id),
                             headers=user_headers['userA'])
        self.assertEqual(rv.status_code, 200)
        # User B should have received an email.
        mailer = mail.get_mailer()
        self.assertEqual(len(mailer.queue), 1)
        email = mailer.pop()
        self.assertEqual(email.to_address, sample_userB['email'])
예제 #38
0
 def test_one(self):
     # Make sure we get an OK when requesting index.
     rv = self.app.get('/')
     self.assertEqual(rv.status_code, 200)
     # Now try to get user from API
     # Expect forbidden (401)
     rv = self.app.get('/api/user/1')
     self.assertEqual(rv.status_code, 401)
     # Now sign up UserA
     userA_id, userA_api_key, userA_email_key = self.sign_up(sample_userA)
     # Get userA and check that email is not confirmed
     userA_headers = make_headers(userA_api_key)
     rv = self.app.get('/api/user/1', headers=userA_headers)
     self.assertEqual(rv.status_code, 200)
     data = json.loads(rv.data.decode('utf8'))['data']
     # Confirm email
     self.confirm_email(userA_email_key)
     # Get userA and check that email is confirmed
     rv = self.app.get('/api/user/1', headers=userA_headers)
     self.assertEqual(rv.status_code, 200)
     data = json.loads(rv.data.decode('utf8'))['data']
     self.assertTrue(data['email_confirmed'])
     # Sign up UserB
     userB_id, userB_api_key, userB_email_key = self.sign_up(sample_userB)
     self.confirm_email(userB_email_key)
     # Create Searches
     userB_headers = make_headers(api_key=userB_api_key)
     user_headers = {
         'userA': userA_headers,
         'userB': userB_headers,
     }
     user_ids = {'userA': userA_id, 'userB': userB_id}
     searchA_id, searchB_id = self.create_searches(user_ids, user_headers)
     # Get all the results for userA's search
     rv = self.app.get(
         '/api/search/{0}/0/results'.format(searchA_id),
         headers=user_headers['userA'],
     )
     data = json.loads(rv.data.decode('utf8'))
     searches = data['data']
     self.assertEqual(len(searches), 1)
     self.assertEqual(searches[0]['searcher_user_id'], userB_id)
     # Now userA starts a conversation with userB
     conversation_title = 'Trip to moon.'
     conversation_data = self.make_conversation(
         user_headers['userA'],
         search_id=searchA_id,
         title=conversation_title,
         userA_id=user_ids['userA'],
         userB_id=user_ids['userB'],
     )
     conversation_id = conversation_data['id']
     # And send the first message
     message_content = 'Are you interested in going to the moon?'
     rv = self.send_message(
         conversation_id=conversation_id,
         sender_user_id=userA_id,
         content=message_content,
         api_key=userA_api_key,
     )
     data = json.loads(rv.data.decode('utf8'))
     message_id = data['data']['id']
     mailer = mail.get_mailer()
     # We should have one email in queue (email about new message)
     self.assertEqual(len(mailer.queue), 1)
     email = mailer.pop()
     self.assertEqual(email.subject, conversation_title)
     self.assertTrue(email.content.startswith(message_content))
     self.assertEqual(email.to_address, sample_userB['email'])
     new_reply_content = 'Sure, sounds great!'
     reply_email = email.make_reply(new_reply_content)
     self.assertEqual(reply_email.subject, conversation_title)
     self.assertTrue(reply_email.content.startswith(new_reply_content))
     self.assertEqual(reply_email.from_address, email.to_address)
     self.assertEqual(reply_email.to_address, email.from_address)
     # That email should contain a link to the conversation
     # We're not running the javascript so we can't test it properly.
     links = email.find_links()
     self.assertEqual(len(links), 1)
     chopped_link = chop_link(links[0])
     rv = self.app.get(chopped_link)
     self.assertEqual(rv.status_code, 200)
     # Send the reply email to our email API in the form of a Mailgun
     # request.
     rv = self.app.post('/api/email', data=reply_email.make_mailgun_data())
     self.assertEqual(rv.status_code, 200)
     # It should have been forwarded to the other user.
     self.assertEqual(len(mailer.queue), 1)
     email = mailer.pop()
     self.assertEqual(email.subject, conversation_title)
     self.assertTrue(email.content.startswith(new_reply_content))
     self.assertEqual(email.to_address, sample_userA['email'])
     # And we should now have two messages in the conversation
     # We'll hit the conversation API to confirm this.
     rv = self.app.get(
         '/api/conversation/{0}'.format(conversation_id),
         headers=user_headers['userA'],
     )
     rcvd_conversation_data = json.loads(rv.data.decode('utf8'))['data']
     self.assertEqual(rcvd_conversation_data['id'], conversation_id)
     self.assertEqual(rcvd_conversation_data['title'], conversation_title)
     messages_data = rcvd_conversation_data['messages']
     self.assertEqual(len(messages_data), 2)
     self.assertEqual(messages_data[0]['content'], message_content)
     self.assertEqual(messages_data[0]['sender_user_id'], userA_id)
     self.assertEqual(messages_data[1]['content'], new_reply_content)
     self.assertEqual(messages_data[1]['sender_user_id'], userB_id)
예제 #39
0
 def test_user_review(self):
     user_datas = {
         'userA': sample_userA,
         'userB': sample_userB,
         'userC': sample_userC,
     }
     user_ids, user_headers = self.create_users(user_datas)
     searchA_id, searchB_id = self.create_searches(user_ids, user_headers)
     conversation_data = self.make_conversation(
         user_headers['userA'], search_id=searchA_id, title='Trip to moon.',
         userA_id=user_ids['userA'], userB_id=user_ids['userB'])
     conversation_id = conversation_data['id']
     share_data = self.make_share(
         user_headers['userA'], conversation_id,
         educator_user_id=user_ids['userA'],
         community_partner_user_id=user_ids['userB'],
         starting_in_hours=0.5, force_past_events=False)
     # We shouldn't be able to save a review for the current event
     # because it is in the future
     share_id = share_data['id']
     eventA_id = share_data['events'][0]['id']
     review_data = {
         'event_id': eventA_id,
         'user_id': user_ids['userA'],
         'rating': 3,
     }
     serialized = json.dumps(review_data)
     rv = self.app.post('/api/user_review', data=serialized, headers=user_headers['userB'])
     assert(rv.status_code == 403)
     # Two reminder emails should have been sent.
     # This check is mostly here since we need to flush the emails out
     # to test review reminder emails later.
     mailer = mail.get_mailer()
     while mailer.queue:
         mailer.pop()
     worker.work_loop(target_time_between_calls=datetime.timedelta(seconds=1),
                      max_loops=2)
     assert(len(mailer.queue) == 2)
     while mailer.queue:
         mailer.pop()
     # Let's make another conversation and share this time but put event in past.
     conversation_data = self.make_conversation(
         user_headers['userA'], search_id=searchA_id, title='Trip to moon.',
         userA_id=user_ids['userA'], userB_id=user_ids['userB'])
     conversation_id = conversation_data['id']
     share_data = self.make_share(
         user_headers['userA'], conversation_id,
         educator_user_id=user_ids['userA'],
         community_partner_user_id=user_ids['userB'],
         starting_in_hours=-26, force_past_events=True)
     eventA_id = share_data['events'][0]['id']
     # We should receive an email telling us to review it.
     events = EventReminder.get_review_reminder_events()
     assert(len(events) == 1)
     while mailer.queue:
         mailer.pop()
     worker.work_loop(target_time_between_calls=datetime.timedelta(seconds=1),
                      max_loops=2)
     events = EventReminder.get_review_reminder_events()
     assert(len(events) == 0)
     # Two reminder emails should have been sent.
     assert(len(mailer.queue) == 2)
     # Now try to make a review for the wrong user
     review_data = {
         'event_id': eventA_id,
         'user_id': user_ids['userC'],
         'rating': 3,
         'review': 'Was really super'
     }
     serialized = json.dumps(review_data)
     rv = self.app.post('/api/user_review', data=serialized, headers=user_headers['userB'])
     assert(rv.status_code == 403)
     # Now try to make a review for oneself
     review_data = {
         'event_id': eventA_id,
         'user_id': user_ids['userB'],
         'rating': 3,
         'review': 'Was really super'
     }
     serialized = json.dumps(review_data)
     rv = self.app.post('/api/user_review', data=serialized, headers=user_headers['userB'])
     assert(rv.status_code == 403)
     # Now try to make a review with invalid rating
     review_data = {
         'event_id': eventA_id,
         'user_id': user_ids['userA'],
         'rating': 6,
         'review': 'Was really super'
     }
     serialized = json.dumps(review_data)
     rv = self.app.post('/api/user_review', data=serialized, headers=user_headers['userB'])
     assert(rv.status_code == 400)
     # Now try to make a review with invalid rating again
     review_data = {
         'event_id': eventA_id,
         'user_id': user_ids['userA'],
         'rating': -1,
         'review': 'Was really super'
     }
     serialized = json.dumps(review_data)
     rv = self.app.post('/api/user_review', data=serialized, headers=user_headers['userB'])
     assert(rv.status_code == 400)
     # Make a valid review
     review_data = {
         'event_id': eventA_id,
         'user_id': user_ids['userA'],
         'rating': 3,
         'review': 'Was really super'
     }
     serialized = json.dumps(review_data)
     rv = self.app.post('/api/user_review', data=serialized, headers=user_headers['userB'])
     assert(rv.status_code == 200)
     # We can't make a second review based off the same event
     review_data = {
         'event_id': eventA_id,
         'user_id': user_ids['userA'],
         'rating': 3,
         'review': 'Was really super'
     }
     serialized = json.dumps(review_data)
     rv = self.app.post('/api/user_review', data=serialized, headers=user_headers['userB'])
     assert(rv.status_code == 403)