Ejemplo n.º 1
0
 def remove_user(self, user, agent=None):
     """
     Un-assign user from request.
     :param user: user to remove
     :param agent: user performing this action
     """
     user_request = UserRequests.query.filter_by(
         user_guid=user.guid,
         auth_user_type=user.auth_user_type,
         request_id=self.request.id).one()
     self.__create_event(event_type.USER_REMOVED, user_request, agent)
     delete_object(user_request)
Ejemplo n.º 2
0
def remove_user_request(request_id, user_guid):
    """
    Remove user from request and sends email to all agency administrators and to user being removed.
    Delete row from UserRequests table and stores event object into Events.

    :param request_id: FOIL request ID
    :param user_guid: string guid of user being removed

    """
    user_request = UserRequests.query.options(joinedload(
        UserRequests.user)).filter_by(user_guid=user_guid,
                                      request_id=request_id).one()
    agency_admin_emails = get_agency_emails(request_id, admins_only=True)

    request = Requests.query.filter_by(id=request_id).one()
    agency_name = request.agency.name

    # send email to agency administrators
    tmp = safely_send_and_add_email(
        request_id,
        render_template(
            'email_templates/email_user_request_removed.html',
            request_id=request_id,
            name=' '.join(
                [user_request.user.first_name, user_request.user.last_name]),
            agency_name=agency_name,
            page=urljoin(flask_request.host_url,
                         url_for('request.view', request_id=request_id)),
            admin=True),
        'User Removed from Request {}'.format(request_id),
        to=agency_admin_emails)

    # send email to user being removed
    tmp = safely_send_and_add_email(
        request_id,
        render_template(
            'email_templates/email_user_request_removed.html',
            request_id=request_id,
            name=' '.join(
                [user_request.user.first_name, user_request.user.last_name]),
            agency_name=agency_name,
            page=urljoin(flask_request.host_url,
                         url_for('request.view', request_id=request_id))),
        'User Removed from Request {}'.format(request_id),
        to=[user_request.user.email])
    old_permissions = user_request.permissions
    old_point_of_contact = user_request.point_of_contact

    create_user_request_event(event_type.USER_REMOVED, user_request,
                              old_permissions, old_point_of_contact)
    delete_object(user_request)

    request.es_update()
Ejemplo n.º 3
0
def remove_user_request(request_id, user_guid):
    """
    Remove user from request and sends email to all agency administrators and to user being removed.
    Delete row from UserRequests table and stores event object into Events.

    :param request_id: FOIL request ID
    :param user_guid: string guid of user being removed

    """
    user_request = UserRequests.query.filter_by(user_guid=user_guid,
                                                request_id=request_id).first()
    agency_admin_emails = get_agency_emails(request_id, admins_only=True)

    request = Requests.query.filter_by(id=request_id).one()
    agency_name = request.agency.name

    # send email to agency administrators
    tmp = safely_send_and_add_email(
        request_id,
        render_template(
            'email_templates/email_user_request_removed.html',
            request_id=request_id,
            name=' '.join([user_request.user.first_name, user_request.user.last_name]),
            agency_name=agency_name,
            page=urljoin(flask_request.host_url, url_for('request.view', request_id=request_id)),
            admin=True),
        'User Removed from Request {}'.format(request_id),
        to=agency_admin_emails)

    # send email to user being removed
    tmp = safely_send_and_add_email(
        request_id,
        render_template(
            'email_templates/email_user_request_removed.html',
            request_id=request_id,
            name=' '.join([user_request.user.first_name, user_request.user.last_name]),
            agency_name=agency_name,
            page=urljoin(flask_request.host_url, url_for('request.view', request_id=request_id))),
        'User Removed from Request {}'.format(request_id),
        to=[user_request.user.email])
    old_permissions = user_request.permissions
    old_point_of_contact = user_request.point_of_contact

    create_user_request_event(event_type.USER_REMOVED, user_request, old_permissions, old_point_of_contact)
    delete_object(user_request)

    request.es_update()
