예제 #1
0
def notify_added_contributor(node, contributor, auth=None, throttle=None):
    throttle = throttle or settings.CONTRIBUTOR_ADDED_EMAIL_THROTTLE

    # Exclude forks and templates because the user forking/templating the project gets added
    # via 'add_contributor' but does not need to get notified.
    # Only email users for projects, or for components where they are not contributors on the parent node.
    if (contributor.is_registered and not node.template_node and not node.is_fork and
            (not node.parent_node or
                (node.parent_node and not node.parent_node.is_contributor(contributor)))):
        contributor_record = contributor.contributor_added_email_records.get(node._id, {})
        if contributor_record:
            timestamp = contributor_record.get('last_sent', None)
            if timestamp:
                if not throttle_period_expired(timestamp, throttle):
                    return
        else:
            contributor.contributor_added_email_records[node._id] = {}

        mails.send_mail(
            contributor.username,
            mails.CONTRIBUTOR_ADDED,
            user=contributor,
            node=node,
            referrer_name=auth.user.fullname if auth else '',
            all_global_subscriptions_none=check_if_all_global_subscriptions_are_none(contributor)
        )

        contributor.contributor_added_email_records[node._id]['last_sent'] = get_timestamp()
        contributor.save()
예제 #2
0
def request_export(auth):
    mails.send_mail(
        to_addr=settings.SUPPORT_EMAIL,
        mail=mails.REQUEST_EXPORT,
        user=auth.user,
    )
    return {'message': 'Sent account export request'}
예제 #3
0
파일: emails.py 프로젝트: lbanner/osf.io
def email_transactional(subscribed_user_ids, uid, event, **context):
    """
    :param subscribed_user_ids: mod-odm User object ids
    :param uid: id of the event owner (Node or User)
    :param event: name of notification event (e.g. 'comments')
    :param context: context variables for email template
    :return:
    """
    template = event + '.html.mako'
    subject = Template(EMAIL_SUBJECT_MAP[event]).render(**context)

    for user_id in subscribed_user_ids:
        user = website_models.User.load(user_id)
        email = user.username
        context['localized_timestamp'] = localize_timestamp(context.get('timestamp'), user)
        message = mails.render_message(template, **context)

        if context.get('commenter')._id != user._id:
            mails.send_mail(
                to_addr=email,
                mail=mails.TRANSACTIONAL,
                mimetype='html',
                name=user.fullname,
                node_id=context.get('node_id'),
                node_title=context.get('title'),
                subject=subject,
                message=message,
                url=get_settings_url(uid, user)
            )
예제 #4
0
파일: views.py 프로젝트: XTech2K/osf.io
def send_confirm_email(user, email):
    """Sends a confirmation email to `user` to a given email.

    :raises: KeyError if user does not have a confirmation token for the given
        email.
    """
    confirmation_url = user.get_confirmation_url(
        email,
        external=True,
        force=True,
    )

    try:
        merge_target = User.find_one(Q('emails', 'eq', email))
    except NoResultsFound:
        merge_target = None

    mails.send_mail(
        email,
        mails.CONFIRM_MERGE if merge_target else mails.CONFIRM_EMAIL,
        'plain',
        user=user,
        confirmation_url=confirmation_url,
        email=email,
        merge_target=merge_target,
    )
예제 #5
0
파일: sanctions.py 프로젝트: atelic/osf.io
 def _send_approval_request_email(self, user, template, context):
     mails.send_mail(
         user.username,
         template,
         user=user,
         **context
     )
예제 #6
0
def request_deactivation(auth):
    mails.send_mail(
        to_addr=settings.SUPPORT_EMAIL,
        mail=mails.REQUEST_DEACTIVATION,
        user=auth.user,
    )
    return {'message': 'Sent account deactivation request'}
예제 #7
0
def main(dry=True):
    qs = PreprintService.objects.filter(
        is_published=True,
        node__is_deleted=False
    ).select_related('node').prefetch_related('node___contributors').order_by('pk')
    count = qs.count()
    pbar = progressbar.ProgressBar(maxval=count).start()
    contributors_emailed = set()
    logger.info('Sending emails to users for {} published preprints...'.format(count))
    paginator = Paginator(qs, PAGE_SIZE)
    n_processed = 0
    for page_num in paginator.page_range:
        page = paginator.page(page_num)
        for preprint in page.object_list:
            users = preprint.node.contributors.filter(is_active=True)
            for user in users:
                if user._id not in contributors_emailed:
                    if not dry:
                        mails.send_mail(
                            mail=mails.PREPRINT_DOI_CHANGE,
                            to_addr=user.username,
                            can_change_preferences=False,
                            user=user
                        )
                    contributors_emailed.add(user._id)
        n_processed += len(page.object_list)
        pbar.update(n_processed)

    logger.info('Sent email to {} users from {} preprints'.format(len(contributors_emailed), count))
예제 #8
0
def send_claim_registered_email(claimer, unreg_user, node, throttle=24 * 3600):
    unclaimed_record = unreg_user.get_unclaimed_record(node._primary_key)
    referrer = User.load(unclaimed_record['referrer_id'])
    claim_url = web_url_for(
        'claim_user_registered',
        uid=unreg_user._primary_key,
        pid=node._primary_key,
        token=unclaimed_record['token'],
        _external=True,
    )
    timestamp = unclaimed_record.get('last_sent')
    if throttle_period_expired(timestamp, throttle):
        # Send mail to referrer, telling them to forward verification link to claimer
        mails.send_mail(
            referrer.username,
            mails.FORWARD_INVITE_REGiSTERED,
            user=unreg_user,
            referrer=referrer,
            node=node,
            claim_url=claim_url,
            fullname=unclaimed_record['name'],
        )
        unclaimed_record['last_sent'] = get_timestamp()
        unreg_user.save()
    # Send mail to claimer, telling them to wait for referrer
    mails.send_mail(
        claimer.username,
        mails.PENDING_VERIFICATION_REGISTERED,
        fullname=claimer.fullname,
        referrer=referrer,
        node=node,
    )
예제 #9
0
def forgot_password():
    form = ForgotPasswordForm(request.form, prefix='forgot_password')

    if form.validate():
        email = form.email.data
        user_obj = get_user(username=email)
        if user_obj:
            user_obj.verification_key = security.random_string(20)
            user_obj.save()
            reset_link = "http://{0}{1}".format(
                request.host,
                web_url_for(
                    'reset_password',
                    verification_key=user_obj.verification_key
                )
            )
            mails.send_mail(
                to_addr=email,
                mail=mails.FORGOT_PASSWORD,
                reset_link=reset_link
            )
            status.push_status_message('Reset email sent to {0}'.format(email))
        else:
            status.push_status_message('Email {email} not found'.format(email=email))

    forms.push_errors_to_status(form.errors)
    return auth_login(forgot_password_form=form)
예제 #10
0
파일: tasks.py 프로젝트: mfraezz/osf.io
def send_users_email(send_type):
    """Find pending Emails and amalgamates them into a single Email.

    :param send_type
    :return:
    """
    grouped_emails = get_users_emails(send_type)
    for group in grouped_emails:
        user = OSFUser.load(group['user_id'])
        if not user:
            log_exception()
            continue
        info = group['info']
        notification_ids = [message['_id'] for message in info]
        sorted_messages = group_by_node(info)
        if sorted_messages:
            if not user.is_disabled:
                mails.send_mail(
                    to_addr=user.username,
                    mimetype='html',
                    mail=mails.DIGEST,
                    name=user.fullname,
                    message=sorted_messages,
                )
            remove_notifications(email_notification_ids=notification_ids)
