示例#1
0
def edit_request_info():
    """
    Edits the title and agency request summary of a FOIL request through an API PUT method.
    Retrieves updated edited content from AJAX call on view_request page and stores changes into database.

    :return: JSON Response with updated content: either request title or agency request summary)
    """
    edit_request = flask_request.form
    request_id = flask_request.form.get('pk')
    current_request = Requests.query.filter_by(id=request_id).first()
    previous_value = {}
    new_value = {}
    type_ = ''
    val = edit_request['value'].strip()
    if edit_request['name'] == 'title':
        previous_value['title'] = current_request.title
        new_value['title'] = val
        type_ = event_type.REQ_TITLE_EDITED
    elif edit_request['name'] == 'agency_request_summary':
        previous_value['agency_request_summary'] = current_request.agency_request_summary
        new_value['agency_request_summary'] = val
        type_ = event_type.REQ_AGENCY_REQ_SUM_EDITED
    update_object({edit_request['name']: val if val else None},
                  Requests,
                  current_request.id)
    create_request_info_event(request_id,
                              type_,
                              previous_value,
                              new_value)
    return jsonify(edit_request), 200
示例#2
0
def edit_privacy():
    """
    Edits the privacy privacy options of a request's title and agency description.
    Retrieves updated privacy options from AJAX call on view_request page and stores changes into database.

    :return: JSON Response with updated title and agency description privacy options
    """
    request_id = flask_request.form.get('id')
    current_request = Requests.query.filter_by(id=request_id).first()
    privacy = {}
    previous_value = {}
    new_value = {}
    title = flask_request.form.get('title')
    agency_request_summary = flask_request.form.get('agency_request_summary')
    type_ = ''
    if title is not None:
        privacy['title'] = title == 'true'
        previous_value['privacy'] = current_request.privacy['title']
        new_value['privacy'] = privacy['title']
        type_ = event_type.REQ_TITLE_PRIVACY_EDITED
    elif agency_request_summary is not None:
        privacy['agency_request_summary'] = agency_request_summary == 'true'
        previous_value['privacy'] = current_request.privacy[
            'agency_request_summary']
        new_value['privacy'] = privacy['agency_request_summary']
        type_ = event_type.REQ_AGENCY_REQ_SUM_PRIVACY_EDITED
    update_object({'privacy': privacy}, Requests, current_request.id)
    create_request_info_event(request_id, type_, previous_value, new_value)
    return jsonify(privacy), 200
示例#3
0
def saml_slo(saml_sp):
    """Generate a SAML LogoutRequest for the user.

    Args:
        saml_sp (OneLogin_Saml2_Auth): SAML SP Instance

    Returns:
        Response Object: Redirect the user to the IdP for SLO.
    """
    name_id = None
    session_index = None
    if 'samlNameId' in session:
        name_id = session['samlNameId']
    if 'samlSessionIndex' in session:
        session_index = session['samlSessionIndex']

    update_object(
        {
            'session_id': None
        },
        Users,
        current_user.guid
    )

    return saml_sp.logout(name_id=name_id, session_index=session_index)
示例#4
0
def edit_request_info():
    """
    Edits the title and agency description of a FOIL request through an API PUT method.
    Retrieves updated edited content from AJAX call on view_request page and stores changes into database.

    :return: JSON Response with updated content: either request title or agency description)
    """
    edit_request = flask_request.form
    request_id = flask_request.form.get('pk')
    current_request = Requests.query.filter_by(id=request_id).first()
    previous_value = {}
    new_value = {}
    type_ = ''
    val = edit_request['value'].strip()
    if edit_request['name'] == 'title':
        previous_value['title'] = current_request.title
        new_value['title'] = val
        type_ = event_type.REQ_TITLE_EDITED
    elif edit_request['name'] == 'agency_request_summary':
        previous_value[
            'agency_request_summary'] = current_request.agency_request_summary
        new_value['agency_request_summary'] = val
        type_ = event_type.REQ_AGENCY_REQ_SUM_EDITED
    update_object({edit_request['name']: val if val else None}, Requests,
                  current_request.id)
    create_request_info_event(request_id, type_, previous_value, new_value)
    return jsonify(edit_request), 200
示例#5
0
def edit_privacy():
    """
    Edits the privacy privacy options of a request's title and agency request summary.
    Retrieves updated privacy options from AJAX call on view_request page and stores changes into database.

    :return: JSON Response with updated title and agency request summary privacy options
    """
    request_id = flask_request.form.get('id')
    current_request = Requests.query.filter_by(id=request_id).first()
    privacy = {}
    previous_value = {}
    new_value = {}
    title = flask_request.form.get('title')
    agency_request_summary = flask_request.form.get('agency_request_summary')
    type_ = ''
    if title is not None:
        privacy['title'] = title == 'true'
        previous_value['privacy'] = current_request.privacy['title']
        new_value['privacy'] = privacy['title']
        type_ = event_type.REQ_TITLE_PRIVACY_EDITED
    elif agency_request_summary is not None:
        privacy['agency_request_summary'] = agency_request_summary == 'true'
        previous_value['privacy'] = current_request.privacy['agency_request_summary']
        new_value['privacy'] = privacy['agency_request_summary']
        type_ = event_type.REQ_AGENCY_REQ_SUM_PRIVACY_EDITED
    update_object({'privacy': privacy},
                  Requests,
                  current_request.id)
    create_request_info_event(request_id,
                              type_,
                              previous_value,
                              new_value)
    return jsonify(privacy), 200
示例#6
0
 def test_json_update(self):
     self.assertEqual(self.rf.request.privacy, {
         'title': False,
         'agency_request_summary': True
     })
     # check single value change
     with patch('app.models.Requests.es_update'):
         update_object({'privacy': {
             'title': True
         }}, Requests, self.request_id)
     req = self.refetch_request()
     self.assertEqual(req.privacy, {
         'title': True,
         'agency_request_summary': True
     })
     # check multiple value changes
     with patch('app.models.Requests.es_update'):
         update_object(
             {'privacy': {
                 'title': False,
                 'agency_request_summary': False
             }}, Requests, self.request_id)
     req = self.refetch_request()
     self.assertEqual(req.privacy, {
         'title': False,
         'agency_request_summary': False
     })
示例#7
0
def index():
    fresh_login = request.args.get('fresh_login', False)
    if current_user.is_authenticated and fresh_login:
        if current_user.session_id is not None:
            return render_template('main/home.html', duplicate_session=True)
        update_object({'session_id': session.sid_s}, Users,
                      (current_user.guid, current_user.auth_user_type))
    return render_template('main/home.html')
示例#8
0
def set_point_of_contact(request_id, user_request, point_of_contact):
    """
    Toggles point of contact of a given request
    :param request_id: FOIL request ID
    :param user_request: UserRequest row to be changed
    :param point_of_contact: boolean flag for point of contact
    """
    update_object({"point_of_contact": point_of_contact}, UserRequests,
                  (user_request.user_guid, request_id))
示例#9
0
def set_point_of_contact(request_id, user_request, point_of_contact):
    """
    Toggles point of contact of a given request
    :param request_id: FOIL request ID
    :param user_request: UserRequest row to be changed
    :param point_of_contact: boolean flag for point of contact
    """
    update_object({"point_of_contact": point_of_contact},
                  UserRequests,
                  (user_request.user_guid, request_id)
                  )
示例#10
0
 def test_multifield_update(self):
     new_title = "this title is betta, is fasta, is stronga"
     new_description = "it's the batman"
     with patch('app.models.Requests.es_update'):
         update_object({
             'title': new_title,
             'description': new_description
         }, Requests, self.request_id)
     req = self.refetch_request()
     self.assertEqual([req.title, req.description],
                      [new_title, new_description])