Ejemplo n.º 4
0
def get_response_content(response_id):
    """
    Currently only supports File Responses.

    Request Parameters:
    - token: (optional) ephemeral access token

    :return: response file contents or
             redirect to login if user not authenticated and no token provided or
             400 error if response/file not found
    """
    response_ = Responses.query.filter_by(id=response_id, deleted=False).one()

    if response_ is not None and response_.type == FILE:
        upload_path = os.path.join(
            current_app.config["UPLOAD_DIRECTORY"],
            response_.request_id
        )
        filepath_parts = (
            upload_path,
            response_.name
        )
        filepath = os.path.join(*filepath_parts)
        serving_path = os.path.join(
            current_app.config['UPLOAD_SERVING_DIRECTORY'],
            response_.request_id,
            response_.name
        )
        token = flask_request.args.get('token')
        if fu.exists(filepath):
            if response_.is_public:
                # then we just serve the file, anyone can view it
                @after_this_request
                def remove(resp):
                    os.remove(serving_path)
                    return resp

                return fu.send_file(*filepath_parts, as_attachment=True)
            else:
                # check presence of token in url
                if token is not None:
                    resptok = ResponseTokens.query.filter_by(
                        token=token, response_id=response_id).first()
                    if resptok is not None:
                        if response_.privacy != PRIVATE:
                            @after_this_request
                            def remove(resp):
                                os.remove(serving_path)
                                return resp

                            return fu.send_file(*filepath_parts, as_attachment=True)
                        else:
                            delete_object(resptok)

                # if token not included, nonexistent, or is expired, but user is logged in
                if current_user.is_authenticated:
                    # user is agency or is public and response is not private
                    if (((current_user.is_public and response_.privacy != PRIVATE)
                         or current_user.is_agency)
                            # user is associated with request
                            and UserRequests.query.filter_by(
                                request_id=response_.request_id,
                                user_guid=current_user.guid
                            ).first() is not None):
                        @after_this_request
                        def remove(resp):
                            os.remove(serving_path)
                            return resp

                        return fu.send_file(*filepath_parts, as_attachment=True)
                    # user does not have permission to view file
                    return abort(403)
                else:
                    # redirect to login
                    return redirect(login_url(
                        login_manager.login_view,
                        next_url=url_for('request.view', request_id=response_.request_id)
                    ))
    return abort(404)  # file does not exist
Ejemplo n.º 5
0
def get_response_content(response_id):
    """
    Currently only supports File Responses.

    Request Parameters:
    - token: (optional) ephemeral access token

    :return: response file contents or
             redirect to login if user not authenticated and no token provided or
             400 error if response/file not found
    """
    response_ = Responses.query.filter_by(id=response_id, deleted=False).one()

    # if ((current_user.is_authenticated
    #    and current_user not in response_.request.agency_users
    #    and response_.request.requester != current_user)
    #    or flask_request.args.get('token') is None):
    #     return abort(403)

    if response_ is not None and response_.type == FILE:
        upload_path = os.path.join(
            current_app.config["UPLOAD_DIRECTORY"],
            response_.request_id
        )
        filepath_parts = (
            upload_path,
            response_.name
        )
        filepath = os.path.join(*filepath_parts)
        serving_path = os.path.join(
            current_app.config['UPLOAD_SERVING_DIRECTORY'],
            response_.request_id,
            response_.name
        )
        token = flask_request.args.get('token')
        if fu.exists(filepath):
            if token is not None:
                resptok = ResponseTokens.query.filter_by(
                    token=token, response_id=response_id).first()
                if resptok is not None:
                    if (datetime.utcnow() < resptok.expiration_date
                       and response_.privacy != PRIVATE):
                        @after_this_request
                        def remove(resp):
                            os.remove(serving_path)
                            return resp

                        return fu.send_file(*filepath_parts, as_attachment=True)
                    else:
                        delete_object(resptok)
            else:
                if current_user.is_authenticated:
                    # user is agency or is public and response is not private
                    if (((current_user.is_public and response_.privacy != PRIVATE)
                        or current_user.is_agency)
                        # user is associated with request
                        and UserRequests.query.filter_by(
                            request_id=response_.request_id,
                            user_guid=current_user.guid,
                            auth_user_type=current_user.auth_user_type
                       ).first() is not None):
                        @after_this_request
                        def remove(resp):
                            os.remove(serving_path)
                            return resp
                        return fu.send_file(*filepath_parts, as_attachment=True)
                    return abort(403)
                else:
                    # response is release and public  # TODO: Responses.is_release_public property
                    if (response_.privacy == RELEASE_AND_PUBLIC
                       and response_.release_date is not None
                       and datetime.utcnow() > response_.release_date):
                        @after_this_request
                        def remove(resp):
                            os.remove(serving_path)
                            return resp
                        return fu.send_file(*filepath_parts, as_attachment=True)
                    else:
                        return redirect(url_for(
                            'auth.login',
                            return_to_url=url_for('request.view', request_id=response_.request_id)
                        ))
                        # TODO: restore after saml/oauth implementation
                        # return redirect(url_for(
                        #     'auth.index',
                        #     sso2=True,
                        #     return_to=flask_request.base_url))
    return abort(404)