예제 #11
0
파일: tasks.py 프로젝트: icereval/osf.io
def _send_global_and_node_emails(send_type):
    """
    Called by `send_users_email`. Send all global and node-related notification emails.
    """
    grouped_emails = get_users_emails(send_type)
    for group in grouped_emails:
        user = OSFUser.load(group['user_id'])
        if not user:
            log_exception()
            continue
        info = group['info']
        notification_ids = [message['_id'] for message in info]
        sorted_messages = group_by_node(info)
        if sorted_messages:
            if not user.is_disabled:
                # If there's only one node in digest we can show it's preferences link in the template.
                notification_nodes = sorted_messages['children'].keys()
                node = AbstractNode.load(notification_nodes[0]) if len(
                    notification_nodes) == 1 else None
                mails.send_mail(
                    to_addr=user.username,
                    mimetype='html',
                    can_change_node_preferences=bool(node),
                    node=node,
                    mail=mails.DIGEST,
                    name=user.fullname,
                    message=sorted_messages,
                )
            remove_notifications(email_notification_ids=notification_ids)
예제 #12
0
    def _send_preprint_confirmation(self, auth):
        # Send creator confirmation email
        recipient = self.creator
        event_type = utils.find_subscription_type('global_reviews')
        user_subscriptions = get_user_subscriptions(recipient, event_type)
        if self.provider._id == 'osf':
            logo = settings.OSF_PREPRINTS_LOGO
        else:
            logo = self.provider._id

        context = {
            'domain': settings.DOMAIN,
            'reviewable': self,
            'workflow': self.provider.reviews_workflow,
            'provider_url': '{domain}preprints/{provider_id}'.format(
                            domain=self.provider.domain or settings.DOMAIN,
                            provider_id=self.provider._id if not self.provider.domain else '').strip('/'),
            'provider_contact_email': self.provider.email_contact or settings.OSF_CONTACT_EMAIL,
            'provider_support_email': self.provider.email_support or settings.OSF_SUPPORT_EMAIL,
            'no_future_emails': user_subscriptions['none'],
            'is_creator': True,
            'provider_name': 'OSF Preprints' if self.provider.name == 'Open Science Framework' else self.provider.name,
            'logo': logo,
        }

        mails.send_mail(
            recipient.username,
            mails.REVIEWS_SUBMISSION_CONFIRMATION,
            mimetype='html',
            user=recipient,
            **context
        )
예제 #13
0
파일: views.py 프로젝트: Alpani/osf.io
def send_confirm_email(user, email):
    """Sends a confirmation email to `user` to a given email.

    :raises: KeyError if user does not have a confirmation token for the given
        email.
    """
    confirmation_url = user.get_confirmation_url(
        email,
        external=True,
        force=True,
    )

    try:
        merge_target = User.find_one(Q('emails', 'eq', email))
    except NoResultsFound:
        merge_target = None

    campaign = campaigns.campaign_for_user(user)
    # Choose the appropriate email template to use
    if merge_target:
        mail_template = mails.CONFIRM_MERGE
    elif campaign:
        mail_template = campaigns.email_template_for_campaign(campaign)
    else:
        mail_template = mails.CONFIRM_EMAIL

    mails.send_mail(
        email,
        mail_template,
        'plain',
        user=user,
        confirmation_url=confirmation_url,
        email=email,
        merge_target=merge_target,
    )
예제 #14
0
파일: views.py 프로젝트: XTech2K/osf.io
def forgot_password_post():
    """Attempt to send user password reset or return respective error.
    """
    form = ForgotPasswordForm(request.form, prefix='forgot_password')

    if form.validate():
        email = form.email.data
        user_obj = get_user(email=email)
        if user_obj:
            user_obj.verification_key = security.random_string(20)
            user_obj.save()
            reset_link = "http://{0}{1}".format(
                request.host,
                web_url_for(
                    'reset_password',
                    verification_key=user_obj.verification_key
                )
            )
            mails.send_mail(
                to_addr=email,
                mail=mails.FORGOT_PASSWORD,
                reset_link=reset_link
            )
        status.push_status_message(
            ('An email with instructions on how to reset the password '
             'for the account associated with {0} has been sent. If you '
             'do not receive an email and believe you should have please '
             'contact OSF Support.').format(email), 'success')

    forms.push_errors_to_status(form.errors)
    return auth_login(forgot_password_form=form)
예제 #15
0
def send_digest(grouped_digests):
    """ Send digest emails and remove digests for sent messages in a callback.
    :param grouped_digests: digest notification messages from the past 24 hours grouped by user
    :return:
    """
    for group in grouped_digests:
        user = User.load(group['user_id'])
        if not user:
            sentry.log_exception()
            sentry.log_message("A user with this username does not exist.")
            return

        info = group['info']
        digest_notification_ids = [message['_id'] for message in info]
        sorted_messages = group_messages_by_node(info)

        if sorted_messages:
            logger.info('Sending email digest to user {0!r}'.format(user))
            mails.send_mail(
                to_addr=user.username,
                mimetype='html',
                mail=mails.DIGEST,
                name=user.fullname,
                message=sorted_messages,
                callback=remove_sent_digest_notifications.si(
                    digest_notification_ids=digest_notification_ids
                )
            )
예제 #16
0
def meeting_hook():
    """View function for email conference submission.
    """
    message = ConferenceMessage()

    try:
        message.verify()
    except ConferenceError as error:
        logger.error(error)
        raise HTTPError(httplib.NOT_ACCEPTABLE)

    try:
        conference = Conference.get_by_endpoint(message.conference_name, active=False)
    except ConferenceError as error:
        logger.error(error)
        raise HTTPError(httplib.NOT_ACCEPTABLE)

    if not conference.active:
        send_mail(
            message.sender_email,
            CONFERENCE_INACTIVE,
            fullname=message.sender_display,
            presentations_url=web_url_for('conference_view', _absolute=True),
            can_change_preferences=False,
            logo=settings.OSF_MEETINGS_LOGO,
        )
        raise HTTPError(httplib.NOT_ACCEPTABLE)

    add_poster_by_email(conference=conference, message=message)
예제 #17
0
파일: tasks.py 프로젝트: Alpani/osf.io
def send_users_email(send_type):
    """Find pending Emails and amalgamates them into a single Email.

    :param send_type
    :return:
    """
    grouped_emails = get_users_emails(send_type)
    if not grouped_emails:
        return
    for group in grouped_emails:
        user = User.load(group["user_id"])
        if not user:
            log_exception()
            continue
        info = group["info"]
        notification_ids = [message["_id"] for message in info]
        sorted_messages = group_by_node(info)
        if sorted_messages:
            mails.send_mail(
                to_addr=user.username,
                mimetype="html",
                mail=mails.DIGEST,
                name=user.fullname,
                message=sorted_messages,
                callback=remove_notifications(email_notification_ids=notification_ids),
            )
예제 #18
0
def main(send_email=False):
    logger.info('Starting Project storage audit')
    init_app(set_backends=True, routes=False)

    lines = []
    projects = {}
    users = defaultdict(lambda: (0, 0))

    for node in Node.find(Q('__backrefs.parent.node.nodes', 'eq', None)):  # ODM hack to ignore all nodes with parents
        if node._id in WHITE_LIST:
            continue  # Dont count whitelisted nodes against users
        projects[node] = get_usage(node)
        for contrib in node.contributors:
            if node.can_edit(user=contrib):
                users[contrib] = tuple(map(sum, zip(users[contrib], projects[node])))  # Adds tuples together, map(sum, zip((a, b), (c, d))) -> (a+c, b+d)

    for collection, limit in ((users, USER_LIMIT), (projects, PROJECT_LIMIT)):
        for item, (used, deleted) in filter(functools.partial(limit_filter, limit), collection.items()):
            line = '{!r} has exceeded the limit {:.2f}GBs ({}b) with {:.2f}GBs ({}b) used and {:.2f}GBs ({}b) deleted.'.format(item, limit / GBs, limit, used / GBs, used, deleted / GBs, deleted)
            logger.info(line)
            lines.append(line)

    if lines:
        if send_email:
            logger.info('Sending email...')
            mails.send_mail('*****@*****.**', mails.EMPTY, body='\n'.join(lines), subject='Script: OsfStorage usage audit')
        else:
            logger.info('send_email is False, not sending email'.format(len(lines)))
        logger.info('{} offending project(s) and user(s) found'.format(len(lines)))
    else:
        logger.info('No offending projects or users found')
