예제 #1
0
    def add_file(
            self,
            title=None,
            filepath=None,
            name=None,  # will be ignored if filepath supplied
            privacy=response_privacy.PRIVATE,
            user=None):
        if filepath is None:
            filename = name or fake.file_name(extension='txt')
            filepath = os.path.join(current_app.config["UPLOAD_DIRECTORY"],
                                    self.request.id, filename)
        else:
            filename = os.path.basename(filepath)

        if not fu.exists(filepath):
            fu.makedirs(os.path.dirname(filepath), exist_ok=True)
            with open(filepath, "w") as fp:
                fp.write(fake.file_content())
            self.__files.append(filepath)

        response = Files(
            self.request.id,
            privacy=privacy,
            title=title or fake.title(),
            name=filename,
            mime_type=fu.get_mime_type(filepath),
            size=fu.getsize(filepath),
            hash_=fu.get_hash(filepath),
        )
        create_object(response)
        self.__create_event(event_type.FILE_ADDED, response, user)
        return response
예제 #2
0
    def add_file(self,
                 filepath=None,
                 mime_type='text/plain',
                 contents=None,
                 title=None):
        if filepath is None:
            filename = str(uuid.uuid4())
            filepath = os.path.join(current_app.config['UPLOAD_DIRECTORY'],
                                    self.request.id, filename)
        else:
            filename = os.path.basename(filepath)

        self.filepaths.append(filepath)

        # create an empty file if the specified path does not exist
        if not fu.exists(filepath):
            fu.makedirs(os.path.dirname(filepath), exist_ok=True)
            with open(filepath, 'w') as fp:
                fp.write(contents or ''.join(
                    random.choice(ascii_letters)
                    for _ in range(random.randrange(100, 500))))

        response = Files(self.request.id, PRIVATE, title or filename,
                         filename, mime_type, fu.getsize(filepath),
                         fu.get_hash(filepath))
        # TODO: add Events FILE_ADDED
        create_object(response)
        return response