Ejemplo n.º 6
0
def get_response_content(response_id):
    """
    Currently only supports File Responses.

    Request Parameters:
    - token: (optional) ephemeral access token

    :return: response file contents or
             redirect to login if user not authenticated and no token provided or
             400 error if response/file not found
    """
    response_ = Responses.query.filter_by(id=response_id, deleted=False).one()

    if response_ is not None and response_.type == FILE:
        upload_path = os.path.join(
            current_app.config["UPLOAD_DIRECTORY"],
            response_.request_id
        )
        filepath_parts = (
            upload_path,
            response_.name
        )
        filepath = os.path.join(*filepath_parts)
        serving_path = os.path.join(
            current_app.config['UPLOAD_SERVING_DIRECTORY'],
            response_.request_id,
            response_.name
        )
        token = flask_request.args.get('token')
        if fu.exists(filepath):
            if response_.is_public:
                # then we just serve the file, anyone can view it
                @after_this_request
                def remove(resp):
                    os.remove(serving_path)
                    return resp

                return fu.send_file(*filepath_parts, as_attachment=True)
            else:
                # check presence of token in url
                if token is not None:
                    resptok = ResponseTokens.query.filter_by(
                        token=token, response_id=response_id).first()
                    if resptok is not None:
                        if response_.privacy != PRIVATE:
                            @after_this_request
                            def remove(resp):
                                os.remove(serving_path)
                                return resp

                            return fu.send_file(*filepath_parts, as_attachment=True)
                        else:
                            delete_object(resptok)

                # if token not included, nonexistent, or is expired, but user is logged in
                if current_user.is_authenticated:
                    # user is agency or is public and response is not private
                    if (((current_user.is_public and response_.privacy != PRIVATE)
                         or current_user.is_agency)
                            # user is associated with request
                            and UserRequests.query.filter_by(
                                request_id=response_.request_id,
                                user_guid=current_user.guid
                            ).first() is not None):
                        @after_this_request
                        def remove(resp):
                            os.remove(serving_path)
                            return resp

                        return fu.send_file(*filepath_parts, as_attachment=True)
                    # user does not have permission to view file
                    return abort(403)
                else:
                    # redirect to login
                    return redirect(login_url(
                        login_manager.login_view,
                        next_url=url_for('request.view', request_id=response_.request_id)
                    ))
    return abort(404)  # file does not exist