예제 #19
0
파일: emails.py 프로젝트: XTech2K/osf.io
def email_transactional(recipient_ids, uid, event, user, node, timestamp, **context):
    """
    :param recipient_ids: mod-odm User object ids
    :param uid: id of the event owner (Node or User)
    :param event: name of notification event (e.g. 'comments')
    :param context: context variables for email template
        See notify for specifics
    :return:
    """
    template = event + '.html.mako'
    context['title'] = node.title
    context['user'] = user
    subject = Template(EMAIL_SUBJECT_MAP[event]).render(**context)

    for user_id in recipient_ids:
        recipient = website_models.User.load(user_id)
        email = recipient.username
        context['localized_timestamp'] = localize_timestamp(timestamp, recipient)
        message = mails.render_message(template, **context)

        if user._id != recipient._id:
            mails.send_mail(
                to_addr=email,
                mail=mails.TRANSACTIONAL,
                mimetype='html',
                name=recipient.fullname,
                node_id=node._id,
                node_title=node.title,
                subject=subject,
                message=message,
                url=get_settings_url(uid, recipient)
            )
예제 #20
0
def send_claim_email(email, user, node, notify=True, throttle=24 * 3600):
    """Send an email for claiming a user account. Either sends to the given email
    or the referrer's email, depending on the email address provided.

    :param str email: The address given in the claim user form
    :param User user: The User record to claim.
    :param Node node: The node where the user claimed their account.
    :param bool notify: If True and an email is sent to the referrer, an email
        will also be sent to the invited user about their pending verification.
    :param int throttle: Time period (in seconds) after the referrer is
        emailed during which the referrer will not be emailed again.

    """
    claimer_email = email.lower().strip()

    unclaimed_record = user.get_unclaimed_record(node._primary_key)
    referrer = User.load(unclaimed_record['referrer_id'])
    claim_url = user.get_claim_url(node._primary_key, external=True)
    # If given email is the same provided by user, just send to that email
    if unclaimed_record.get('email') == claimer_email:
        mail_tpl = mails.INVITE
        to_addr = claimer_email
        unclaimed_record['claimer_email'] = claimer_email
        user.save()
    else:  # Otherwise have the referrer forward the email to the user
        # roll the valid token for each email, thus user cannot change email and approve a different email address
        timestamp = unclaimed_record.get('last_sent')
        if not throttle_period_expired(timestamp, throttle):
            raise HTTPError(400, data=dict(
                message_long='User account can only be claimed with an existing user once every 24 hours'
            ))
        unclaimed_record['last_sent'] = get_timestamp()
        unclaimed_record['token'] = generate_confirm_token()
        unclaimed_record['claimer_email'] = claimer_email
        user.save()
        claim_url = user.get_claim_url(node._primary_key, external=True)
        if notify:
            pending_mail = mails.PENDING_VERIFICATION
            mails.send_mail(
                claimer_email,
                pending_mail,
                user=user,
                referrer=referrer,
                fullname=unclaimed_record['name'],
                node=node
            )
        mail_tpl = mails.FORWARD_INVITE
        to_addr = referrer.username
    mails.send_mail(
        to_addr,
        mail_tpl,
        user=user,
        referrer=referrer,
        node=node,
        claim_url=claim_url,
        email=claimer_email,
        fullname=unclaimed_record['name']
    )
    return to_addr
예제 #21
0
def confirm_email_get(token, auth=None, **kwargs):
    """View for email confirmation links.
    Authenticates and redirects to user settings page if confirmation is
    successful, otherwise shows an "Expired Link" error.

    methods: GET
    """
    user = User.load(kwargs['uid'])
    is_merge = 'confirm_merge' in request.args
    is_initial_confirmation = not user.date_confirmed

    if user is None:
        raise HTTPError(http.NOT_FOUND)

    if auth and auth.user and (auth.user._id == user._id or auth.user._id == user.merged_by._id):
        if not is_merge:
            # determine if the user registered through a campaign
            campaign = campaigns.campaign_for_user(user)
            if campaign:
                return redirect(
                    campaigns.campaign_url_for(campaign)
                )
            status.push_status_message(language.WELCOME_MESSAGE, 'default', jumbotron=True)
            # Go to dashboard
            return redirect(web_url_for('dashboard'))

        status.push_status_message(language.MERGE_COMPLETE, 'success')
        return redirect(web_url_for('user_account'))

    try:
        user.confirm_email(token, merge=is_merge)
    except exceptions.EmailConfirmTokenError as e:
        raise HTTPError(http.BAD_REQUEST, data={
            'message_short': e.message_short,
            'message_long': e.message_long
        })

    if is_initial_confirmation:
        user.date_last_login = datetime.datetime.utcnow()
        user.save()

        # Send out our welcome message
        mails.send_mail(
            to_addr=user.username,
            mail=mails.WELCOME,
            mimetype='html',
            user=user
        )

    # Redirect to CAS and authenticate the user with a verification key.
    user.verification_key = security.random_string(20)
    user.save()

    return redirect(cas.get_login_url(
        request.url,
        auto=True,
        username=user.username,
        verification_key=user.verification_key
    ))
예제 #22
0
def send_claim_registered_email(claimer, unclaimed_user, node, throttle=24 * 3600):
    """
    A registered user claiming the unclaimed user account as an contributor to a project.
    Send an email for claiming the account to the referrer and notify the claimer.

    :param claimer: the claimer
    :param unclaimed_user: the user account to claim
    :param node: the project node where the user account is claimed
    :param throttle: the time period in seconds before another claim for the account can be made
    :return:
    :raise: http.BAD_REQUEST
    """

    unclaimed_record = unclaimed_user.get_unclaimed_record(node._primary_key)

    # check throttle
    timestamp = unclaimed_record.get('last_sent')
    if not throttle_period_expired(timestamp, throttle):
        raise HTTPError(http.BAD_REQUEST, data=dict(
            message_long='User account can only be claimed with an existing user once every 24 hours'
        ))

    # roll the valid token for each email, thus user cannot change email and approve a different email address
    verification_key = generate_verification_key(verification_type='claim')
    unclaimed_record['token'] = verification_key['token']
    unclaimed_record['expires'] = verification_key['expires']
    unclaimed_record['claimer_email'] = claimer.username
    unclaimed_user.save()

    referrer = User.load(unclaimed_record['referrer_id'])
    claim_url = web_url_for(
        'claim_user_registered',
        uid=unclaimed_user._primary_key,
        pid=node._primary_key,
        token=unclaimed_record['token'],
        _external=True,
    )

    # Send mail to referrer, telling them to forward verification link to claimer
    mails.send_mail(
        referrer.username,
        mails.FORWARD_INVITE_REGISTERED,
        user=unclaimed_user,
        referrer=referrer,
        node=node,
        claim_url=claim_url,
        fullname=unclaimed_record['name'],
    )
    unclaimed_record['last_sent'] = get_timestamp()
    unclaimed_user.save()

    # Send mail to claimer, telling them to wait for referrer
    mails.send_mail(
        claimer.username,
        mails.PENDING_VERIFICATION_REGISTERED,
        fullname=claimer.fullname,
        referrer=referrer,
        node=node,
    )
예제 #23
0
파일: views.py 프로젝트: chrisseto/osf.io
def send_confirm_email(user, email, renew=False, external_id_provider=None, external_id=None, destination=None):
    """
    Sends `user` a confirmation to the given `email`.


    :param user: the user
    :param email: the email
    :param renew: refresh the token
    :param external_id_provider: user's external id provider
    :param external_id: user's external id
    :param destination: the destination page to redirect after confirmation
    :return:
    :raises: KeyError if user does not have a confirmation token for the given email.
    """

    confirmation_url = user.get_confirmation_url(
        email,
        external=True,
        force=True,
        renew=renew,
        external_id_provider=external_id_provider,
        destination=destination
    )

    try:
        merge_target = User.find_one(Q('emails', 'eq', email))
    except NoResultsFound:
        merge_target = None
    campaign = campaigns.campaign_for_user(user)

    # Choose the appropriate email template to use and add existing_user flag if a merge or adding an email.
    if external_id_provider and external_id:  # first time login through external identity provider
        if user.external_identity[external_id_provider][external_id] == 'CREATE':
            mail_template = mails.EXTERNAL_LOGIN_CONFIRM_EMAIL_CREATE
        elif user.external_identity[external_id_provider][external_id] == 'LINK':
            mail_template = mails.EXTERNAL_LOGIN_CONFIRM_EMAIL_LINK
    elif merge_target:  # merge account
        mail_template = mails.CONFIRM_MERGE
        confirmation_url = '{}?logout=1'.format(confirmation_url)
    elif user.is_active:  # add email
        mail_template = mails.CONFIRM_EMAIL
        confirmation_url = '{}?logout=1'.format(confirmation_url)
    elif campaign:  # campaign
        # TODO: In the future, we may want to make confirmation email configurable as well (send new user to
        #   appropriate landing page or with redirect after)
        mail_template = campaigns.email_template_for_campaign(campaign)
    else:  # account creation
        mail_template = mails.INITIAL_CONFIRM_EMAIL

    mails.send_mail(
        email,
        mail_template,
        'plain',
        user=user,
        confirmation_url=confirmation_url,
        email=email,
        merge_target=merge_target,
        external_id_provider=external_id_provider,
    )