예제 #3
0
def create_request(title,
                   description,
                   category,
                   tz_name,
                   agency_ein=None,
                   first_name=None,
                   last_name=None,
                   submission=DIRECT_INPUT,
                   agency_date_submitted_local=None,
                   email=None,
                   user_title=None,
                   organization=None,
                   phone=None,
                   fax=None,
                   address=None,
                   upload_path=None,
                   custom_metadata=None):
    """
    Creates a new FOIL Request and associated Users, UserRequests, and Events.

    :param title: request title
    :param description: detailed description of the request
    :param tz_name: client's timezone name
    :param agency_ein: agency_ein selected for the request
    :param first_name: first name of the requester
    :param last_name: last name of the requester
    :param submission: request submission method
    :param agency_date_submitted_local: submission date chosen by agency
    :param email: requester's email address
    :param user_title: requester's organizational title
    :param organization: requester's organization
    :param phone: requester's phone number
    :param fax: requester's fax number
    :param address: requester's mailing address
    :param upload_path: file path of the validated upload
    :param custom_metadata: JSON containing all data from custom request forms
    """
    # 1. Generate the request id
    request_id = generate_request_id(agency_ein)

    # 2a. Generate Email Notification Text for Agency
    # agency_email = generate_email_template('agency_acknowledgment.html', request_id=request_id)
    # 2b. Generate Email Notification Text for Requester

    # 3a. Send Email Notification Text for Agency
    # 3b. Send Email Notification Text for Requester

    # 4a. Calculate Request Submitted Date (Round to next business day)
    date_created_local = utc_to_local(datetime.utcnow(), tz_name)
    if current_user.is_agency:
        date_submitted_local = agency_date_submitted_local
    else:
        date_submitted_local = date_created_local

    # 4b. Calculate Request Due Date (month day year but time is always 5PM, 5 Days after submitted date)
    due_date = get_due_date(date_submitted_local, ACKNOWLEDGMENT_PERIOD_LENGTH,
                            tz_name)

    date_created = local_to_utc(date_created_local, tz_name)
    date_submitted = local_to_utc(date_submitted_local, tz_name)

    # 5. Create Request
    request = Requests(id=request_id,
                       title=title,
                       agency_ein=agency_ein,
                       category=category,
                       description=description,
                       date_created=date_created,
                       date_submitted=date_submitted,
                       due_date=due_date,
                       submission=submission,
                       custom_metadata=custom_metadata)
    create_object(request)

    guid_for_event = current_user.guid if not current_user.is_anonymous else None

    # 6. Get or Create User
    if current_user.is_public:
        user = current_user
    else:
        user = Users(guid=generate_guid(),
                     email=email,
                     first_name=first_name,
                     last_name=last_name,
                     title=user_title or None,
                     organization=organization or None,
                     email_validated=False,
                     terms_of_use_accepted=False,
                     phone_number=phone,
                     fax_number=fax,
                     mailing_address=address,
                     is_anonymous_requester=True)
        create_object(user)
        # user created event
        create_object(
            Events(request_id,
                   guid_for_event,
                   event_type.USER_CREATED,
                   previous_value=None,
                   new_value=user.val_for_events,
                   response_id=None,
                   timestamp=datetime.utcnow()))

    if upload_path is not None:
        # 7. Move file to upload directory
        upload_path = _move_validated_upload(request_id, upload_path)
        # 8. Create response object
        filename = os.path.basename(upload_path)
        response = Files(request_id,
                         RELEASE_AND_PRIVATE,
                         filename,
                         filename,
                         fu.get_mime_type(upload_path),
                         fu.getsize(upload_path),
                         fu.get_hash(upload_path),
                         is_editable=False)
        create_object(obj=response)

        # 8. Create upload Event
        upload_event = Events(user_guid=user.guid,
                              response_id=response.id,
                              request_id=request_id,
                              type_=event_type.FILE_ADDED,
                              timestamp=datetime.utcnow(),
                              new_value=response.val_for_events)
        create_object(upload_event)

        # Create response token if requester is anonymous
        if current_user.is_anonymous or current_user.is_agency:
            create_object(ResponseTokens(response.id))

    role_to_user = {
        role.PUBLIC_REQUESTER: user.is_public,
        role.ANONYMOUS: user.is_anonymous_requester,
    }
    role_name = [k for (k, v) in role_to_user.items() if v][0]
    # (key for "truthy" value)

    # 9. Create Event
    timestamp = datetime.utcnow()
    event = Events(user_guid=user.guid
                   if current_user.is_anonymous else current_user.guid,
                   request_id=request_id,
                   type_=event_type.REQ_CREATED,
                   timestamp=timestamp,
                   new_value=request.val_for_events)
    create_object(event)
    if current_user.is_agency:
        agency_event = Events(user_guid=current_user.guid,
                              request_id=request.id,
                              type_=event_type.AGENCY_REQ_CREATED,
                              timestamp=timestamp)
        create_object(agency_event)

    # 10. Create UserRequest for requester
    user_request = UserRequests(
        user_guid=user.guid,
        request_user_type=user_type_request.REQUESTER,
        request_id=request_id,
        permissions=Roles.query.filter_by(name=role_name).first().permissions)
    create_object(user_request)
    create_object(
        Events(request_id,
               guid_for_event,
               event_type.USER_ADDED,
               previous_value=None,
               new_value=user_request.val_for_events,
               response_id=None,
               timestamp=datetime.utcnow()))

    # 11. Create the elasticsearch request doc only if agency has been onboarded
    agency = Agencies.query.filter_by(ein=agency_ein).one()

    # 12. Add all agency administrators to the request.
    if agency.administrators:
        # b. Store all agency users objects in the UserRequests table as Agency users with Agency Administrator
        # privileges
        _create_agency_user_requests(request_id=request_id,
                                     agency_admins=agency.administrators,
                                     guid_for_event=guid_for_event)

    # 13. Add all parent agency administrators to the request.
    if agency != agency.parent:
        if (agency.parent.agency_features is not None
                and agency_ein in agency.parent.agency_features.get(
                    'monitor_agency_requests', []) and agency.parent.is_active
                and agency.parent.administrators):
            _create_agency_user_requests(
                request_id=request_id,
                agency_admins=agency.parent.administrators,
                guid_for_event=guid_for_event)

    # (Now that we can associate the request with its requester AND agency users.)
    if current_app.config['ELASTICSEARCH_ENABLED'] and agency.is_active:
        request.es_create()

    return request_id