示例#11
0
 def test_es_update(self, es_update_patch):
     role = Roles.query.first()
     # check called for model with 'es_update' (Requests)
     update_object({'title': 'new and improved TITLE X50 DELUXE'}, Requests,
                   self.request_id)
     es_update_patch.assert_called_once_with()
     # check not called for model without 'es_update' (Roles)
     try:
         update_object({'name': 'nombre'}, Roles, role.id)
     except AttributeError:
         self.fail('es_update() called when it should not have been.')
示例#12
0
def index():
    fresh_login = request.args.get('fresh_login', False)
    if current_user.is_authenticated and fresh_login:
        if current_user.session_id is not None:
            return render_template('main/home.html', duplicate_session=True)
        update_object(
            {
                'session_id': session.sid_s
            },
            Users,
            current_user.guid
        )
    return render_template('main/home.html')
示例#13
0
def fix_due_dates():  # for "America/New_York"
    """
    Forgot to set due date hour to 5:00 PM in migration script before
    converting to utc. Besides having the incorrect time, this also means
    certain due dates do not fall on business days.
    """
    from app.lib.db_utils import update_object
    for request in Requests.query.all():
        update_object(
            {
                "due_date":
                request.due_date.replace(
                    hour=22, minute=00, second=00, microsecond=00)
            }, Requests, request.id)
示例#14
0
def fix_anonymous_requesters():
    """
    Ensures there is only one anonymous requester per request by
    creating a new anonymous requester (User) for every User Requests record with
    a duplicate anonymous requester guid and updates the User Requests record.
    The new user will be identical to the existing one with the exception of the guid.
    """
    from app.constants import user_type_request
    from app.request.utils import generate_guid
    from app.lib.db_utils import create_object, update_object

    guids = db.engine.execute("""
        SELECT
          user_requests.user_guid AS "GUID"
        FROM user_requests
          JOIN users ON user_requests.user_guid = users.guid AND user_requests.auth_user_type = users.auth_user_type
        WHERE user_requests.request_user_type = 'requester'
        GROUP BY user_requests.user_guid
        HAVING COUNT(user_requests.request_id) > 1;
    """)

    for guid, in guids:
        # get all User Requests with dups, excluding the first (since we need to change all but 1)
        for ur in UserRequests.query.filter_by(
                user_guid=guid,
                request_user_type=user_type_request.REQUESTER).offset(1):
            user = Users.query.filter_by(
                guid=guid, auth_user_type=user_type_auth.ANONYMOUS_USER).one()
            new_guid = generate_guid()
            print("{} -> {}".format(guid, new_guid))
            # create new anonymous requester with new guid
            create_object(
                Users(guid=new_guid,
                      auth_user_type=user_type_auth.ANONYMOUS_USER,
                      email=user.email,
                      first_name=user.first_name,
                      last_name=user.last_name,
                      title=user.title,
                      organization=user.organization,
                      email_validated=False,
                      terms_of_use_accepted=False,
                      phone_number=user.phone_number,
                      fax_number=user.fax_number,
                      mailing_address=user.mailing_address))
            # update user request with new guid
            update_object({"user_guid": new_guid}, UserRequests,
                          (ur.user_guid, ur.auth_user_type, ur.request_id))
示例#15
0
def oauth_logout():
    timed_out = eval_request_bool(request.args.get('timeout'))
    forced_logout = eval_request_bool(request.args.get('forced_logout'))
    if forced_logout:
        user_session = redis_get_user_session(current_user.session_id)
        if user_session is not None:
            user_session.destroy()
    if timed_out:
        flash("Your session timed out. Please login again", category='info')
    if 'token' in session:
        revoke_and_remove_access_token()
    if current_user.is_anonymous:
        return redirect(url_for("main.index"))
    update_object({'session_id': None}, Users, (current_user.guid, current_user.auth_user_type))
    logout_user()
    session.destroy()
    if forced_logout:
        return redirect(url_for("auth.login"))
    return redirect(url_for("main.index"))
示例#16
0
def generate_request_id(agency_ein):
    """
    Generates an agency-specific FOIL request id.

    :param agency_ein: agency_ein ein used to generate the request_id
    :return: generated FOIL Request ID (FOIL - year - agency ein - 5 digits for request number)
    """
    if agency_ein:
        agency = Agencies.query.filter_by(ein=agency_ein).one(
        )  # This is the actual agency (including sub-agencies)
        parent_ein = _get_parent_ein(agency.parent_ein)
        next_request_number = Agencies.query.filter_by(ein=parent_ein).one(
        ).next_request_number  # Parent agencies handle the request counting, not sub-agencies
        update_object({'next_request_number': next_request_number + 1},
                      Agencies, parent_ein)
        agency_ein = agency.parent_ein
        request_id = "FOIL-{0:s}-{1!s}-{2:05d}".format(
            datetime.utcnow().strftime("%Y"), agency_ein,
            int(next_request_number))
        return request_id
    return None
示例#17
0
def update_openrecords_user(form):
    """
    Update OpenRecords-specific user attributes.
    :param form: validated ManageUserAccountForm or ManageAgencyUserAccountForm
    :type form: app.auth.forms.ManageUserAccountForm or app.auth.forms.ManageAgencyUserAccountForm
    """
    update_object(
        {
            'title':
            form.title.data,
            'organization':
            form.organization.data,
            'notification_email':
            form.notification_email.data,
            'phone_number':
            form.phone_number.data,
            'fax_number':
            form.fax_number.data,
            'mailing_address':
            create_mailing_address(form.address_one.data or None,
                                   form.city.data or None, form.state.data
                                   or None, form.zipcode.data or None,
                                   form.address_two.data or None)
        }, Users, (current_user.guid, current_user.auth_user_type))

    if current_user.is_agency and current_user.default_agency_ein != form.default_agency.data:
        update_object({'is_primary_agency': False}, AgencyUsers,
                      (current_user.guid, current_user.auth_user_type,
                       current_user.default_agency_ein))
        update_object({'is_primary_agency': True}, AgencyUsers,
                      (current_user.guid, current_user.auth_user_type,
                       form.default_agency.data))
示例#18
0
def _update_user_data(user, guid, user_type, email, first_name, middle_initial,
                      last_name):
    """
    Update specified user with the information provided, which is
    assumed to have originated from an NYC Service Account, and set
    `email_validated` and `terms_of_use_accepted` (this function
    should be called AFTER email validation and terms-of-use acceptance
    has been completed).

    Update any database objects this user is associated with.
    - user_requests
    - events
    In order to prevent a possbile negative performance impact
    (due to foreign keys CASCADE), guid and user_type are compared with
    stored user attributes and are excluded from the update if both are identical.
    """
    updated_data = {
        'email': email,
        'first_name': first_name,
        'middle_initial': middle_initial,
        'last_name': last_name,
        'email_validated': True,
        'terms_of_use_accepted': True,
    }
    if guid != user.guid or user_type != user.auth_user_type:
        updated_data.update(guid=guid, auth_user_type=user_type)
        update_events_values = Events.query.filter(
            Events.new_value['user_guid'].astext == user.guid,
            Events.new_value['auth_user_type'].astext ==
            user.auth_user_type).all()
        for event in update_events_values:
            update_object(
                {
                    'new_value': {
                        'user_guid': guid,
                        'auth_user_type': user_type
                    }
                }, Events, event.id)
    update_object(updated_data, Users, (user.guid, user.auth_user_type))