예제 #24
0
def notify_added_contributor(node, contributor, auth=None, throttle=None, email_template='default'):
    if email_template == 'false':
        return

    throttle = throttle or settings.CONTRIBUTOR_ADDED_EMAIL_THROTTLE

    # Email users for projects, or for components where they are not contributors on the parent node.
    if contributor.is_registered and \
            (not node.parent_node or (node.parent_node and not node.parent_node.is_contributor(contributor))):

        mimetype = 'html'
        preprint_provider = None
        logo = None
        if email_template == 'preprint':
            email_template, preprint_provider = find_preprint_provider(node)
            if not email_template or not preprint_provider:
                return
            email_template = getattr(mails, 'CONTRIBUTOR_ADDED_PREPRINT')(email_template, preprint_provider)
            if preprint_provider._id == 'osf':
                logo = settings.OSF_PREPRINTS_LOGO
            else:
                logo = preprint_provider._id
        elif email_template == 'access_request':
            mimetype = 'html'
            email_template = getattr(mails, 'CONTRIBUTOR_ADDED_ACCESS_REQUEST'.format(email_template.upper()))
        elif node.is_preprint:
            email_template = getattr(mails, 'CONTRIBUTOR_ADDED_PREPRINT_NODE_FROM_OSF'.format(email_template.upper()))
            logo = settings.OSF_PREPRINTS_LOGO
        else:
            email_template = getattr(mails, 'CONTRIBUTOR_ADDED_DEFAULT'.format(email_template.upper()))

        contributor_record = contributor.contributor_added_email_records.get(node._id, {})
        if contributor_record:
            timestamp = contributor_record.get('last_sent', None)
            if timestamp:
                if not throttle_period_expired(timestamp, throttle):
                    return
        else:
            contributor.contributor_added_email_records[node._id] = {}

        mails.send_mail(
            contributor.username,
            email_template,
            mimetype=mimetype,
            user=contributor,
            node=node,
            referrer_name=auth.user.fullname if auth else '',
            all_global_subscriptions_none=check_if_all_global_subscriptions_are_none(contributor),
            branded_service=preprint_provider,
            can_change_preferences=False,
            logo=logo if logo else settings.OSF_LOGO,
            osf_contact_email=settings.OSF_CONTACT_EMAIL
        )

        contributor.contributor_added_email_records[node._id]['last_sent'] = get_timestamp()
        contributor.save()

    elif not contributor.is_registered:
        unreg_contributor_added.send(node, contributor=contributor, auth=auth, email_template=email_template)
예제 #25
0
    def authenticate(self, request):
        try:
            payload = jwt.decode(
                jwe.decrypt(request.body, settings.JWE_SECRET),
                settings.JWT_SECRET,
                options={'verify_exp': False},
                algorithm='HS256'
            )
        except (jwt.InvalidTokenError, TypeError):
            raise AuthenticationFailed

        # The JWT `data` payload is expected in the following structure.
        #
        # {"provider": {
        #     "idp": "https://login.circle.edu/idp/shibboleth",
        #     "id": "CIR",
        #     "user": {
        #         "middleNames": "",
        #         "familyName": "",
        #         "givenName": "",
        #         "fullname": "Circle User",
        #         "suffix": "",
        #         "username": "******"
        #     }
        # }}
        data = json.loads(payload['data'])
        provider = data['provider']

        institution = Institution.load(provider['id'])
        if not institution:
            raise AuthenticationFailed('Invalid institution id specified "{}"'.format(provider['id']))

        username = provider['user']['username']
        fullname = provider['user']['fullname']

        user, created = get_or_create_user(fullname, username, reset_password=False)

        if created:
            user.given_name = provider['user'].get('givenName')
            user.middle_names = provider['user'].get('middleNames')
            user.family_name = provider['user'].get('familyName')
            user.suffix = provider['user'].get('suffix')
            user.date_last_login = datetime.utcnow()
            user.save()

            # User must be saved in order to have a valid _id
            user.register(username)
            send_mail(
                to_addr=user.username,
                mail=WELCOME_OSF4I,
                mimetype='html',
                user=user
            )

        if institution not in user.affiliated_institutions:
            user.affiliated_institutions.append(institution)
            user.save()

        return user, None
예제 #26
0
파일: sanctions.py 프로젝트: kch8qx/osf.io
    def _send_rejection_email(self, user, draft):
        schema = draft.registration_schema
        prereg_schema = prereg_utils.get_prereg_schema()

        if schema._id == prereg_schema._id:
            mails.send_mail(user.username, mails.PREREG_CHALLENGE_REJECTED, user=user, draft_url=draft.absolute_url)
        else:
            raise NotImplementedError("TODO: add a generic email template for registration approvals")
예제 #27
0
파일: tasks.py 프로젝트: mfraezz/osf.io
def send_desk_share_error(node, resp, retries):
    mails.send_mail(
        to_addr=settings.OSF_SUPPORT_EMAIL,
        mail=mails.SHARE_ERROR_DESK,
        node=node,
        resp=resp,
        retries=retries,
    )
def send_retraction_and_embargo_addition_message(contrib, label, mail, dry_run=True):
    if label in contrib.security_messages:
        return
    logger.info('Sending message to user {0!r}'.format(contrib))
    if not dry_run:
        send_mail(contrib.username, mail, user=contrib)
        contrib.security_messages[MESSAGE_NAME] = datetime.datetime.utcnow()
        contrib.save()
예제 #29
0
파일: tasks.py 프로젝트: mfraezz/osf.io
def send_desk_share_preprint_error(preprint, resp, retries):
    mails.send_mail(
        to_addr=settings.OSF_SUPPORT_EMAIL,
        mail=mails.SHARE_PREPRINT_ERROR_DESK,
        preprint=preprint,
        resp=resp,
        retries=retries,
    )
예제 #30
0
파일: views.py 프로젝트: baylee-d/osf.io
def forgot_password_post():
    """
    View for user to submit forgot password form.
    HTTP Method: POST
    :return {}
    """

    form = ForgotPasswordForm(request.form, prefix='forgot_password')

    if not form.validate():
        # Don't go anywhere
        forms.push_errors_to_status(form.errors)
    else:
        email = form.email.data
        status_message = ('If there is an OSF account associated with {0}, an email with instructions on how to '
                          'reset the OSF password has been sent to {0}. If you do not receive an email and believe '
                          'you should have, please contact OSF Support. ').format(email)
        kind = 'success'
        # check if the user exists
        user_obj = get_user(email=email)
        if user_obj:
            # rate limit forgot_password_post
            if not throttle_period_expired(user_obj.email_last_sent, settings.SEND_EMAIL_THROTTLE):
                status_message = 'You have recently requested to change your password. Please wait a few minutes ' \
                                 'before trying again.'
                kind = 'error'
            else:
                # TODO [OSF-6673]: Use the feature in [OSF-6998] for user to resend claim email.
                # if the user account is not claimed yet
                if (user_obj.is_invited and
                        user_obj.unclaimed_records and
                        not user_obj.date_last_login and
                        not user_obj.is_claimed and
                        not user_obj.is_registered):
                    status_message = 'You cannot reset password on this account. Please contact OSF Support.'
                    kind = 'error'
                else:
                    # new random verification key (v2)
                    user_obj.verification_key_v2 = generate_verification_key(verification_type='password')
                    user_obj.email_last_sent = datetime.datetime.utcnow()
                    user_obj.save()
                    reset_link = furl.urljoin(
                        settings.DOMAIN,
                        web_url_for(
                            'reset_password_get',
                            uid=user_obj._id,
                            token=user_obj.verification_key_v2['token']
                        )
                    )
                    mails.send_mail(
                        to_addr=email,
                        mail=mails.FORGOT_PASSWORD,
                        reset_link=reset_link
                    )

        status.push_status_message(status_message, kind=kind, trust=False)

    return {}