Ejemplo n.º 7
0
def patch(user_id):
    """
    Request Parameters:
    - title
    - organization
    - email
    - phone_number
    - fax_number
    - mailing_address
    - is_super
    - is_agency_active
    - is_agency_admin
    (Mailing Address)
    - zip
    - city
    - state
    - address_one
    - address_two

    Restrictions:
    - Anonymous Users
        - cannot access this endpoint
    - Agency Administrators
        - cannot change their agency status
        - can only update the agency status of users within their agency
        - cannot change any super user status
    - Super Users
        - cannot change their super user status
    - Agency Users
        - cannot change any user except for themselves or
          *anonymous* requesters for requests they are assigned to
        - cannot change super user or agency status
    - Public Users
        - can only update themselves
        - cannot change super user or agency status

    """
    if not current_user.is_anonymous:
        # attempt to parse user_id and find user
        try:
            guid, auth_type = user_id.split(USER_ID_DELIMITER)
            user_ = Users.query.filter_by(guid=guid,
                                          auth_user_type=auth_type).one()
        except (ValueError, NoResultFound, MultipleResultsFound):
            return jsonify({}), 404

        agency_ein = request.form.get('agency_ein', None)
        if agency_ein is None and not (auth_type
                                       == user_type_auth.ANONYMOUS_USER
                                       or 'is_super' in request.form):
            return jsonify({}), 404

        updating_self = current_user == user_
        current_user_is_agency_user = (
            current_user.is_agency and not current_user.is_super
            and not current_user.is_agency_admin(agency_ein)
            and current_user.is_agency_active(agency_ein))
        current_user_is_agency_admin = (
            current_user.is_agency and not current_user.is_super
            and current_user.is_agency_admin(agency_ein)
            and current_user.is_agency_active(agency_ein))
        same_agency = agency_ein in [
            agency.ein for agency in current_user.agencies.all()
        ]
        associated_anonymous_requester = (
            user_.is_anonymous_requester
            and current_user.user_requests.filter_by(
                request_id=user_.anonymous_request.id).first() is None)

        is_agency_admin = request.form.get('is_agency_admin')
        is_agency_active = request.form.get('is_agency_active')
        is_super = request.form.get('is_super')

        changing_status = any((is_agency_active, is_agency_admin, is_super))

        rform_copy = dict(request.form)
        try:
            rform_copy.pop('is_agency_admin')
            rform_copy.pop('is_agency_active')
            rform_copy.pop('agency_ein')
            changing_more_than_agency_status = len(rform_copy) != 0
        except KeyError:
            changing_more_than_agency_status = False

        # VALIDATE
        if ((
                updating_self and
            (
                # super user attempting to change their own super status
                (current_user.is_super and is_super is not None) or
                # agency admin or public user attempting to change their own agency/super status
                (changing_status and
                 (current_user_is_agency_admin or current_user.is_public)))) or
            (not updating_self and (
                # public user attempting to change another user
                current_user.is_public or
                # agency user attempting to change a agency/super status
                (current_user_is_agency_user and changing_status) or
                # agency user attempting to change a user that is not an anonymous requester
                # for a request they are assigned to
                (current_user_is_agency_user and
                 (not user_.is_anonymous_requester
                  or not associated_anonymous_requester)) or
                # agency admin attempting to change another user that is not in the same agency or
                # attempting to change more than just the agency status of a user
                (current_user_is_agency_admin
                 and not (associated_anonymous_requester
                          or user_.is_anonymous_requester) and
                 (not same_agency or changing_more_than_agency_status)) or
                # agency admin attempting to change an anonymous requester for a request
                # they are not assigned to
                (current_user_is_agency_admin
                 and associated_anonymous_requester)))):
            return jsonify({}), 403

        # UPDATE
        user_fields = [
            'email', 'phone_number', 'fax_number', 'title', 'organization'
        ]
        status_fields = ['is_agency_admin', 'is_agency_active', 'is_super']
        address_fields = ['zip', 'city', 'state', 'address_one', 'address_two']

        user_field_val = {
            'email': request.form.get('email'),
            'phone_number': request.form.get('phone'),
            'fax_number': request.form.get('fax'),
            'title': request.form.get('title'),
            'organization': request.form.get('organization'),
        }
        status_field_val = {
            'is_agency_admin': request.form.get('is_agency_admin'),
            'is_agency_active': request.form.get('is_agency_active'),
            'is_super': request.form.get('is_super')
        }
        address_field_val = {
            'address_one': request.form.get('address_one'),
            'address_two': request.form.get('address_two'),
            'zip': request.form.get('zipcode'),
            'city': request.form.get('city'),
            'state': request.form.get('state')
        }

        # check if missing contact information
        if (user_field_val['email'] == ''
                and user_field_val['phone_number'] == ''
                and user_field_val['fax_number'] == '' and
            (address_field_val['city'] == '' or address_field_val['zip'] == ''
             or address_field_val['state'] == ''
             or address_field_val['address_one'] == '')):
            return jsonify({"error": "Missing contact information."}), 400

        old = {}
        old_address = {}
        new = {}
        new_address = {}

        for field in status_fields:
            if status_field_val[field] is not None:
                if field == 'is_agency_admin':
                    cur_val = user_.is_agency_admin(agency_ein)
                elif field == 'is_agency_active':
                    cur_val = user_.is_agency_active(agency_ein)
                else:
                    cur_val = getattr(user_, field)
                new_val = eval_request_bool(status_field_val[field])
                if cur_val != new_val:
                    old[field] = cur_val
                    new[field] = new_val

        for field in user_fields:
            val = user_field_val[field]
            if val is not None:
                if val == '':
                    user_field_val[
                        field] = None  # null in db, not empty string
                cur_val = getattr(user_, field)
                new_val = user_field_val[field]
                if cur_val != new_val:
                    old[field] = cur_val
                    new[field] = new_val

        for field in address_fields:
            val = address_field_val[field]
            if val is not None:
                if val == '':
                    address_field_val[field] = None
                cur_val = (user_.mailing_address.get(field)
                           if user_.mailing_address else None)
                new_val = address_field_val[field]
                if cur_val != new_val:
                    old_address[field] = cur_val
                    new_address[field] = new_val

        if new or new_address:
            # in spite of not changing, the guid and auth type of
            # the user being updated is added to Events.new_value
            # in order to identify this user
            new['user_guid'] = user_.guid
            new['auth_user_type'] = user_.auth_user_type

            if new_address:
                new['mailing_address'] = new_address
            if old_address:
                old['mailing_address'] = old_address

            if ('is_agency_admin' in new) or ('is_agency_active' in new):
                new['agency_ein'] = agency_ein
                update_object(new, AgencyUsers, (guid, auth_type, agency_ein))
            else:
                update_object(new, Users, (guid, auth_type))

            # create event(s)
            event_kwargs = {
                'request_id':
                user_.anonymous_request.id
                if user_.is_anonymous_requester else None,
                'response_id':
                None,
                'user_guid':
                current_user.guid,
                'auth_user_type':
                current_user.auth_user_type,
                'timestamp':
                datetime.utcnow()
            }

            if changing_status:
                new_statuses = {}
                old_statuses = {}
                for field in status_fields:
                    if new.get(field) is not None:
                        new_statuses[field] = new.pop(field)
                        old_statuses[field] = old.pop(field)

                # TODO: a better way to store user identifiers (than in the value columns)
                new_statuses['user_guid'] = user_.guid
                new_statuses['auth_user_type'] = user_.auth_user_type
                new_statuses['agency_ein'] = agency_ein

                is_agency_active = new_statuses.get('is_agency_active')
                is_agency_admin = new_statuses.get('is_agency_admin')

                if is_agency_active is not None and not is_agency_active:
                    # remove ALL UserRequests
                    for user_request in user_.user_requests.all():
                        create_user_request_event(event_type.USER_REMOVED,
                                                  user_request)
                        delete_object(user_request)
                elif is_agency_admin is not None:

                    def set_permissions_and_create_event(user_req, perms):
                        """
                        Set permissions for a user request and create a
                        'user_permissions_changed' Event.

                        :param user_req: user request
                        :param perms: permissions to set for user request
                        """
                        old_permissions = user_req.permissions
                        user_request.set_permissions(perms)
                        create_user_request_event(event_type.USER_PERM_CHANGED,
                                                  user_req, old_permissions)

                    if is_agency_admin:
                        permissions = Roles.query.filter_by(
                            name=role_name.AGENCY_ADMIN).one().permissions
                        # create UserRequests for ALL existing requests under user's agency where user is not assigned
                        # for where the user *is* assigned, only change the permissions
                        for req in user_.agencies.filter_by(
                                ein=agency_ein).one().requests:
                            user_request = UserRequests.query.filter_by(
                                request_id=req.id,
                                user_guid=user_.guid,
                                auth_user_type=user_.auth_user_type).first()
                            if user_request is None:
                                user_request = UserRequests(
                                    user_guid=user_.guid,
                                    auth_user_type=user_.auth_user_type,
                                    request_id=req.id,
                                    request_user_type=user_type_request.AGENCY,
                                    permissions=permissions)
                                create_object(user_request)
                                create_user_request_event(
                                    event_type.USER_ADDED, user_request)
                            else:
                                set_permissions_and_create_event(
                                    user_request, permissions)

                    else:
                        # update ALL UserRequests (strip user of permissions)
                        for user_request in user_.user_requests.all():
                            set_permissions_and_create_event(
                                user_request, permission.NONE)

                # TODO: single email detailing user changes?

                create_object(
                    Events(type_=event_type.USER_STATUS_CHANGED,
                           previous_value=old_statuses,
                           new_value=new_statuses,
                           **event_kwargs))

            if old:  # something besides status changed ('new' holds user guid and auth type)
                create_object(
                    Events(type_=(event_type.REQUESTER_INFO_EDITED
                                  if user_.is_anonymous_requester else
                                  event_type.USER_INFO_EDITED),
                           previous_value=old,
                           new_value=new,
                           **event_kwargs))
            return jsonify({}), 200
        else:
            return jsonify({"message": "No changes detected."}), 200

    return jsonify({}), 403