示例#19
0
def patch(agency_ein):
    """
    Only accessible by Super Users

    Currently only changes:
        is_active
    """
    if not current_user.is_anonymous and current_user.is_super:
        is_active = request.form.get('is_active')
        if is_active is not None and Agencies.query.filter_by(
                ein=agency_ein).first() is not None:
            update_object({'is_active': eval_request_bool(is_active)},
                          Agencies, agency_ein)
            create_object(
                Events(request_id=None,
                       user_guid=current_user.guid,
                       auth_user_type=current_user.auth_user_type,
                       type_=AGENCY_ACTIVATED,
                       new_value={"ein": agency_ein},
                       timestamp=datetime.utcnow()))
            return '', 200
        return '', 400
    return '', 403
示例#20
0
def generate_request_id(agency_ein):
    """
    Generates an agency-specific FOIL request id.

    :param agency_ein: agency_ein ein used to generate the request_id
    :return: generated FOIL Request ID (FOIL - year - agency ein - 5 digits for request number)
    """
    if agency_ein:
        agency = Agencies.query.filter_by(
            ein=agency_ein).one()  # This is the actual agency (including sub-agencies)
        next_request_number = Agencies.query.filter_by(
            ein=agency.formatted_parent_ein).one().next_request_number  # Parent agencies handle the request counting, not sub-agencies
        agency_ein = agency.parent_ein
        request_id = "FOIL-{0:s}-{1!s}-{2:05d}".format(
            datetime.utcnow().strftime("%Y"), agency_ein, int(next_request_number))
        if Requests.query.filter_by(id=request_id).one_or_none():
            update_object(
                {'next_request_number': next_request_number + 1},
                Agencies,
                agency.ein
            )
            request_id = generate_request_id(agency.ein)
        return request_id
    return None
示例#21
0
def update_user(guid=None, auth_user_type=None, **kwargs):
    """
    Updates a user if they exist in the database.
    :param guid:
    :param kwargs: Fields that need to be updated in the user.
    :return: GUID + UserType of the user (forms unique ID)
    """
    user = str()
    if not guid:
        return None

    user = update_object(kwargs, Users, obj_id=(guid, auth_user_type))

    if not user:
        return None
    return user
示例#22
0
def edit_privacy():
    """
    Edits the privacy privacy options of a request's title and agency description.
    Retrieves updated privacy options from AJAX call on view_request page and stores changes into database.

    :return: JSON Response with updated title and agency description privacy options
    """
    request_id = flask_request.form.get('id')
    current_request = Requests.query.filter_by(id=request_id).first()
    privacy = {}
    previous_value = {}
    new_value = {}
    title = flask_request.form.get('title')
    agency_desc = flask_request.form.get('agency_desc')
    type_ = ''
    if title is not None:
        privacy['title'] = title == 'true'
        previous_value['privacy'] = current_request.privacy['title']
        new_value['privacy'] = title
        type_ = event_type.REQ_TITLE_PRIVACY_EDITED
    elif agency_desc is not None:
        privacy['agency_description'] = agency_desc == 'true'
        previous_value['privacy'] = current_request.privacy[
            'agency_description']
        new_value['privacy'] = agency_desc
        type_ = event_type.REQ_AGENCY_DESC_PRIVACY_EDITED
        if not privacy['agency_description']:
            # if current_request.agency_description_release_date:
            previous_value['release_date'] = None
            release_date = calendar.addbusdays(datetime.utcnow(), offset=20)
            update_object(
                {
                    'privacy': privacy,
                    'agency_description_release_date': release_date
                }, Requests, current_request.id)
            new_value['release_date'] = release_date.isoformat()
        else:
            previous_value[
                'release_date'] = current_request.agency_description_release_date.isoformat(
                )
            update_object(
                {
                    'privacy': privacy,
                    'agency_description_release_date': None
                }, Requests, current_request.id)
            new_value['release_date'] = None
        create_edit_event(request_id, type_, previous_value, new_value)
        return jsonify(privacy), 200
    update_object({'privacy': privacy}, Requests, current_request.id)
    create_edit_event(request_id, type_, previous_value, new_value)
    return jsonify(privacy), 200
示例#23
0
def update_openrecords_user(form):
    """
    Update OpenRecords-specific user attributes.

    Args:
        form (app.auth.forms.ManageAgencyUserAccountForm OR app.auth.forms.ManageUserAccountForm): validated form
    """
    update_object(
        {
            'title': form.title.data,
            'organization': form.organization.data,
            'notification_email': form.notification_email.data,
            'phone_number': form.phone_number.data,
            'fax_number': form.fax_number.data,
            '_mailing_address': create_mailing_address(
                form.address_one.data or None,
                form.city.data or None,
                form.state.data or None,
                form.zipcode.data or None,
                form.address_two.data or None)
        },
        Users,
        current_user.guid
    )

    if current_user.is_agency and current_user.default_agency_ein != form.default_agency.data:
        update_object(
            {'is_primary_agency': False},
            AgencyUsers,
            (current_user.guid, current_user.default_agency_ein)
        )
        update_object(
            {'is_primary_agency': True},
            AgencyUsers,
            (current_user.guid, form.default_agency.data)
        )
示例#24
0
def update_agency_active_status(agency_ein, is_active):
    """
    Update the active status of an agency.
    :param agency_ein: String identifier for agency (4 characters)
    :param is_active: Boolean value for agency active status (True = Active)
    :return: Boolean value (True if successfully changed active status)
    """
    agency = Agencies.query.filter_by(ein=agency_ein).first()
    is_valid_agency = agency is not None
    activate_agency = eval_request_bool(is_active)

    if is_active is not None and is_valid_agency:
        update_object({'is_active': activate_agency}, Agencies, agency_ein)
        if activate_agency:
            create_object(
                Events(request_id=None,
                       user_guid=current_user.guid,
                       type_=AGENCY_ACTIVATED,
                       previous_value={
                           "ein": agency_ein,
                           "is_active": "False"
                       },
                       new_value={
                           "ein": agency_ein,
                           "is_active": "True"
                       },
                       timestamp=datetime.utcnow()))
            # create request documents
            for request in agency.requests:
                request.es_create()

            return True
        else:
            create_object(
                Events(request_id=None,
                       user_guid=current_user.guid,
                       type_=AGENCY_DEACTIVATED,
                       previous_value={
                           "ein": agency_ein,
                           "is_active": "True"
                       },
                       new_value={
                           "ein": agency_ein,
                           "is_active": "False"
                       },
                       timestamp=datetime.utcnow()))
            # remove requests from index
            for request in agency.requests:
                request.es_delete()
            # deactivate agency users
            for user in agency.active_users:
                update_object(
                    {
                        "is_agency_active": "False",
                        "is_agency_admin": "False"
                    }, AgencyUsers, (user.guid, agency_ein))
                create_object(
                    Events(request_id=None,
                           user_guid=current_user.guid,
                           type_=AGENCY_USER_DEACTIVATED,
                           previous_value={
                               "user_guid": user.guid,
                               "ein": agency_ein,
                               "is_active": "True"
                           },
                           new_value={
                               "user_guid": user.guid,
                               "ein": agency_ein,
                               "is_active": "False"
                           },
                           timestamp=datetime.utcnow()))

            return True
    return False