예제 #31
0
def send_claim_email(email, user, node, notify=True, throttle=24 * 3600):
    """Send an email for claiming a user account. Either sends to the given email
    or the referrer's email, depending on the email address provided.

    :param str email: The address given in the claim user form
    :param User user: The User record to claim.
    :param Node node: The node where the user claimed their account.
    :param bool notify: If True and an email is sent to the referrer, an email
        will also be sent to the invited user about their pending verification.
    :param int throttle: Time period (in seconds) after the referrer is
        emailed during which the referrer will not be emailed again.

    """
    invited_email = email.lower().strip()

    unclaimed_record = user.get_unclaimed_record(node._primary_key)
    referrer = User.load(unclaimed_record['referrer_id'])
    claim_url = user.get_claim_url(node._primary_key, external=True)
    # If given email is the same provided by user, just send to that email
    if unclaimed_record.get('email', None) == invited_email:
        mail_tpl = mails.INVITE
        to_addr = invited_email
    else:  # Otherwise have the referrer forward the email to the user
        if notify:
            pending_mail = mails.PENDING_VERIFICATION
            mails.send_mail(invited_email,
                            pending_mail,
                            user=user,
                            referrer=referrer,
                            fullname=unclaimed_record['name'],
                            node=node)
        timestamp = unclaimed_record.get('last_sent')
        if throttle_period_expired(timestamp, throttle):
            unclaimed_record['last_sent'] = get_timestamp()
            user.save()
        else:  # Don't send the email to the referrer
            return
        mail_tpl = mails.FORWARD_INVITE
        to_addr = referrer.username
    mails.send_mail(to_addr,
                    mail_tpl,
                    user=user,
                    referrer=referrer,
                    node=node,
                    claim_url=claim_url,
                    email=invited_email,
                    fullname=unclaimed_record['name'])
    return to_addr
예제 #32
0
def send_archiver_size_exceeded_mails(src, user, stat_result):
    mails.send_mail(
        to_addr=settings.SUPPORT_EMAIL,
        mail=mails.ARCHIVE_SIZE_EXCEEDED_DESK,
        user=user,
        src=src,
        stat_result=stat_result
    )
    mails.send_mail(
        to_addr=user.username,
        mail=mails.ARCHIVE_SIZE_EXCEEDED_USER,
        user=user,
        src=src,
        can_change_preferences=False,
        mimetype='html',
    )
예제 #33
0
def send_archiver_uncaught_error_mails(src, user, results):
    mails.send_mail(
        to_addr=settings.SUPPORT_EMAIL,
        mail=mails.ARCHIVE_UNCAUGHT_ERROR_DESK,
        user=user,
        src=src,
        results=results,
    )
    mails.send_mail(
        to_addr=user.username,
        mail=mails.ARCHIVE_UNCAUGHT_ERROR_USER,
        user=user,
        src=src,
        results=results,
        mimetype='html',
    )
예제 #34
0
def request_export(auth):
    user = auth.user
    if not throttle_period_expired(user.email_last_sent, settings.SEND_EMAIL_THROTTLE):
        raise HTTPError(http_status.HTTP_400_BAD_REQUEST,
                        data={'message_long': 'Too many requests. Please wait a while before sending another account export request.',
                              'error_type': 'throttle_error'})

    mails.send_mail(
        to_addr=settings.OSF_SUPPORT_EMAIL,
        mail=mails.REQUEST_EXPORT,
        user=auth.user,
        can_change_preferences=False,
    )
    user.email_last_sent = timezone.now()
    user.save()
    return {'message': 'Sent account export request'}
예제 #35
0
    def _send_preprint_confirmation(self, auth):
        # Send creator confirmation email
        if self.provider._id == 'osf':
            email_template = getattr(mails, 'PREPRINT_CONFIRMATION_DEFAULT')
        else:
            email_template = getattr(mails, 'PREPRINT_CONFIRMATION_BRANDED')(
                self.provider)

        mails.send_mail(
            auth.user.username,
            email_template,
            user=auth.user,
            node=self.node,
            preprint=self,
            osf_contact_email=settings.OSF_CONTACT_EMAIL,
        )
예제 #36
0
def forgot_password_post():
    """
    View for user to submit forgot password form.
    HTTP Method: POST
    :return {}
    """

    form = ForgotPasswordForm(request.form, prefix='forgot_password')

    if not form.validate():
        # Don't go anywhere
        forms.push_errors_to_status(form.errors)
    else:
        email = form.email.data
        status_message = (
            'If there is an OSF account associated with {0}, an email with instructions on how to '
            'reset the OSF password has been sent to {0}. If you do not receive an email and believe '
            'you should have, please contact OSF Support. ').format(email)
        kind = 'success'
        # check if the user exists
        user_obj = get_user(email=email)
        if user_obj:
            # rate limit forgot_password_post
            if not throttle_period_expired(user_obj.email_last_sent,
                                           settings.SEND_EMAIL_THROTTLE):
                status_message = 'You have recently requested to change your password. Please wait a few minutes ' \
                                 'before trying again.'
                kind = 'error'
            # TODO [OSF-6673]: Use the feature in [OSF-6998] for user to resend claim email.
            elif user_obj.is_active:
                # new random verification key (v2)
                user_obj.verification_key_v2 = generate_verification_key(
                    verification_type='password')
                user_obj.email_last_sent = timezone.now()
                user_obj.save()
                reset_link = furl.urljoin(
                    settings.DOMAIN,
                    web_url_for('reset_password_get',
                                uid=user_obj._id,
                                token=user_obj.verification_key_v2['token']))
                mails.send_mail(to_addr=email,
                                mail=mails.FORGOT_PASSWORD,
                                reset_link=reset_link)

        status.push_status_message(status_message, kind=kind, trust=False)

    return {}
예제 #37
0
def send_archiver_file_not_found_mails(src, user, results):
    mails.send_mail(
        to_addr=settings.SUPPORT_EMAIL,
        mail=mails.ARCHIVE_FILE_NOT_FOUND_DESK,
        user=user,
        src=src,
        results=results,
    )
    mails.send_mail(
        to_addr=user.username,
        mail=mails.ARCHIVE_FILE_NOT_FOUND_USER,
        user=user,
        src=src,
        results=results,
        can_change_preferences=False,
        mimetype='html',
    )
예제 #38
0
def send_security_message(user, label, mail):
    if label in user.security_messages:
        return
    # Pass mailer so that celery is not used
    # Email synchronously so that user is only saved after email has been sent
    mails.send_mail(
        user.username,
        mail,
        from_addr=FROM_ADDR,
        mailer=send_email,
        user=user,
        username=settings.MANDRILL_USERNAME,
        password=settings.MANDRILL_PASSWORD,
        mail_server=settings.MANDRILL_MAIL_SERVER,
    )
    user.security_messages[label] = timezone.now()
    user.save()
예제 #39
0
    def _send_rejection_email(self, user, draft):
        schema = draft.registration_schema
        prereg_schema = prereg_utils.get_prereg_schema()

        if schema._id == prereg_schema._id:
            mails.send_mail(
                user.username,
                mails.PREREG_CHALLENGE_REJECTED,
                user=user,
                draft_url=draft.absolute_url,
                can_change_preferences=False,
                logo=osf_settings.OSF_PREREG_LOGO
            )
        else:
            raise NotImplementedError(
                'TODO: add a generic email template for registration approvals'
            )