예제 #4
0
    def test_edit_file(self):
        rf = RequestsFactory(self.request_id)
        response = rf.add_file()

        old_filename = response.name
        data_old = {
            'privacy': response.privacy,
            'title': response.title,
            'name': old_filename,
            'mime_type': response.mime_type,
            'size': response.size,
            'hash': response.hash,
        }

        new_privacy = RELEASE_AND_PUBLIC
        new_filename = PNG_FILE_NAME
        new_title = "Updated Title, Shiny and Chrome"
        new_mime_type = 'image/png'
        new_size = os.path.getsize(PNG_FILE_PATH)
        new_hash = fu.get_hash(PNG_FILE_PATH)
        data_new = {
            'privacy': new_privacy,
            'title': new_title,
            'name': new_filename,
            'mime_type': new_mime_type,
            'size': new_size,
            'hash': new_hash,
        }

        # copy test file into proper directory
        path = os.path.join(self.upload_path, UPDATED_FILE_DIRNAME)
        os.makedirs(path)
        filepath = os.path.join(path, new_filename)
        shutil.copyfile(PNG_FILE_PATH, filepath)

        email_content_agency = "email content agency"
        email_content_requester = "email content requester"

        # https://github.com/mattupstate/flask-security/issues/259
        # http://stackoverflow.com/questions/16238462/flask-unit-test-how-to-test-request-from-logged-in-user/16238537#16238537
        with self.client as client, patch(
                'app.response.utils._send_edit_response_email'
        ) as send_email_patch, patch(
                'app.response.utils._get_edit_response_template',
                return_value=(email_content_requester, email_content_agency,
                              None)):
            with client.session_transaction() as session:
                session['user_id'] = rf.requester.get_id()
                session['_fresh'] = True
            # PUT it in there!
            resp = self.client.patch('/response/' + str(response.id),
                                     data={
                                         'privacy': new_privacy,
                                         'title': new_title,
                                         'filename': new_filename,
                                     })
            # check email sent
            send_email_patch.assert_called_once_with(rf.request.id,
                                                     email_content_agency,
                                                     email_content_requester)

        # check flask response
        self.assertEqual(json.loads(resp.data.decode()), {
            'old': data_old,
            'new': data_new
        })
        # check database (Responses & Metadatas)
        self.assertEqual([
            response.privacy,
            response.title,
            response.name,
            response.mime_type,
            response.size,
            response.hash,
        ], [
            new_privacy,
            new_title,
            new_filename,
            new_mime_type,
            new_size,
            new_hash,
        ])
        # check FILE_EDITED Event created
        events = Events.query.filter_by(response_id=response.id).all()
        self.assertEqual(len(events), 1)
        event = events[0]
        self.assertEqual([
            event.request_id,
            event.user_guid,
            event.auth_user_type,
            event.type,
            event.previous_value,
            event.new_value,
        ], [
            rf.request.id,
            rf.requester.guid,
            rf.requester.auth_user_type,
            FILE_EDITED,
            data_old,
            data_new,
        ])
        # check file replaced
        self.assertFalse(
            os.path.exists(os.path.join(self.upload_path, old_filename)))
        self.assertFalse(
            os.path.exists(
                os.path.join(self.upload_path, UPDATED_FILE_DIRNAME,
                             new_filename)))
        self.assertTrue(
            os.path.exists(os.path.join(self.upload_path, new_filename)))