示例#25
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

    """

    # Anonymous users cannot access endpoint
    if current_user.is_anonymous:
        return jsonify(
            {'error': 'Anonymous users cannot access this endpoint'}), 403

    # Public users cannot access endpoint
    if current_user.is_public:
        return jsonify({'error':
                        'Public users cannot access this endpoint'}), 403

    # Unauthenticated users cannot access endpoint
    if not current_user.is_authenticated:
        return jsonify(
            {'error': 'User must be authenticated to access endpoint'}), 403

    # Retrieve the user
    user_ = Users.query.filter_by(guid=user_id).one_or_none()

    # If the user does not exist, return 404 - Not Found
    if not user_:
        return jsonify({'error': 'Specified user does not exist.'}), 404

    # Gather Form details
    is_agency_admin = eval_request_bool(
        request.form.get('is_agency_admin')) if request.form.get(
            'is_agency_admin', None) else None
    is_agency_active = eval_request_bool(
        request.form.get('is_agency_active')) if request.form.get(
            'is_agency_active', None) else None
    is_super = eval_request_bool(
        request.form.get('is_super')) if request.form.get('is_super',
                                                          None) else None

    agency_ein = request.form.get('agency_ein', None)

    # Checks that apply if user is changing their own profile
    changing_self = current_user == user_

    # Agency User Restrictions (applies to Admins and Regular Users)
    if user_.is_agency:
        # Endpoint can only be used for a specific agency
        if not agency_ein:
            return jsonify({
                'error':
                'agency_ein must be provided to modify an agency user'
            }), 400

        # Agency must exist and be active to modify users
        agency = Agencies.query.filter_by(ein=agency_ein).one_or_none()
        if not agency and agency.is_active:
            return jsonify(
                {'error':
                 'Agency must exist in the database and be active'}), 400

        if not current_user.is_super:
            # Current user must belong to agency specified by agency_ein
            current_user_is_agency_admin = current_user.is_agency_admin(
                agency.ein)

            if not current_user_is_agency_admin:
                return jsonify({
                    'error':
                    'Current user must belong to agency specified by agency_ein'
                }), 400

            user_in_agency = AgencyUsers.query.filter(
                AgencyUsers.user_guid == user_.guid,
                AgencyUsers.agency_ein == agency_ein).one_or_none()

            if user_in_agency is None:
                return jsonify({
                    'error':
                    'User to be modified must belong to agency specified by agency_ein'
                }), 400

        # Non-Agency Admins cannot access endpoint to modify other agency_users
        if not current_user.is_super and not current_user.is_agency_admin(
                agency_ein):
            return jsonify(
                {'error': 'User must be agency admin to modify users'}), 403

        # Cannot modify super status when changing agency active or agency admin status
        if (is_agency_admin or is_agency_active) and is_super:
            return jsonify({
                'error':
                'Cannot modify super status when changing agency active or agency admin status'
            }), 400

        if changing_self:
            # Super users cannot change their own is_super value
            if current_user.is_super and is_super:
                return jsonify({
                    'error':
                    'Super users cannot change their own `super` status'
                }), 400

            if is_agency_admin:
                return jsonify({
                    'error':
                    'Agency Administrators cannot change their administrator permissions'
                }), 400

    elif user_.is_public:
        if current_user != user_:
            return jsonify({
                'error':
                'Public user attributes cannot be modified by agency users.'
            }), 400

    elif user_.is_anonymous_requester:
        ur = current_user.user_requests.filter_by(
            request_id=user_.anonymous_request.id).one_or_none()
        if not ur:
            return jsonify({
                'error':
                'Agency users can only modify anonymous requesters for requests where they are assigned.'
            }), 403

        if not ur.has_permission(permission.EDIT_REQUESTER_INFO):
            return jsonify({
                'error':
                'Current user does not have EDIT_REQUESTER_INFO permission'
            }), 403

    # Gather User Fields

    user_editable_fields = user_attrs.UserEditableFieldsDict(
        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'),
        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'))
    status_field_val = user_attrs.UserStatusDict(
        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'))
    if changing_self:
        if not user_editable_fields.is_valid:
            return jsonify({"error": "Missing contact information."}), 400
    else:
        if user_.is_agency and not status_field_val.is_valid:
            return jsonify({"error": "User status values invalid"}), 400

    # Status Values for Events
    old_status = {}
    new_status = {}

    # User Attributes for Events
    old_user_attrs = defaultdict(dict)
    new_user_attrs = defaultdict(dict)

    for key, value in status_field_val.items():
        if value is not None:
            if key == 'is_agency_admin':
                cur_val = user_.is_agency_admin(agency_ein)
            elif key == 'is_agency_active':
                cur_val = user_.is_agency_active(agency_ein)
            else:
                cur_val = getattr(user_, key)
            new_val = eval_request_bool(status_field_val[key])
            if cur_val != new_val:
                old_status[key] = cur_val
                new_status[key] = new_val

    for key, value in user_editable_fields.items():
        # Address is a dictionary and needs to be handled separately
        if key == 'address':
            for address_key, address_value in value.items():
                cur_val = (user_.mailing_address.get(address_key)
                           if user_.mailing_address else None)
                new_val = address_value
                if cur_val != new_val:
                    old_user_attrs['_mailing_address'][address_key] = cur_val
                    new_user_attrs['_mailing_address'][address_key] = new_val
            continue
        if value is not None:
            cur_val = getattr(user_, key)
            new_val = user_editable_fields[key]
            if cur_val != new_val:
                old_user_attrs[key] = cur_val
                new_user_attrs[key] = new_val

    # Update the Users object if new_user_attrs is not None (empty dict)
    if new_user_attrs and old_user_attrs:
        update_object(new_user_attrs, Users, user_id)
        # GUID is added to the 'new' value in events to identify the user that was changed
        new_user_attrs['user_guid'] = user_.guid

        # 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,
            'timestamp':
            datetime.utcnow()
        }

        create_object(
            Events(type_=(event_type.REQUESTER_INFO_EDITED
                          if user_.is_anonymous_requester else
                          event_type.USER_INFO_EDITED),
                   previous_value=old_user_attrs,
                   new_value=new_user_attrs,
                   **event_kwargs))

    if new_status:
        redis_key = "{current_user_guid}-{update_user_guid}-{agency_ein}-{timestamp}".format(
            current_user_guid=current_user.guid,
            update_user_guid=user_.guid,
            agency_ein=agency_ein,
            timestamp=datetime.now())
        old_status['user_guid'] = user_.guid
        new_status['user_guid'] = user_.guid

        old_status['agency_ein'] = agency_ein
        new_status['agency_ein'] = agency_ein

        # Update agency active status and create associated event. Occurs first because a user can be
        # activated / deactivated with admin status set to True.
        if is_agency_active is not None:
            update_object(new_status, AgencyUsers, (user_.guid, agency_ein))
            event_kwargs = {
                'request_id':
                user_.anonymous_request.id
                if user_.is_anonymous_requester else None,
                'response_id':
                None,
                'user_guid':
                current_user.guid,
                'timestamp':
                datetime.utcnow()
            }
            if is_agency_active:
                create_object(
                    Events(type_=event_type.AGENCY_USER_ACTIVATED,
                           previous_value=old_status,
                           new_value=new_status,
                           **event_kwargs))
                if is_agency_admin is not None and is_agency_admin:
                    make_user_admin.apply_async(args=(user_.guid,
                                                      current_user.guid,
                                                      agency_ein),
                                                task_id=redis_key)
                    return jsonify({
                        'status': 'success',
                        'message': 'Update task has been scheduled.'
                    }), 200
            else:
                create_object(
                    Events(type_=event_type.AGENCY_USER_DEACTIVATED,
                           previous_value=old_status,
                           new_value=new_status,
                           **event_kwargs))
                remove_user_permissions.apply_async(
                    args=(user_.guid, current_user.guid, agency_ein,
                          event_type.AGENCY_USER_DEACTIVATED),
                    task_id=redis_key)
                return jsonify({
                    'status': 'success',
                    'message': 'Update task has been scheduled.'
                }), 200
            return jsonify({
                'status': 'success',
                'message': 'Agency user successfully updated'
            }), 200

        # Update agency admin status and create associated event.
        elif is_agency_admin is not None:
            new_status['agency_ein'] = agency_ein
            update_object(new_status, AgencyUsers, (user_.guid, agency_ein))
            event_kwargs = {
                'request_id':
                user_.anonymous_request.id
                if user_.is_anonymous_requester else None,
                'response_id':
                None,
                'user_guid':
                current_user.guid,
                'timestamp':
                datetime.utcnow()
            }
            if is_agency_admin:
                create_object(
                    Events(type_=event_type.USER_MADE_AGENCY_ADMIN,
                           previous_value=old_status,
                           new_value=new_status,
                           **event_kwargs))
                make_user_admin.apply_async(args=(user_.guid,
                                                  current_user.guid,
                                                  agency_ein),
                                            task_id=redis_key)
                return jsonify({
                    'status': 'success',
                    'message': 'Update task has been scheduled.'
                }), 200
            else:
                create_object(
                    Events(type_=event_type.USER_MADE_AGENCY_USER,
                           previous_value=old_status,
                           new_value=new_status,
                           **event_kwargs))
                remove_user_permissions.apply_async(
                    args=(user_.guid, current_user.guid, agency_ein,
                          event_type.USER_MADE_AGENCY_USER),
                    task_id=redis_key)
                return jsonify({
                    'status': 'success',
                    'message': 'Update task has been scheduled.'
                }), 200

        # Update user super status and create associated event.
        elif is_super is not None:
            new_status['agency_ein'] = agency_ein
            update_object(new_status, AgencyUsers, (user_.guid, agency_ein))
            event_kwargs = {
                'request_id':
                user_.anonymous_request.id
                if user_.is_anonymous_requester else None,
                'response_id':
                None,
                'user_guid':
                current_user.guid,
                'timestamp':
                datetime.utcnow()
            }
            if is_super:
                create_object(
                    Events(type_=event_type.USER_MADE_SUPER_USER,
                           previous_value=old_status,
                           new_value=new_status,
                           **event_kwargs))
            else:
                create_object(
                    Events(type_=event_type.USER_REMOVED_FROM_SUPER,
                           previous_value=old_status,
                           new_value=new_status,
                           **event_kwargs))
            return jsonify({
                'status': 'success',
                'message': 'Agency user successfully updated'
            }), 200
    # Always returns 200 so that we can use the data from the response in the client side javascript
    return jsonify({
        'status': 'Not Modified',
        'message': 'No changes detected'
    }), 200
示例#26
0
def update_agency_active_status(agency_ein, is_active):
    """
    Update the active status of an agency.
    :param agency_ein: String identifier for agency (4 characters)
    :param is_active: Boolean value for agency active status (True = Active)
    :return: Boolean value (True if successfully changed active status)
    """
    agency = Agencies.query.filter_by(ein=agency_ein).first()
    is_valid_agency = agency is not None
    activate_agency = eval_request_bool(is_active)

    if is_active is not None and is_valid_agency:
        update_object(
            {'is_active': activate_agency},
            Agencies,
            agency_ein
        )
        if activate_agency:
            create_object(
                Events(
                    request_id=None,
                    user_guid=current_user.guid,
                    type_=AGENCY_ACTIVATED,
                    previous_value={"ein": agency_ein, "is_active": "False"},
                    new_value={"ein": agency_ein, "is_active": "True"},
                    timestamp=datetime.utcnow()
                )
            )
            # create request documents
            for request in agency.requests:
                request.es_create()

            return True
        else:
            create_object(
                Events(
                    request_id=None,
                    user_guid=current_user.guid,
                    type_=AGENCY_DEACTIVATED,
                    previous_value={"ein": agency_ein, "is_active": "True"},
                    new_value={"ein": agency_ein, "is_active": "False"},
                    timestamp=datetime.utcnow()
                )
            )
            # remove requests from index
            for request in agency.requests:
                request.es_delete()
            # deactivate agency users
            for user in agency.active_users:
                update_object(
                    {"is_agency_active": "False",
                     "is_agency_admin": "False"},
                    AgencyUsers,
                    (user.guid, agency_ein)
                )
                create_object(
                    Events(
                        request_id=None,
                        user_guid=current_user.guid,
                        type_=AGENCY_USER_DEACTIVATED,
                        previous_value={"user_guid": user.guid,
                                        "ein": agency_ein,
                                        "is_active": "True"},
                        new_value={"user_guid": user.guid,
                                   "ein": agency_ein,
                                   "is_active": "False"},
                        timestamp=datetime.utcnow()
                    )
                )

            return True
    return False
示例#27
0
def _update_user_data(
        user,
        guid,
        email,
        first_name=None,
        middle_initial=None,
        last_name=None,
        email_validated=False,
        is_nyc_employee=False,
        has_nyc_account=False,
        active=False,
        terms_of_use_accepted=False,
        is_anonymous_requester=False
):
    """
    Update a users data with the updated values.

    Args:
        user (Users): User to be updated.
        guid (str): Updated GUID (Required)
        email (str): Updated email address
        first_name (str): Updated first name
        middle_initial (str): Updated middle initial
        last_name (str): Updated last name
        email_validated (bool): Updated email validation status
        is_nyc_employee (bool): Updated NYC Employee status
        has_nyc_account (bool): Updated NYC Account Status
        active (bool): Updated active status (is the user account active in the authentication provider)
        terms_of_use_accepted (bool): Terms of Use Accepted Status
        is_anonymous_requester (bool): Updated Anonymous Requester status

    """
    current_data = user.val_for_events

    updated_data = {
        'guid': guid,
        'first_name': first_name,
        'middle_initial': middle_initial,
        'last_name': last_name,
        'email': email,
        'email_validated': email_validated,
        'is_nyc_employee': is_nyc_employee,
        'has_nyc_account': has_nyc_account,
        'active': active,
        'terms_of_use_accepted': terms_of_use_accepted,
        'is_anonymous_requester': is_anonymous_requester
    }

    updates = {}

    for k, v in current_data.items():
        _temp_update = updated_data.get(k, None)
        if _temp_update and _temp_update != v:
            updates[k] = updated_data.get(k)

    if updates:
        # Get all the events that need to be changed to associate with the updated GUID.
        events_to_update = Events.query.filter(Events.new_value['user_guid'].astext == user.guid).all()

        # Staging area for update events
        updated_events = []

        # Loop through the events and create a dictionary that contains the updated GUID in the proper keys
        for event in events_to_update:
            update = EventsDict(
                id=event.id,
                request_id=event.request_id,
                user_guid=event.user_guid,
                response_id=event.response_id,
                type=event.type,
                timestamp=event.timestamp,
                previous_value=event.previous_value,
                new_value=event.new_value
            )

            update['new_value']['user_guid'] = guid

            updated_events.append(('new_value', update['new_value']))

        update_object(
            updates,
            Users,
            user.guid
        )

        if updated_events:
            Events.query.filter(Events.new_value['user_guid'].astext == current_data['guid']).update(updated_events,
                                                                                                     synchronize_session=False)
        UserRequests.query.filter(UserRequests.user_guid == current_data['guid']).update([('user_guid', guid)])

        request_ids = [ur.request_id for ur in UserRequests.query.with_entities(UserRequests.request_id).filter(
            UserRequests.user_guid == guid).all()]

        es_update_assigned_users.apply_async(args=[request_ids])
示例#28
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

    """

    # Anonymous users cannot access endpoint
    if current_user.is_anonymous:
        return jsonify({'error': 'Anonymous users cannot access this endpoint'}), 403

    # Public users cannot access endpoint
    if current_user.is_public:
        return jsonify({'error': 'Public users cannot access this endpoint'}), 403

    # Unauthenticated users cannot access endpoint
    if not current_user.is_authenticated:
        return jsonify({'error': 'User must be authenticated to access endpoint'}), 403

    # Retrieve the user
    user_ = Users.query.filter_by(guid=user_id).one_or_none()

    # If the user does not exist, return 404 - Not Found
    if not user_:
        return jsonify({'error': 'Specified user does not exist.'}), 404

    # Gather Form details
    is_agency_admin = eval_request_bool(request.form.get('is_agency_admin')) if request.form.get('is_agency_admin',
                                                                                                 None) else None
    is_agency_active = eval_request_bool(request.form.get('is_agency_active')) if request.form.get('is_agency_active',
                                                                                                   None) else None
    is_super = eval_request_bool(request.form.get('is_super')) if request.form.get('is_super', None) else None

    agency_ein = request.form.get('agency_ein', None)

    # Checks that apply if user is changing their own profile
    changing_self = current_user == user_

    # Agency User Restrictions (applies to Admins and Regular Users)
    if user_.is_agency:
        # Endpoint can only be used for a specific agency
        if not agency_ein:
            return jsonify({'error': 'agency_ein must be provided to modify an agency user'}), 400

        # Agency must exist and be active to modify users
        agency = Agencies.query.filter_by(ein=agency_ein).one_or_none()
        if not agency and agency.is_active:
            return jsonify({'error': 'Agency must exist in the database and be active'}), 400

        if not current_user.is_super:
            # Current user must belong to agency specified by agency_ein
            current_user_is_agency_admin = current_user.is_agency_admin(agency.ein)

            if not current_user_is_agency_admin:
                return jsonify({'error': 'Current user must belong to agency specified by agency_ein'}), 400

            user_in_agency = AgencyUsers.query.filter(AgencyUsers.user_guid == user_.guid, AgencyUsers.agency_ein == agency_ein).one_or_none()

            if user_in_agency is None:
                return jsonify({'error': 'User to be modified must belong to agency specified by agency_ein'}), 400

        # Non-Agency Admins cannot access endpoint to modify other agency_users
        if not current_user.is_super and not current_user.is_agency_admin(agency_ein):
            return jsonify({'error': 'User must be agency admin to modify users'}), 403

        # Cannot modify super status when changing agency active or agency admin status
        if (is_agency_admin or is_agency_active) and is_super:
            return jsonify({
                'error': 'Cannot modify super status when changing agency active or agency admin status'}), 400

        if changing_self:
            # Super users cannot change their own is_super value
            if current_user.is_super and is_super:
                return jsonify({'error': 'Super users cannot change their own `super` status'}), 400

            if is_agency_admin:
                return jsonify({'error': 'Agency Administrators cannot change their administrator permissions'}), 400

    elif user_.is_public:
        if current_user != user_:
            return jsonify({'error': 'Public user attributes cannot be modified by agency users.'}), 400

    elif user_.is_anonymous_requester:
        ur = current_user.user_requests.filter_by(request_id=user_.anonymous_request.id).one_or_none()
        if not ur:
            return jsonify({
                'error': 'Agency users can only modify anonymous requesters for requests where they are assigned.'}), 403

        if not ur.has_permission(permission.EDIT_REQUESTER_INFO):
            return jsonify({'error': 'Current user does not have EDIT_REQUESTER_INFO permission'}), 403

    # Gather User Fields

    user_editable_fields = user_attrs.UserEditableFieldsDict(
        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'),
        address_one=request.form.get('address_one'),
        address_two=request.form.get('address_two'),
        zip=request.form.get('zipcode'),
        city=request.form.get('city'),
    )
    status_field_val = user_attrs.UserStatusDict(
        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')
    )
    if changing_self:
        if not user_editable_fields.is_valid:
            return jsonify({"error": "Missing contact information."}), 400
    else:
        if user_.is_agency and not status_field_val.is_valid:
            return jsonify({"error": "User status values invalid"}), 400

    # Status Values for Events
    old_status = {}
    new_status = {}

    # User Attributes for Events
    old_user_attrs = {'_mailing_address': {}}
    new_user_attrs = {'_mailing_address': {}}

    for key, value in status_field_val.items():
        if value is not None:
            if key == 'is_agency_admin':
                cur_val = user_.is_agency_admin(agency_ein)
            elif key == 'is_agency_active':
                cur_val = user_.is_agency_active(agency_ein)
            else:
                cur_val = getattr(user_, key)
            new_val = eval_request_bool(status_field_val[key])
            if cur_val != new_val:
                old_status[key] = cur_val
                new_status[key] = new_val

    for key, value in user_editable_fields.items():
        # Address is a dictionary and needs to be handled separately
        if key == 'address':
            for address_key, address_value in value.items():
                cur_val = (user_.mailing_address.get(address_key)
                           if user_.mailing_address else None)
                new_val = address_value
                if cur_val != new_val:
                    old_user_attrs['_mailing_address'][address_key] = cur_val
                    new_user_attrs['_mailing_address'][address_key] = new_val
            continue
        if value is not None:
            cur_val = getattr(user_, key)
            new_val = user_editable_fields[key]
            if cur_val != new_val:
                old_user_attrs[key] = cur_val
                new_user_attrs[key] = new_val

    # Update the Users object if new_user_attrs is not None (empty dict)
    if new_user_attrs and new_user_attrs.get('_mailing_address') and old_user_attrs:
        update_object(
            new_user_attrs,
            Users,
            user_id
        )
        # GUID is added to the 'new' value in events to identify the user that was changed
        new_user_attrs['user_guid'] = user_.guid

        # 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,
            'timestamp': datetime.utcnow()
        }

        create_object(Events(
            type_=(event_type.REQUESTER_INFO_EDITED
                   if user_.is_anonymous_requester
                   else event_type.USER_INFO_EDITED),
            previous_value=old_user_attrs,
            new_value=new_user_attrs,
            **event_kwargs
        ))

    if new_status:
        redis_key = "{current_user_guid}-{update_user_guid}-{agency_ein}-{timestamp}".format(
            current_user_guid=current_user.guid, update_user_guid=user_.guid, agency_ein=agency_ein,
            timestamp=datetime.now())
        old_status['user_guid'] = user_.guid
        new_status['user_guid'] = user_.guid

        old_status['agency_ein'] = agency_ein
        new_status['agency_ein'] = agency_ein

        # Update agency active status and create associated event. Occurs first because a user can be
        # activated / deactivated with admin status set to True.
        if is_agency_active is not None:
            update_object(
                new_status,
                AgencyUsers,
                (user_.guid, agency_ein)
            )
            event_kwargs = {
                'request_id': user_.anonymous_request.id if user_.is_anonymous_requester else None,
                'response_id': None,
                'user_guid': current_user.guid,
                'timestamp': datetime.utcnow()
            }
            if is_agency_active:
                create_object(Events(
                    type_=event_type.AGENCY_USER_ACTIVATED,
                    previous_value=old_status,
                    new_value=new_status,
                    **event_kwargs
                ))
                if is_agency_admin is not None and is_agency_admin:
                    make_user_admin.apply_async(args=(user_.guid, current_user.guid, agency_ein), task_id=redis_key)
                    return jsonify({'status': 'success', 'message': 'Update task has been scheduled.'}), 200
            else:
                create_object(Events(
                    type_=event_type.AGENCY_USER_DEACTIVATED,
                    previous_value=old_status,
                    new_value=new_status,
                    **event_kwargs
                ))
                remove_user_permissions.apply_async(
                    args=(user_.guid, current_user.guid, agency_ein, event_type.AGENCY_USER_DEACTIVATED), task_id=redis_key)
                return jsonify({'status': 'success', 'message': 'Update task has been scheduled.'}), 200
            return jsonify({'status': 'success', 'message': 'Agency user successfully updated'}), 200

        # Update agency admin status and create associated event.
        elif is_agency_admin is not None:
            new_status['agency_ein'] = agency_ein
            update_object(
                new_status,
                AgencyUsers,
                (user_.guid, agency_ein)
            )
            event_kwargs = {
                'request_id': user_.anonymous_request.id if user_.is_anonymous_requester else None,
                'response_id': None,
                'user_guid': current_user.guid,
                'timestamp': datetime.utcnow()
            }
            if is_agency_admin:
                create_object(Events(
                    type_=event_type.USER_MADE_AGENCY_ADMIN,
                    previous_value=old_status,
                    new_value=new_status,
                    **event_kwargs
                ))
                make_user_admin.apply_async(args=(user_.guid, current_user.guid, agency_ein), task_id=redis_key)
                return jsonify({'status': 'success', 'message': 'Update task has been scheduled.'}), 200
            else:
                create_object(Events(
                    type_=event_type.USER_MADE_AGENCY_USER,
                    previous_value=old_status,
                    new_value=new_status,
                    **event_kwargs
                ))
                remove_user_permissions.apply_async(
                    args=(user_.guid, current_user.guid, agency_ein, event_type.USER_MADE_AGENCY_USER), task_id=redis_key)
                return jsonify({'status': 'success', 'message': 'Update task has been scheduled.'}), 200

        # Update user super status and create associated event.
        elif is_super is not None:
            new_status['agency_ein'] = agency_ein
            update_object(
                new_status,
                AgencyUsers,
                (user_.guid, agency_ein)
            )
            event_kwargs = {
                'request_id': user_.anonymous_request.id if user_.is_anonymous_requester else None,
                'response_id': None,
                'user_guid': current_user.guid,
                'timestamp': datetime.utcnow()
            }
            if is_super:
                create_object(Events(
                    type_=event_type.USER_MADE_SUPER_USER,
                    previous_value=old_status,
                    new_value=new_status,
                    **event_kwargs
                ))
            else:
                create_object(Events(
                    type_=event_type.USER_REMOVED_FROM_SUPER,
                    previous_value=old_status,
                    new_value=new_status,
                    **event_kwargs
                ))
            return jsonify({'status': 'success', 'message': 'Agency user successfully updated'}), 200
    # Always returns 200 so that we can use the data from the response in the client side javascript
    return jsonify({'status': 'Not Modified', 'message': 'No changes detected'}), 200