예제 #40
0
def send_archiver_copy_error_mails(src, user, results):
    mails.send_mail(
        to_addr=settings.SUPPORT_EMAIL,
        mail=mails.ARCHIVE_COPY_ERROR_DESK,
        user=user,
        src=src,
        results=results,
    )
    mails.send_mail(
        to_addr=user.username,
        mail=mails.ARCHIVE_COPY_ERROR_USER,
        user=user,
        src=src,
        results=results,
        can_change_preferences=False,
        mimetype='html',
    )
예제 #41
0
def notify_added_contributor(node,
                             contributor,
                             auth=None,
                             throttle=None,
                             email_template='default'):
    throttle = throttle or settings.CONTRIBUTOR_ADDED_EMAIL_THROTTLE

    # Exclude forks and templates because the user forking/templating the project gets added
    # via 'add_contributor' but does not need to get notified.
    # Only email users for projects, or for components where they are not contributors on the parent node.
    if (contributor.is_registered and not node.template_node
            and not node.is_fork
            and (not node.parent_node or
                 (node.parent_node
                  and not node.parent_node.is_contributor(contributor)))):
        email_template = getattr(
            mails, 'CONTRIBUTOR_ADDED_{}'.format(email_template.upper()))
        contributor_record = contributor.contributor_added_email_records.get(
            node._id, {})
        if contributor_record:
            timestamp = contributor_record.get('last_sent', None)
            if timestamp:
                if not throttle_period_expired(timestamp, throttle):
                    return
        else:
            contributor.contributor_added_email_records[node._id] = {}

        mails.send_mail(
            contributor.username,
            email_template,
            user=contributor,
            node=node,
            referrer_name=auth.user.fullname if auth else '',
            all_global_subscriptions_none=
            check_if_all_global_subscriptions_are_none(contributor))

        contributor.contributor_added_email_records[
            node._id]['last_sent'] = get_timestamp()
        contributor.save()

    elif not contributor.is_registered:
        unreg_contributor_added.send(node,
                                     contributor=contributor,
                                     auth=auth,
                                     email_template=email_template)
예제 #42
0
def request_deactivation(auth):
    user = auth.user
    if not throttle_period_expired(user.email_last_sent, settings.SEND_EMAIL_THROTTLE):
        raise HTTPError(http.BAD_REQUEST,
                        data={
                            'message_long': 'Too many requests. Please wait a while before sending another account deactivation request.',
                            'error_type': 'throttle_error'
                        })

    mails.send_mail(
        to_addr=settings.OSF_SUPPORT_EMAIL,
        mail=mails.REQUEST_DEACTIVATION,
        user=auth.user,
    )
    user.email_last_sent = timezone.now()
    user.requested_deactivation = True
    user.save()
    return {'message': 'Sent account deactivation request'}
예제 #43
0
def send_archiver_uncaught_error_mails(src, user, results, url):
    mails.send_mail(
        to_addr=settings.OSF_SUPPORT_EMAIL,
        mail=mails.ARCHIVE_UNCAUGHT_ERROR_DESK,
        user=user,
        src=src,
        results=results,
        url=url,
    )
    mails.send_mail(
        to_addr=user.username,
        mail=mails.ARCHIVE_UNCAUGHT_ERROR_USER,
        user=user,
        src=src,
        results=results,
        can_change_preferences=False,
        mimetype='html',
    )
예제 #44
0
def main():
    prereg_csv = generate_prereg_csv()

    filename = 'prereg_{}.csv.gz'.format(timezone.now().isoformat())

    output = io.BytesIO()
    with gzip.GzipFile(filename=filename, mode='wb',
                       fileobj=output) as gzip_obj:
        gzip_obj.write(prereg_csv.getvalue())

    mails.send_mail(
        mail=mails.PREREG_CSV,
        to_addr=settings.SUPPORT_EMAIL,
        attachment_name=filename,
        attachment_content=output.getvalue(),
    )

    logger.info('Updated prereg CSV email sent.')
예제 #45
0
def _send_reviews_moderator_emails(send_type):
    """
    Called by `send_users_email`. Send all reviews triggered emails.
    """
    grouped_emails = get_moderators_emails(send_type)
    for group in grouped_emails:
        user = OSFUser.load(group['user_id'])
        info = group['info']
        notification_ids = [message['_id'] for message in info]
        provider = AbstractProvider.objects.get(id=group['provider_id'])
        additional_context = dict()
        if isinstance(provider, RegistrationProvider):
            provider_type = 'registration'
            submissions_url = f'{settings.DOMAIN}registries/{provider._id}/moderation/submissions',
            withdrawals_url = f'{submissions_url}?state=pending_withdraw'
            notification_settings_url = f'{settings.DOMAIN}registries/{provider._id}/moderation/notifications'
            if provider.brand:
                additional_context = {
                    'logo_url': provider.brand.hero_logo_image,
                    'top_bar_color': provider.brand.primary_color
                }
        else:
            provider_type = 'preprint'
            submissions_url = f'{settings.DOMAIN}reviews/preprints/{provider._id}',
            withdrawals_url = ''
            notification_settings_url = f'{settings.DOMAIN}reviews/{provider_type}s/{provider._id}/notifications'

        if not user.is_disabled:
            mails.send_mail(
                to_addr=user.username,
                mimetype='html',
                mail=mails.DIGEST_REVIEWS_MODERATORS,
                name=user.fullname,
                message=info,
                provider_name=provider.name,
                reviews_submissions_url=submissions_url,
                notification_settings_url=notification_settings_url,
                reviews_withdrawal_url=withdrawals_url,
                is_reviews_moderator_notification=True,
                is_admin=provider.get_group(ADMIN).user_set.filter(
                    id=user.id).exists(),
                provider_type=provider_type,
                **additional_context)
        remove_notifications(email_notification_ids=notification_ids)
예제 #46
0
def main(send_email=False):
    logger.info('Starting Project storage audit')
    init_app(set_backends=True, routes=False)

    lines = []
    projects = {}
    users = defaultdict(lambda: (0, 0))

    progress_bar = progressbar.ProgressBar(maxval=Node.find(Q('parent_node', 'eq', None)).count()).start()

    for i, node in enumerate(Node.find(Q('parent_node', 'eq', None))):
        progress_bar.update(i+1)
        if node._id in WHITE_LIST:
            continue  # Dont count whitelisted nodes against users
        projects[node._id] = get_usage(node)
        for contrib in node.contributors:
            if node.can_edit(user=contrib):
                users[contrib._id] = tuple(map(sum, zip(users[contrib._id], projects[node._id])))  # Adds tuples together, map(sum, zip((a, b), (c, d))) -> (a+c, b+d)

        if i % 25 == 0:
            # Clear all caches
            for key in ('node', 'user', 'fileversion', 'storedfilenode'):
                Node._cache.data.get(key, {}).clear()
                Node._object_cache.data.get(key, {}).clear()
            # Collect garbage
            gc.collect()
    progress_bar.finish()

    for model, collection, limit in ((User, users, USER_LIMIT), (Node, projects, PROJECT_LIMIT)):
        for item, (used, deleted) in filter(functools.partial(limit_filter, limit), collection.items()):
            line = '{!r} has exceeded the limit {:.2f}GBs ({}b) with {:.2f}GBs ({}b) used and {:.2f}GBs ({}b) deleted.'.format(model.load(item), limit / GBs, limit, used / GBs, used, deleted / GBs, deleted)
            logger.info(line)
            lines.append(line)

    if lines:
        if send_email:
            logger.info('Sending email...')
            mails.send_mail('*****@*****.**', mails.EMPTY, body='\n'.join(lines), subject='Script: OsfStorage usage audit')
        else:
            logger.info('send_email is False, not sending email'.format(len(lines)))
        logger.info('{} offending project(s) and user(s) found'.format(len(lines)))
    else:
        logger.info('No offending projects or users found')