예제 #5
0
def create_request(title,
                   description,
                   category,
                   tz_name,
                   agency_ein=None,
                   first_name=None,
                   last_name=None,
                   submission=DIRECT_INPUT,
                   agency_date_submitted_local=None,
                   email=None,
                   user_title=None,
                   organization=None,
                   phone=None,
                   fax=None,
                   address=None,
                   upload_path=None,
                   custom_metadata=None):
    """
    Creates a new FOIL Request and associated Users, UserRequests, and Events.

    :param title: request title
    :param description: detailed description of the request
    :param tz_name: client's timezone name
    :param agency_ein: agency_ein selected for the request
    :param first_name: first name of the requester
    :param last_name: last name of the requester
    :param submission: request submission method
    :param agency_date_submitted_local: submission date chosen by agency
    :param email: requester's email address
    :param user_title: requester's organizational title
    :param organization: requester's organization
    :param phone: requester's phone number
    :param fax: requester's fax number
    :param address: requester's mailing address
    :param upload_path: file path of the validated upload
    :param custom_metadata: JSON containing all data from custom request forms
    """
    # 1. Generate the request id
    request_id = generate_request_id(agency_ein)

    # 2a. Generate Email Notification Text for Agency
    # agency_email = generate_email_template('agency_acknowledgment.html', request_id=request_id)
    # 2b. Generate Email Notification Text for Requester

    # 3a. Send Email Notification Text for Agency
    # 3b. Send Email Notification Text for Requester

    # 4a. Calculate Request Submitted Date (Round to next business day)
    date_created_local = utc_to_local(datetime.utcnow(), tz_name)
    if current_user.is_agency:
        date_submitted_local = agency_date_submitted_local
    else:
        date_submitted_local = date_created_local

    # 4b. Calculate Request Due Date (month day year but time is always 5PM, 5 Days after submitted date)
    due_date = get_due_date(
        date_submitted_local,
        ACKNOWLEDGMENT_PERIOD_LENGTH,
        tz_name)

    date_created = local_to_utc(date_created_local, tz_name)
    date_submitted = local_to_utc(date_submitted_local, tz_name)

    # 5. Create Request
    request = Requests(
        id=request_id,
        title=title,
        agency_ein=agency_ein,
        category=category,
        description=description,
        date_created=date_created,
        date_submitted=date_submitted,
        due_date=due_date,
        submission=submission,
        custom_metadata=custom_metadata
    )
    create_object(request)

    guid_for_event = current_user.guid if not current_user.is_anonymous else None

    # 6. Get or Create User
    if current_user.is_public:
        user = current_user
    else:
        user = Users(
            guid=generate_guid(),
            email=email,
            first_name=first_name,
            last_name=last_name,
            title=user_title or None,
            organization=organization or None,
            email_validated=False,
            terms_of_use_accepted=False,
            phone_number=phone,
            fax_number=fax,
            mailing_address=address,
            is_anonymous_requester=True
        )
        create_object(user)
        # user created event
        create_object(Events(
            request_id,
            guid_for_event,
            event_type.USER_CREATED,
            previous_value=None,
            new_value=user.val_for_events,
            response_id=None,
            timestamp=datetime.utcnow()
        ))

    if upload_path is not None:
        # 7. Move file to upload directory
        upload_path = _move_validated_upload(request_id, upload_path)
        # 8. Create response object
        filename = os.path.basename(upload_path)
        response = Files(request_id,
                         RELEASE_AND_PRIVATE,
                         filename,
                         filename,
                         fu.get_mime_type(upload_path),
                         fu.getsize(upload_path),
                         fu.get_hash(upload_path),
                         is_editable=False)
        create_object(obj=response)

        # 8. Create upload Event
        upload_event = Events(user_guid=user.guid,
                              response_id=response.id,
                              request_id=request_id,
                              type_=event_type.FILE_ADDED,
                              timestamp=datetime.utcnow(),
                              new_value=response.val_for_events)
        create_object(upload_event)

        # Create response token if requester is anonymous
        if current_user.is_anonymous or current_user.is_agency:
            create_object(ResponseTokens(response.id))

    role_to_user = {
        role.PUBLIC_REQUESTER: user.is_public,
        role.ANONYMOUS: user.is_anonymous_requester,
    }
    role_name = [k for (k, v) in role_to_user.items() if v][0]
    # (key for "truthy" value)

    # 9. Create Event
    timestamp = datetime.utcnow()
    event = Events(user_guid=user.guid if current_user.is_anonymous else current_user.guid,
                   request_id=request_id,
                   type_=event_type.REQ_CREATED,
                   timestamp=timestamp,
                   new_value=request.val_for_events)
    create_object(event)
    if current_user.is_agency:
        agency_event = Events(user_guid=current_user.guid,
                              request_id=request.id,
                              type_=event_type.AGENCY_REQ_CREATED,
                              timestamp=timestamp)
        create_object(agency_event)

    # 10. Create UserRequest for requester
    user_request = UserRequests(user_guid=user.guid,
                                request_user_type=user_type_request.REQUESTER,
                                request_id=request_id,
                                permissions=Roles.query.filter_by(
                                    name=role_name).first().permissions)
    create_object(user_request)
    create_object(Events(
        request_id,
        guid_for_event,
        event_type.USER_ADDED,
        previous_value=None,
        new_value=user_request.val_for_events,
        response_id=None,
        timestamp=datetime.utcnow()
    ))

    # 11. Create the elasticsearch request doc only if agency has been onboarded
    agency = Agencies.query.filter_by(ein=agency_ein).one()

    # 12. Add all agency administrators to the request.
    if agency.administrators:
        # b. Store all agency users objects in the UserRequests table as Agency users with Agency Administrator
        # privileges
        _create_agency_user_requests(request_id=request_id,
                                     agency_admins=agency.administrators,
                                     guid_for_event=guid_for_event)

    # 13. Add all parent agency administrators to the request.
    if agency != agency.parent:
        if (
                agency.parent.agency_features is not None and
                agency_ein in agency.parent.agency_features.get('monitor_agency_requests', []) and
                agency.parent.is_active and
                agency.parent.administrators
        ):
            _create_agency_user_requests(request_id=request_id,
                                         agency_admins=agency.parent.administrators,
                                         guid_for_event=guid_for_event)

    # (Now that we can associate the request with its requester AND agency users.)
    if current_app.config['ELASTICSEARCH_ENABLED'] and agency.is_active:
        request.es_create()

    return request_id