示例#29
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
示例#30
0
def update_request_statuses():
    """
    Update statuses for all requests that are now Due Soon or Overdue
    and send a notification email to agency admins listing the requests.
    """
    with scheduler.app.app_context():
        now = datetime.utcnow()
        due_soon_date = calendar.addbusdays(
            now, current_app.config['DUE_SOON_DAYS_THRESHOLD']).replace(
                hour=23, minute=59, second=59)  # the entire day

        requests_overdue = Requests.query.filter(
            Requests.due_date < now,
            Requests.status != request_status.CLOSED).order_by(
                Requests.due_date.asc()).all()

        requests_due_soon = Requests.query.filter(
            Requests.due_date > now, Requests.due_date <= due_soon_date,
            Requests.status != request_status.CLOSED).order_by(
                Requests.due_date.asc()).all()

        agencies_to_requests_overdue = {}
        agencies_to_acknowledgments_overdue = {}
        agencies_to_requests_due_soon = {}
        agencies_to_acknowledgments_due_soon = {}

        def add_to_agencies_to_request_dict(req, agencies_to_request_dict):
            if req.agency.ein not in agencies_to_request_dict:
                agencies_to_request_dict[req.agency.ein] = [req]
            else:
                agencies_to_request_dict[req.agency.ein].append(req)

        # OVERDUE
        for request in requests_overdue:

            if request.was_acknowledged:
                add_to_agencies_to_request_dict(request,
                                                agencies_to_requests_overdue)
            else:
                add_to_agencies_to_request_dict(
                    request, agencies_to_acknowledgments_overdue)

            if request.status != request_status.OVERDUE:
                update_object({"status": request_status.OVERDUE}, Requests,
                              request.id)

        # DUE SOON
        for request in requests_due_soon:

            if request.was_acknowledged:
                add_to_agencies_to_request_dict(request,
                                                agencies_to_requests_due_soon)
            else:
                add_to_agencies_to_request_dict(
                    request, agencies_to_acknowledgments_due_soon)

            if request.status != request_status.DUE_SOON:
                update_object({"status": request_status.DUE_SOON}, Requests,
                              request.id)

        # get all possible agencies to email
        agency_eins = set(
            list(agencies_to_requests_overdue) +
            list(agencies_to_acknowledgments_overdue) +
            list(agencies_to_requests_due_soon) +
            list(agencies_to_acknowledgments_due_soon))

        # mail to agency admins for each agency
        for agency_ein in agency_eins:
            agency_requests_overdue = agencies_to_requests_overdue.get(
                agency_ein, [])
            agency_acknowledgments_overdue = agencies_to_acknowledgments_overdue.get(
                agency_ein, [])
            agency_requests_due_soon = agencies_to_requests_due_soon.get(
                agency_ein, [])
            agency_acknowledgments_due_soon = agencies_to_acknowledgments_due_soon.get(
                agency_ein, [])

            user_emails = list(
                set(admin.notification_email or admin.email
                    for admin in Agencies.query.filter_by(
                        ein=agency_ein).one().administrators))
            send_email(
                STATUSES_EMAIL_SUBJECT,
                to=user_emails,
                template=STATUSES_EMAIL_TEMPLATE,
                requests_overdue=agency_requests_overdue,
                acknowledgments_overdue=agency_acknowledgments_overdue,
                requests_due_soon=agency_requests_due_soon,
                acknowledgments_due_soon=agency_acknowledgments_due_soon)
            email = Emails(
                request.id,
                PRIVATE,
                to=','.join(user_emails),
                cc=None,
                bcc=None,
                subject=STATUSES_EMAIL_SUBJECT,
                body=render_template(
                    STATUSES_EMAIL_TEMPLATE + ".html",
                    requests_overdue=agency_requests_overdue,
                    acknowledgments_overdue=agency_acknowledgments_overdue,
                    requests_due_soon=agency_requests_due_soon,
                    acknowledgments_due_soon=agency_acknowledgments_due_soon))
            create_object(email)
            create_object(
                Events(request.id,
                       user_guid=None,
                       auth_user_type=None,
                       type_=EMAIL_NOTIFICATION_SENT,
                       previous_value=None,
                       new_value=email.val_for_events,
                       response_id=None,
                       timestamp=datetime.utcnow()))