예제 #47
0
    def _send_preprint_confirmation(self, auth):
        # Send creator confirmation email
        recipient = self.node.creator
        event_type = utils.find_subscription_type('global_reviews')
        user_subscriptions = get_user_subscriptions(recipient, event_type)
        if self.provider._id == 'osf':
            logo = settings.OSF_PREPRINTS_LOGO
        else:
            logo = self.provider._id

        context = {
            'domain':
            settings.DOMAIN,
            'reviewable':
            self,
            'workflow':
            self.provider.reviews_workflow,
            'provider_url':
            '{domain}preprints/{provider_id}'.format(
                domain=self.provider.domain or settings.DOMAIN,
                provider_id=self.provider._id
                if not self.provider.domain else '').strip('/'),
            'provider_contact_email':
            self.provider.email_contact or settings.OSF_CONTACT_EMAIL,
            'provider_support_email':
            self.provider.email_support or settings.OSF_SUPPORT_EMAIL,
            'no_future_emails':
            user_subscriptions['none'],
            'is_creator':
            True,
            'provider_name':
            'OSF Preprints' if self.provider.name == 'Open Science Framework'
            else self.provider.name,
            'logo':
            logo,
        }

        mails.send_mail(recipient.username,
                        mails.REVIEWS_SUBMISSION_CONFIRMATION,
                        mimetype='html',
                        user=recipient,
                        **context)
예제 #48
0
def send_claim_registered_email(claimer, unreg_user, node, throttle=24 * 3600):
    unclaimed_record = unreg_user.get_unclaimed_record(node._primary_key)
    # roll the valid token for each email, thus user cannot change email and approve a different email address
    timestamp = unclaimed_record.get('last_sent')
    if not throttle_period_expired(timestamp, throttle):
        raise HTTPError(
            400,
            data=dict(
                message_long=
                'User account can only be claimed with an existing user once every 24 hours'
            ))
    unclaimed_record['token'] = generate_confirm_token()
    unclaimed_record['claimer_email'] = claimer.username
    unreg_user.save()
    referrer = User.load(unclaimed_record['referrer_id'])
    claim_url = web_url_for(
        'claim_user_registered',
        uid=unreg_user._primary_key,
        pid=node._primary_key,
        token=unclaimed_record['token'],
        _external=True,
    )
    # Send mail to referrer, telling them to forward verification link to claimer
    mails.send_mail(
        referrer.username,
        mails.FORWARD_INVITE_REGiSTERED,
        user=unreg_user,
        referrer=referrer,
        node=node,
        claim_url=claim_url,
        fullname=unclaimed_record['name'],
    )
    unclaimed_record['last_sent'] = get_timestamp()
    unreg_user.save()
    # Send mail to claimer, telling them to wait for referrer
    mails.send_mail(
        claimer.username,
        mails.PENDING_VERIFICATION_REGISTERED,
        fullname=claimer.fullname,
        referrer=referrer,
        node=node,
    )
예제 #49
0
def request_export(auth):
    user = auth.user
    if not throttle_period_expired(user.email_last_sent,
                                   settings.SEND_EMAIL_THROTTLE):
        raise HTTPError(
            httplib.BAD_REQUEST,
            data={
                'message_long':
                'Too many requests. Please wait a while before sending another account export request.',
                'error_type': 'throttle_error'
            })

    mails.send_mail(
        to_addr=settings.SUPPORT_EMAIL,
        mail=mails.REQUEST_EXPORT,
        user=auth.user,
    )
    user.email_last_sent = datetime.datetime.utcnow()
    user.save()
    return {'message': 'Sent account export request'}
예제 #50
0
파일: tasks.py 프로젝트: jwalz/osf.io
def inform_product_of_errors(initiator=None, provider=None, message=None):
    """Inform product owner of internal errors.
    """

    email = settings.PRODUCT_OWNER_EMAIL_ADDRESS.get('Registration')
    if not email:
        logger.warning('Missing email for OSF Registration product owner.')
        return

    if not message:
        message = 'Bulk upload preparation failure'
    user = f'{initiator._id}, {initiator.fullname}, {initiator.username}' if initiator else 'UNIDENTIFIED'
    provider_name = provider.name if provider else 'UNIDENTIFIED'
    mails.send_mail(
        to_addr=email,
        mail=mails.REGISTRATION_BULK_UPLOAD_PRODUCT_OWNER,
        message=message,
        user=user,
        provider_name=provider_name,
    )
예제 #51
0
def report_stuck_dois(dry_run=True):

    preprints_with_pending_dois = Preprint.objects.filter(preprint_doi_created__isnull=True,
                                                          is_published=True,
                                                          date_published__lt=timezone.now() - time_since_published)

    if preprints_with_pending_dois:
        guids = ', '.join(preprints_with_pending_dois.values_list('guids___id', flat=True))
        if not dry_run:
            mails.send_mail(
                to_addr=settings.OSF_SUPPORT_EMAIL,
                mail=mails.CROSSREF_DOIS_PENDING,
                pending_doi_count=preprints_with_pending_dois.count(),
                time_since_published=time_since_published.days,
                guids=guids,
            )
        else:
            logger.info('DRY RUN')

        logger.info('There were {} stuck registrations for CrossRef, email sent to help desk'.format(preprints_with_pending_dois.count()))
예제 #52
0
def _send_retraction_email(node, user):
    """ Sends Approve/Disapprove email for retraction of a public registration to user
        :param node: Node being retracted
        :param user: Admin user to be emailed
    """

    registration_link = node.web_url_for('view_project', _absolute=True)
    approval_time_span = settings.RETRACTION_PENDING_TIME.days * 24
    initiators_fullname = node.retraction.initiated_by.fullname

    if node.has_permission(user, 'admin'):
        approval_token = node.retraction.approval_state[
            user._id]['approval_token']
        disapproval_token = node.retraction.approval_state[
            user._id]['disapproval_token']
        approval_link = node.web_url_for(
            'node_registration_retraction_approve',
            token=approval_token,
            _absolute=True)
        disapproval_link = node.web_url_for(
            'node_registration_retraction_disapprove',
            token=disapproval_token,
            _absolute=True)

        mails.send_mail(
            user.username,
            mails.PENDING_RETRACTION_ADMIN,
            'plain',
            user=user,
            initiated_by=initiators_fullname,
            approval_link=approval_link,
            disapproval_link=disapproval_link,
            registration_link=registration_link,
            approval_time_span=approval_time_span,
        )
    else:
        mails.send_mail(user.username,
                        mails.PENDING_RETRACTION_NON_ADMIN,
                        user=user,
                        initiated_by=initiators_fullname,
                        registration_link=registration_link)
예제 #53
0
파일: views.py 프로젝트: ccfair/osf.io
def forgot_password_post():
    """Attempt to send user password reset or return respective error.
    """
    form = ForgotPasswordForm(request.form, prefix='forgot_password')

    if form.validate():
        email = form.email.data
        status_message = (
            'If there is an OSF account associated with {0}, an email with instructions on how to reset '
            'the OSF password has been sent to {0}. If you do not receive an email and believe you '
            'should have, please contact OSF Support. ').format(email)
        user_obj = get_user(email=email)
        if user_obj:
            if throttle_period_expired(user_obj.email_last_sent,
                                       settings.SEND_EMAIL_THROTTLE):
                user_obj.verification_key = security.random_string(20)
                user_obj.email_last_sent = datetime.datetime.utcnow()
                user_obj.save()
                reset_link = furl.urljoin(
                    settings.DOMAIN,
                    web_url_for('reset_password',
                                verification_key=user_obj.verification_key))
                mails.send_mail(to_addr=email,
                                mail=mails.FORGOT_PASSWORD,
                                reset_link=reset_link)
                status.push_status_message(status_message,
                                           kind='success',
                                           trust=False)
            else:
                status.push_status_message(
                    'You have recently requested to change your password. Please wait a little '
                    'while before trying again.',
                    kind='error',
                    trust=False)
        else:
            status.push_status_message(status_message,
                                       kind='success',
                                       trust=False)
    forms.push_errors_to_status(form.errors)
    return auth_login(forgot_password_form=form)