示例#31
0
def _update_request_statuses():
    """
    Update statuses for all requests that are now Due Soon or Overdue
    and send a notification email to agency admins listing the requests.
    """
    now = datetime.utcnow()
    due_soon_date = calendar.addbusdays(
        now, current_app.config['DUE_SOON_DAYS_THRESHOLD']
    ).replace(hour=23, minute=59, second=59)  # the entire day

    agencies = Agencies.query.with_entities(Agencies.ein).filter_by(is_active=True).all()
    for agency_ein, in agencies:
        requests_overdue = Requests.query.filter(
            Requests.due_date < now,
            Requests.status != request_status.CLOSED,
            Requests.agency_ein == agency_ein
        ).order_by(
            Requests.due_date.asc()
        ).all()

        requests_due_soon = Requests.query.filter(
            Requests.due_date > now,
            Requests.due_date <= due_soon_date,
            Requests.status != request_status.CLOSED,
            Requests.agency_ein == agency_ein
        ).order_by(
            Requests.due_date.asc()
        ).all()

        if not requests_overdue and not requests_due_soon:
            continue

        agency_requests_overdue = []
        agency_acknowledgments_overdue = []
        agency_requests_due_soon = []
        agency_acknowledgments_due_soon = []

        # OVERDUE
        for request in requests_overdue:

            if request.was_acknowledged:
                agency_requests_overdue.append(request)
            else:
                agency_acknowledgments_overdue.append(request)

            if request.status != request_status.OVERDUE:
                create_object(
                    Events(
                        request.id,
                        user_guid=None,
                        type_=REQ_STATUS_CHANGED,
                        previous_value={"status": request.status},
                        new_value={"status": request_status.OVERDUE},
                        response_id=None,
                    )
                )
                update_object(
                    {"status": request_status.OVERDUE},
                    Requests,
                    request.id)

        # DUE SOON
        for request in requests_due_soon:

            if request.was_acknowledged:
                agency_requests_due_soon.append(request)
            else:
                agency_acknowledgments_due_soon.append(request)

            if request.status != request_status.DUE_SOON:
                create_object(
                    Events(
                        request.id,
                        user_guid=None,
                        type_=REQ_STATUS_CHANGED,
                        previous_value={"status": request.status},
                        new_value={"status": request_status.DUE_SOON},
                        response_id=None,
                    )
                )
                update_object(
                    {"status": request_status.DUE_SOON},
                    Requests,
                    request.id)

        # mail to agency admins for each agency
        user_emails = list(set(admin.notification_email or admin.email for admin
                               in Agencies.query.filter_by(ein=agency_ein).one().administrators))

        send_email(
            STATUSES_EMAIL_SUBJECT,
            to=user_emails,
            template=STATUSES_EMAIL_TEMPLATE,
            requests_overdue=agency_requests_overdue,
            acknowledgments_overdue=agency_acknowledgments_overdue,
            requests_due_soon=agency_requests_due_soon,
            acknowledgments_due_soon=agency_acknowledgments_due_soon
        )
        email = Emails(
            request.id,
            PRIVATE,
            to=','.join(user_emails),
            cc=None,
            bcc=None,
            subject=STATUSES_EMAIL_SUBJECT,
            body=render_template(
                STATUSES_EMAIL_TEMPLATE + ".html",
                requests_overdue=agency_requests_overdue,
                acknowledgments_overdue=agency_acknowledgments_overdue,
                requests_due_soon=agency_requests_due_soon,
                acknowledgments_due_soon=agency_acknowledgments_due_soon
            )
        )
        create_object(email)
        create_object(
            Events(
                request.id,
                user_guid=None,
                type_=EMAIL_NOTIFICATION_SENT,
                previous_value=None,
                new_value=email.val_for_events,
                response_id=None,
                timestamp=datetime.utcnow()
            )
        )