예제 #54
0
def main(send_email=False):
    logger.info('Starting Project storage audit')

    lines = []
    projects = {}
    users = defaultdict(lambda: (0, 0))

    top_level_nodes = AbstractNode.objects.get_roots()
    progress_bar = tqdm(total=top_level_nodes.count())
    top_level_nodes = top_level_nodes.iterator()

    for i, node in enumerate(top_level_nodes):
        progress_bar.update(i+1)
        if node._id in WHITE_LIST:
            continue  # Dont count whitelisted nodes against users
        projects[node._id] = get_usage(node)
        for contrib in node.contributors:
            if node.can_edit(user=contrib):
                users[contrib._id] = tuple(map(sum, zip(users[contrib._id], projects[node._id])))  # Adds tuples together, map(sum, zip((a, b), (c, d))) -> (a+c, b+d)

        if i % 25 == 0:
            gc.collect()
    progress_bar.close()

    for model, collection, limit in ((OSFUser, users, USER_LIMIT), (AbstractNode, projects, PROJECT_LIMIT)):
        for item, (used, deleted) in filter(functools.partial(limit_filter, limit), collection.items()):
            line = '{!r} has exceeded the limit {:.2f}GBs ({}b) with {:.2f}GBs ({}b) used and {:.2f}GBs ({}b) deleted.'.format(model.load(item), limit / GBs, limit, used / GBs, used, deleted / GBs, deleted)
            logger.info(line)
            lines.append(line)

    if lines:
        if send_email:
            logger.info('Sending email...')
            mails.send_mail('*****@*****.**', mails.EMPTY, body='\n'.join(lines), subject='Script: OsfStorage usage audit', can_change_preferences=False,)
        else:
            logger.info('send_email is False, not sending email'.format(len(lines)))
        logger.info('{} offending project(s) and user(s) found'.format(len(lines)))
    else:
        logger.info('No offending projects or users found')
예제 #55
0
def forgot_password_post():
    """Attempt to send user password reset or return respective error.
    """
    form = ForgotPasswordForm(request.form, prefix='forgot_password')

    if form.validate():
        email = form.email.data
        status_message = (
            'If there is an OSF account associated with {0}, an email with instructions on how to reset '
            'the OSF password has been sent to {0}. If you do not receive an email and believe you '
            'should have, please contact OSF Support. ').format(email)
        user_obj = get_user(email=email)
        if user_obj:
            #TODO: Remove this rate limiting and replace it with something that doesn't write to the User model
            now = datetime.datetime.utcnow()
            last_attempt = user_obj.forgot_password_last_post or now - datetime.timedelta(
                seconds=FORGOT_PASSWORD_MINIMUM_TIME)
            user_obj.forgot_password_last_post = now
            time_since_last_attempt = now - last_attempt
            if time_since_last_attempt.seconds >= FORGOT_PASSWORD_MINIMUM_TIME:
                user_obj.verification_key = security.random_string(20)
                user_obj.save()
                reset_link = "http://{0}{1}".format(
                    request.host,
                    web_url_for('reset_password',
                                verification_key=user_obj.verification_key))
                mails.send_mail(to_addr=email,
                                mail=mails.FORGOT_PASSWORD,
                                reset_link=reset_link)
                status.push_status_message(status_message, 'success')
            else:
                user_obj.save()
                status.push_status_message(
                    'You have recently requested to change your password. Please wait a little '
                    'while before trying again.', 'error')
        else:
            status.push_status_message(status_message, 'success')
    forms.push_errors_to_status(form.errors)
    return auth_login(forgot_password_form=form)
예제 #56
0
    def set_password(self, raw_password, notify=True):
        """Set the password for this user to the hash of ``raw_password``.
        If this is a new user, we're done. If this is a password change,
        then email the user about the change and clear all the old sessions
        so that users will have to log in again with the new password.

        :param raw_password: the plaintext value of the new password
        :param notify: Only meant for unit tests to keep extra notifications from being sent
        :rtype: list
        :returns: Changed fields from the user save
        """
        had_existing_password = self.has_usable_password()
        if self.username == raw_password:
            raise ChangePasswordError(
                ['Password cannot be the same as your email address'])
        super(OSFUser, self).set_password(raw_password)
        if had_existing_password and notify:
            mails.send_mail(to_addr=self.username,
                            mail=mails.PASSWORD_RESET,
                            mimetype='plain',
                            user=self)
            remove_sessions_for_user(self)
예제 #57
0
파일: views.py 프로젝트: ccfair/osf.io
def send_confirm_email(user, email):
    """Sends a confirmation email to `user` to a given email.

    :raises: KeyError if user does not have a confirmation token for the given
        email.
    """
    confirmation_url = user.get_confirmation_url(
        email,
        external=True,
        force=True,
    )

    try:
        merge_target = User.find_one(Q('emails', 'eq', email))
    except NoResultsFound:
        merge_target = None

    campaign = campaigns.campaign_for_user(user)
    # Choose the appropriate email template to use and add existing_user flag if a merge or adding an email.
    if merge_target:
        mail_template = mails.CONFIRM_MERGE
        confirmation_url = '{}?logout=1'.format(confirmation_url)
    elif campaign:
        mail_template = campaigns.email_template_for_campaign(campaign)
    elif user.is_active:
        mail_template = mails.CONFIRM_EMAIL
        confirmation_url = '{}?logout=1'.format(confirmation_url)
    else:
        mail_template = mails.INITIAL_CONFIRM_EMAIL

    mails.send_mail(
        email,
        mail_template,
        'plain',
        user=user,
        confirmation_url=confirmation_url,
        email=email,
        merge_target=merge_target,
    )
예제 #58
0
def main():
    prereg_csv = generate_prereg_csv()

    filename = 'prereg_{}.csv.gz'.format(timezone.now().isoformat())

    output = io.BytesIO()
    with gzip.GzipFile(filename=filename, mode='wb',
                       fileobj=output) as gzip_obj:
        gzip_obj.write(prereg_csv.getvalue())

    mails.send_mail(
        mail=mails.PREREG_CSV,
        to_addr=settings.PREREG_EMAIL,
        attachment_name=filename,
        attachment_content=output.getvalue(),
        can_change_preferences=False,
        logo=settings.OSF_PREREG_LOGO,
        celery=
        False  # attachment is not JSON-serializable, so don't pass it to celery
    )

    logger.info('Updated prereg CSV email sent.')
예제 #59
0
파일: views.py 프로젝트: WenTingZhu/osf.io
def forgot_password():
    form = ForgotPasswordForm(request.form, prefix='forgot_password')

    if form.validate():
        email = form.email.data
        user_obj = get_user(username=email)
        if user_obj:
            user_obj.verification_key = security.random_string(20)
            user_obj.save()
            reset_link = "http://{0}{1}".format(
                request.host,
                web_url_for('reset_password',
                            verification_key=user_obj.verification_key))
            mails.send_mail(to_addr=email,
                            mail=mails.FORGOT_PASSWORD,
                            reset_link=reset_link)
            status.push_status_message('Reset email sent to {0}'.format(email))
        else:
            status.push_status_message(
                'Email {email} not found'.format(email=email))

    forms.push_errors_to_status(form.errors)
    return auth_login(forgot_password_form=form)
def deactivate_requested_accounts(dry_run=True):
    users = OSFUser.objects.filter(requested_deactivation=True,
                                   contacted_deactivation=False,
                                   date_disabled__isnull=True)

    for user in users:
        if user.has_resources:
            logger.info(
                'OSF support is being emailed about deactivating the account of user {}.'
                .format(user._id))
            if not dry_run:
                mails.send_mail(
                    to_addr=OSF_SUPPORT_EMAIL,
                    mail=mails.REQUEST_DEACTIVATION,
                    user=user,
                    can_change_preferences=False,
                )
        else:
            logger.info('Disabling user {}.'.format(user._id))
            if not dry_run:
                user.disable_account()
                user.is_registered = False
                mails.send_mail(
                    to_addr=user.username,
                    mail=mails.REQUEST_DEACTIVATION_COMPLETE,
                    user=user,
                    contact_email=OSF_CONTACT_EMAIL,
                    can_change_preferences=False,
                )

        user.contacted_deactivation = True
        user.email_last_sent = timezone.now()
        if not dry_run:
            user.save()

    if dry_run:
        logger.info('Dry run complete')