示例#32
0
 def __update(self, data):
     update_object(data, Requests, self.request.id)
示例#33
0
def _update_request_statuses():
    """
    Update statuses for all requests that are now Due Soon or Overdue
    and send a notification email to agency admins listing the requests.
    """
    now = datetime.utcnow()
    due_soon_date = calendar.addbusdays(
        now, current_app.config['DUE_SOON_DAYS_THRESHOLD']).replace(
            hour=23, minute=59, second=59)  # the entire day

    agencies = Agencies.query.with_entities(
        Agencies.ein).filter_by(is_active=True).all()

    for agency_ein, in agencies:
        requests_overdue = Requests.query.filter(
            Requests.due_date < now, Requests.status != request_status.CLOSED,
            Requests.agency_ein == agency_ein).order_by(
                Requests.due_date.asc()).all()

        requests_due_soon = Requests.query.filter(
            Requests.due_date > now, Requests.due_date <= due_soon_date,
            Requests.status != request_status.CLOSED,
            Requests.agency_ein == agency_ein).order_by(
                Requests.due_date.asc()).all()

        if not requests_overdue and not requests_due_soon:
            continue

        agency_requests_overdue = []
        agency_acknowledgments_overdue = []
        agency_requests_due_soon = []
        agency_acknowledgments_due_soon = []

        # OVERDUE
        for request in requests_overdue:

            if request.was_acknowledged:
                agency_requests_overdue.append(request)
            else:
                agency_acknowledgments_overdue.append(request)

            if request.status != request_status.OVERDUE:
                create_object(
                    Events(
                        request.id,
                        user_guid=None,
                        auth_user_type=None,
                        type_=REQ_STATUS_CHANGED,
                        previous_value={"status": request.status},
                        new_value={"status": request_status.OVERDUE},
                        response_id=None,
                    ))
                update_object({"status": request_status.OVERDUE}, Requests,
                              request.id)

        # DUE SOON
        for request in requests_due_soon:

            if request.was_acknowledged:
                agency_requests_due_soon.append(request)
            else:
                agency_acknowledgments_due_soon.append(request)

            if request.status != request_status.DUE_SOON:
                create_object(
                    Events(
                        request.id,
                        user_guid=None,
                        auth_user_type=None,
                        type_=REQ_STATUS_CHANGED,
                        previous_value={"status": request.status},
                        new_value={"status": request_status.DUE_SOON},
                        response_id=None,
                    ))
                update_object({"status": request_status.DUE_SOON}, Requests,
                              request.id)

        # mail to agency admins for each agency
        user_emails = list(
            set(admin.notification_email or admin.email
                for admin in Agencies.query.filter_by(
                    ein=agency_ein).one().administrators))

        send_email(STATUSES_EMAIL_SUBJECT,
                   to=user_emails,
                   template=STATUSES_EMAIL_TEMPLATE,
                   requests_overdue=agency_requests_overdue,
                   acknowledgments_overdue=agency_acknowledgments_overdue,
                   requests_due_soon=agency_requests_due_soon,
                   acknowledgments_due_soon=agency_acknowledgments_due_soon)
        email = Emails(
            request.id,
            PRIVATE,
            to=','.join(user_emails),
            cc=None,
            bcc=None,
            subject=STATUSES_EMAIL_SUBJECT,
            body=render_template(
                STATUSES_EMAIL_TEMPLATE + ".html",
                requests_overdue=agency_requests_overdue,
                acknowledgments_overdue=agency_acknowledgments_overdue,
                requests_due_soon=agency_requests_due_soon,
                acknowledgments_due_soon=agency_acknowledgments_due_soon))
        create_object(email)
        create_object(
            Events(request.id,
                   user_guid=None,
                   auth_user_type=None,
                   type_=EMAIL_NOTIFICATION_SENT,
                   previous_value=None,
                   new_value=email.val_for_events,
                   response_id=None,
                   timestamp=datetime.utcnow()))