def download_brief_responses(brief_id):
    brief = Brief.query.filter(
        Brief.id == brief_id
    ).first_or_404()
    brief_user_ids = [user.id for user in brief.users]
    if current_user.id not in brief_user_ids:
        return forbidden("Unauthorised to view brief or brief does not exist")
    if brief.status != 'closed':
        return forbidden("You can only download documents for closed briefs")

    response = ('', 404)
    if brief.lot.slug in ['digital-professionals', 'training', 'rfx', 'atm']:
        try:
            file = s3_download_file(
                'brief-{}-resumes.zip'.format(brief_id),
                os.path.join(brief.framework.slug, 'archives', 'brief-{}'.format(brief_id))
            )
        except botocore.exceptions.ClientError as e:
            rollbar.report_exc_info()
            not_found("Brief documents not found for brief id '{}'".format(brief_id))

        response = Response(file, mimetype='application/zip')
        response.headers['Content-Disposition'] = 'attachment; filename="brief-{}-responses.zip"'.format(brief_id)
    elif brief.lot.slug == 'digital-outcome':
        responses = BriefResponse.query.filter(
            BriefResponse.brief_id == brief_id,
            BriefResponse.withdrawn_at.is_(None)
        ).all()
        csvdata = generate_brief_responses_csv(brief, responses)
        response = Response(csvdata, mimetype='text/csv')
        response.headers['Content-Disposition'] = (
            'attachment; filename="responses-to-requirements-{}.csv"'.format(brief_id))

    return response
Example #2
0
def update_evidence(evidence_id):
    evidence = evidence_service.get_evidence_by_id(evidence_id)
    if not evidence or current_user.supplier_code != evidence.supplier_code:
        not_found("No evidence for id '%s' found" % (evidence_id))

    if evidence.status != 'draft':
        abort('Only draft submissions can be edited')

    data = get_json_from_request()

    publish = False
    if 'publish' in data and data['publish']:
        del data['publish']
        publish = True

    if 'maxDailyRate' in data:
        try:
            data['maxDailyRate'] = int(data['maxDailyRate'])
        except ValueError as e:
            data['maxDailyRate'] = 0

    # Validate the evidence request data
    errors = EvidenceDataValidator(data,
                                   evidence=evidence).validate(publish=publish)
    if len(errors) > 0:
        abort(', '.join(errors))

    if publish:
        evidence.submit()
        if current_app.config['JIRA_FEATURES']:
            create_evidence_assessment_in_jira.delay(evidence_id)
        try:
            send_evidence_assessment_requested_notification(
                evidence.domain_id, current_user.email_address)
        except Exception as e:
            current_app.logger.warn(
                'Failed to send requested assessment email for evidence id: {}, {}'
                .format(evidence_id, e))

    evidence.data = data
    evidence_service.save_evidence(evidence)

    try:
        publish_tasks.evidence.delay(publish_tasks.compress_evidence(evidence),
                                     'updated',
                                     name=current_user.name,
                                     domain=evidence.domain.name,
                                     supplier_code=current_user.supplier_code)

        if publish:
            publish_tasks.evidence.delay(
                publish_tasks.compress_evidence(evidence),
                'submitted',
                name=current_user.name,
                domain=evidence.domain.name,
                supplier_code=current_user.supplier_code)
    except Exception as e:
        pass

    return jsonify(evidence.serialize())
def decline_join_request(team_id, token):
    data = get_json_from_request()

    if 'reason' not in data or not data['reason']:
        abort('Must provide reason for decline')

    try:
        team = team_business.get_team(team_id)
    except NotFoundError as e:
        return not_found(e.message)
    except UnauthorisedError as e:
        return forbidden(e.message)

    join_request = team_business.get_join_request(token)
    if not join_request or int(join_request.data['team_id']) != team_id:
        return not_found(
            'The token is invalid, or this request has already been declined or accepted'
        )

    if ('user_id' in join_request.data
            and (team_member_service.get_team_members_by_user_id(
                team_id, [int(join_request.data['user_id'])])
                 or team_member_service.get_team_leads_by_user_id(
                     team_id, [int(join_request.data['user_id'])]))):
        abort('This user is already a member of the team')

    team_business.decline_join_request(join_request, data['reason'], team_id)

    return jsonify(success=True)
def withdraw_brief_response(brief_response_id):
    """Withdraw brief responses (role=supplier)
    ---
    tags:
      - "Brief Response"
    security:
      - basicAuth: []
    parameters:
      - name: brief_response_id
        in: path
        type: number
        required: true
    responses:
      200:
        description: Successfully withdrawn a candidate
        schema:
          id: BriefResponse
      400:
        description: brief_response_id not found
    """
    brief_response = (brief_responses_service.find(
        id=brief_response_id,
        supplier_code=current_user.supplier_code).one_or_none())

    if brief_response:
        if brief_response.withdrawn_at is None:
            brief_response.withdrawn_at = utcnow()
            brief_responses_service.save(brief_response)

            try:
                audit = AuditEvent(
                    audit_type=audit_types.update_brief_response,
                    user=current_user.email_address,
                    data={'briefResponseId': brief_response.id},
                    db_object=brief_response)
                audit_service.save(audit)
            except Exception as e:
                extra_data = {
                    'audit_type': audit_types.update_brief_response,
                    'briefResponseId': brief_response.id
                }
                rollbar.report_exc_info(extra_data=extra_data)

            publish_tasks.brief_response.delay(
                publish_tasks.compress_brief_response(brief_response),
                'withdrawn',
                user=current_user.email_address)
        else:
            abort(
                'Brief response with brief_response_id "{}" is already withdrawn'
                .format(brief_response_id))
    else:
        not_found(
            'Cannot find brief response with brief_response_id :{} and supplier_code: {}'
            .format(brief_response_id, current_user.supplier_code))

    return jsonify(briefResponses=brief_response.serialize()), 200
def withdraw_brief_response(brief_response_id):
    """Withdraw brief responses (role=supplier)
    ---
    tags:
      - "Brief Response"
    security:
      - basicAuth: []
    parameters:
      - name: brief_response_id
        in: path
        type: number
        required: true
    responses:
      200:
        description: Successfully withdrawn a candidate
        schema:
          id: BriefResponse
      400:
        description: brief_response_id not found
    """
    brief_response = (brief_responses_service
                      .find(id=brief_response_id,
                            supplier_code=current_user.supplier_code)
                      .one_or_none())

    if brief_response:
        if brief_response.withdrawn_at is None:
            brief_response.withdrawn_at = utcnow()
            brief_responses_service.save(brief_response)

            try:
                audit = AuditEvent(
                    audit_type=audit_types.update_brief_response,
                    user=current_user.email_address,
                    data={
                        'briefResponseId': brief_response.id
                    },
                    db_object=brief_response
                )
                audit_service.save(audit)
            except Exception as e:
                extra_data = {'audit_type': audit_types.update_brief_response, 'briefResponseId': brief_response.id}
                rollbar.report_exc_info(extra_data=extra_data)

            publish_tasks.brief_response.delay(
                publish_tasks.compress_brief_response(brief_response),
                'withdrawn',
                user=current_user.email_address
            )
        else:
            abort('Brief response with brief_response_id "{}" is already withdrawn'.format(brief_response_id))
    else:
        not_found('Cannot find brief response with brief_response_id :{} and supplier_code: {}'
                  .format(brief_response_id, current_user.supplier_code))

    return jsonify(briefResponses=brief_response.serialize()), 200
Example #6
0
def get_questions(brief_id):
    result = None
    try:
        result = questions_business.get_questions(current_user, brief_id)
    except NotFoundError as nfe:
        not_found(nfe.message)
    except UnauthorisedError as ue:
        return forbidden(ue.message)

    return jsonify(result), 200
Example #7
0
def get_insight():
    now = None
    incoming_month_ending = request.args.get('monthEnding', None)
    if incoming_month_ending:
        now = pendulum.parse(incoming_month_ending)
    try:
        insight = insight_business.get_insight(current_user, now)
    except NotFoundError as nfe:
        not_found(nfe.message)

    return jsonify(insight), 200
def get_join_request(team_id, token):
    try:
        team = team_business.get_team(team_id)
    except NotFoundError as e:
        return not_found(e.message)
    except UnauthorisedError as e:
        return forbidden(e.message)

    join_request = team_business.get_join_request(token)
    if not join_request or int(join_request.data['team_id']) != team_id:
        return not_found(
            'The token is invalid, or this request has already been declined or accepted'
        )

    return jsonify(join_request=join_request)
def download_brief_attachment(brief_id, slug):
    """Get brief attachments.
    ---
    tags:
        - brief
    parameters:
      - name: brief_id
        in: path
        type: number
        required: true
      - name: slug
        in: path
        type: string
        required: true
    responses:
        200:
            description: Attachment retrieved successfully.
        404:
            description: Attachment not found.
        500:
            description: Unexpected error.
    """
    brief = briefs.get(brief_id)
    brief_user_ids = [user.id for user in brief.users]

    if (hasattr(current_user, 'role') and
        (current_user.role == 'buyer' or
            (current_user.role == 'supplier' and _can_do_brief_response(brief_id)))):
        file = s3_download_file(slug, os.path.join(brief.framework.slug, 'attachments',
                                                   'brief-' + str(brief_id)))
        mimetype = mimetypes.guess_type(slug)[0] or 'binary/octet-stream'
        return Response(file, mimetype=mimetype)
    else:
        return not_found('File not found')
Example #10
0
def get_answers(brief_id):
    result = None
    try:
        result = questions_business.get_answers(brief_id)
    except NotFoundError as nfe:
        return not_found(nfe.message)

    return jsonify(result), 200
def get_brief_response(brief_response_id):
    """Get brief response (role=supplier)
    ---
    tags:
      - "Brief Response"
    security:
      - basicAuth: []
    parameters:
      - name: brief_response_id
        in: path
        type: number
        required: true
    definitions:
      BriefResponse:
        type: object
        properties:
          id:
            type: number
          data:
            type: object
          brief_id:
            type: number
          supplier_code:
            type: number
    responses:
      200:
        description: A brief response on id
        schema:
          id: BriefResponse
      404:
        description: brief_response_id not found
    """

    brief_response = brief_responses_service.find(
        id=brief_response_id,
        supplier_code=current_user.supplier_code).one_or_none()

    if brief_response:
        if brief_response.withdrawn_at is not None:
            abort('Brief response {} is withdrawn'.format(brief_response_id))
    else:
        not_found(
            'Cannot find brief response with brief_response_id :{} and supplier_code: {}'
            .format(brief_response_id, current_user.supplier_code))

    return jsonify(brief_response.serialize())
def get_brief_response(brief_response_id):
    """Get brief response (role=supplier)
    ---
    tags:
      - "Brief Response"
    security:
      - basicAuth: []
    parameters:
      - name: brief_response_id
        in: path
        type: number
        required: true
    definitions:
      BriefResponse:
        type: object
        properties:
          id:
            type: number
          data:
            type: object
          brief_id:
            type: number
          supplier_code:
            type: number
    responses:
      200:
        description: A brief response on id
        schema:
          id: BriefResponse
      404:
        description: brief_response_id not found
    """

    brief_response = brief_responses_service.find(id=brief_response_id,
                                                  supplier_code=current_user.supplier_code).one_or_none()

    if brief_response:
        if brief_response.withdrawn_at is not None:
            abort('Brief response {} is withdrawn'.format(brief_response_id))
    else:
        not_found('Cannot find brief response with brief_response_id :{} and supplier_code: {}'
                  .format(brief_response_id, current_user.supplier_code))

    return jsonify(brief_response.serialize())
def get_team(team_id):
    team = None
    try:
        team = team_business.get_team(team_id)
    except NotFoundError as e:
        return not_found(e.message)
    except UnauthorisedError as e:
        return forbidden(e.message)

    return jsonify(team)
Example #14
0
def get_evidence(evidence_id):
    evidence = evidence_service.get_evidence_by_id(evidence_id)
    if not evidence or current_user.supplier_code != evidence.supplier_code:
        not_found("No evidence for id '%s' found" % (evidence_id))

    data = evidence.serialize()
    data['failed_criteria'] = {}
    data['previous_evidence_id'] = None
    previous_evidence = evidence_service.get_previous_submitted_evidence_for_supplier_and_domain(
        evidence.id, evidence.domain.id, current_user.supplier_code)
    if previous_evidence and previous_evidence.status == 'rejected':
        previous_assessment = evidence_assessment_service.get_assessment_for_rejected_evidence(
            previous_evidence.id)
        if previous_assessment:
            data['failed_criteria'] = previous_assessment.data.get(
                'failed_criteria', {})
            data['previous_evidence_id'] = previous_evidence.id

    return jsonify(data)
def create_team():
    try:
        team = team_business.create_team()
    except TeamError as e:
        abort(e.message)
    except NotFoundError as e:
        return not_found(e.message)
    except UnauthorisedError as e:
        return forbidden(e.message)

    return jsonify(team)
def request_to_join(team_id):
    try:
        team_business.request_to_join(current_user.email_address, team_id,
                                      current_user.agency_id)
    except NotFoundError as e:
        return not_found(e.message)
    except UnauthorisedError as e:
        return forbidden(e.message)
    except ValidationError as e:
        abort(e.message)

    return jsonify(success=True)
Example #17
0
def publish_answer(brief_id):
    data = get_json_from_request()
    try:
        questions_business.publish_answer(current_user, brief_id, data)
    except NotFoundError as nfe:
        return not_found(nfe.message)
    except ValidationError as ve:
        return abort(ve.message)
    except UnauthorisedError as ue:
        return forbidden(ue.message)

    return jsonify(success=True), 200
Example #18
0
def get_redirect(key):
    """Get redirect
    ---
    tags:
      - redirects
    parameters:
      - name: key
        in: path
        type: string
        required: true
    responses:
      302:
        description: a redirect
    """

    key_value = key_values_service.get_by_key('redirects')
    redirect_url = key_value.get('data', {}).get(key)
    if not redirect_url:
        not_found('redirect not found')

    return redirect(redirect_url)
def update_team(team_id):
    data = get_json_from_request()
    try:
        team = team_business.update_team(team_id, data)
    except ValidationError as e:
        return abort(e.message)
    except NotFoundError as e:
        return not_found(e.message)
    except UnauthorisedError as e:
        return forbidden(e.message)

    return jsonify(team)
def upload_brief_rfx_attachment_file(brief_id, slug):
    """Add brief attachments (role=buyer)
    ---
    tags:
        - brief
    parameters:
      - name: brief_id
        in: path
        type: number
        required: true
      - name: slug
        in: path
        type: string
        required: true
      - name: file
        in: body
        required: true
    responses:
        200:
            description: Attachment uploaded successfully.
        403:
            description: Unauthorised to update brief.
        404:
            description: Brief not found.
        500:
            description: Unexpected error.
    """
    brief = briefs.get(brief_id)

    if not brief:
        not_found("Invalid brief id '{}'".format(brief_id))

    brief_user_ids = [user.id for user in brief.users]
    if current_user.id not in brief_user_ids:
        return forbidden('Unauthorised to update brief')

    return jsonify({"filename": s3_upload_file_from_request(request, slug,
                                                            os.path.join(brief.framework.slug, 'attachments',
                                                                         'brief-' + str(brief_id)))
                    })
def get_notification_template(brief_id, template):
    brief = briefs.get(brief_id)
    if brief:
        frontend_url = current_app.config['FRONTEND_ADDRESS']
        return render_email_template(
            '{}.md'.format(template),
            frontend_url=frontend_url,
            brief_name=brief.data['title'],
            brief_id=brief.id,
            brief_url='{}/digital-marketplace/opportunities/{}'.format(frontend_url, brief_id)
        )

    return not_found('brief not found')
Example #22
0
def get_domain(domain_id):
    domain = domain_service.get_by_name_or_id(domain_id, show_legacy=False)
    if not domain:
        return not_found('Domain does not exist')

    data = domain.serialize()

    data['criteriaEnforcementCutoffDate'] = None
    key_value = key_values_service.get_by_key('criteria_enforcement_cutoff_date')
    if key_value:
        data['criteriaEnforcementCutoffDate'] = (
            pendulum.parse(key_value['data']['value'], tz='Australia/Canberra').isoformat()
        )

    return jsonify(data)
Example #23
0
def get_suppliers_responded(brief_id):
    """Get suppliers responded (role=buyer)
    ---
    tags:
      - "Brief Response"
    security:
      - basicAuth: []
    parameters:
      - name: brief_response_id
        in: path
        type: number
        required: true
    definitions:
      BriefResponse:
        type: object
        properties:
          id:
            type: number
          data:
            type: object
          brief_id:
            type: number
          supplier_code:
            type: number
    responses:
      200:
        description: Suppliers that have responded to brief_id
        schema:
          id: BriefResponse
      404:
        description: brief_response_id not found
    """
    brief = briefs.get(brief_id)
    if not brief:
        return not_found('brief {} not found'.format(brief_id))

    if not briefs.has_permission_to_brief(current_user.id, brief.id):
        return forbidden('Unauthorised to get suppliers responded')

    suppliers = brief_responses_service.get_suppliers_responded(brief_id)
    work_order = work_order_service.find(brief_id=brief_id).one_or_none()

    return jsonify(brief=brief.serialize(with_users=False),
                   suppliers=suppliers,
                   workOrderCreated=True if work_order else False)
def update_brief(brief_id):
    """Update RFX brief (role=buyer)
    ---
    tags:
        - brief
    definitions:
        RFXBrief:
            type: object
            properties:
                title:
                    type: string
                organisation:
                    type: string
                location:
                    type: array
                    items:
                        type: string
                summary:
                    type: string
                industryBriefing:
                    type: string
                sellerCategory:
                    type: string
                sellers:
                    type: object
                attachments:
                    type: array
                    items:
                        type: string
                requirementsDocument:
                    type: array
                    items:
                        type: string
                responseTemplate:
                    type: array
                    items:
                        type: string
                evaluationType:
                    type: array
                    items:
                        type: string
                proposalType:
                    type: array
                    items:
                        type: string
                evaluationCriteria:
                    type: array
                    items:
                        type: object
                includeWeightings:
                    type: boolean
                closedAt:
                    type: string
                contactNumber:
                    type: string
                startDate:
                    type: string
                contractLength:
                    type: string
                contractExtensions:
                    type: string
                budgetRange:
                    type: string
                workingArrangements:
                    type: string
                securityClearance:
                    type: string
    parameters:
      - name: brief_id
        in: path
        type: number
        required: true
      - name: body
        in: body
        required: true
        schema:
            $ref: '#/definitions/RFXBrief'
    responses:
        200:
            description: Brief updated successfully.
            schema:
                $ref: '#/definitions/RFXBrief'
        400:
            description: Bad request.
        403:
            description: Unauthorised to update RFX brief.
        404:
            description: Brief not found.
        500:
            description: Unexpected error.
    """
    brief = briefs.get(brief_id)

    if not brief:
        not_found("Invalid brief id '{}'".format(brief_id))

    if brief.status != 'draft':
        abort('Cannot edit a {} brief'.format(brief.status))

    if brief.lot.slug not in ['rfx', 'atm']:
        abort('Brief lot not supported for editing')

    if current_user.role == 'buyer':
        brief_user_ids = [user.id for user in brief.users]
        if current_user.id not in brief_user_ids:
            return forbidden('Unauthorised to update brief')

    data = get_json_from_request()

    publish = False
    if 'publish' in data and data['publish']:
        del data['publish']
        publish = True

    if brief.lot.slug == 'rfx':
        # validate the RFX JSON request data
        errors = RFXDataValidator(data).validate(publish=publish)
        if len(errors) > 0:
            abort(', '.join(errors))

    if brief.lot.slug == 'atm':
        # validate the ATM JSON request data
        errors = ATMDataValidator(data).validate(publish=publish)
        if len(errors) > 0:
            abort(', '.join(errors))

    if brief.lot.slug == 'rfx' and 'evaluationType' in data:
        if 'Written proposal' not in data['evaluationType']:
            data['proposalType'] = []
        if 'Response template' not in data['evaluationType']:
            data['responseTemplate'] = []

    if brief.lot.slug == 'rfx' and 'sellers' in data and len(data['sellers']) > 0:
        data['sellerSelector'] = 'someSellers' if len(data['sellers']) > 1 else 'oneSeller'

    data['areaOfExpertise'] = ''
    if brief.lot.slug == 'atm' and 'openTo' in data:
        if data['openTo'] == 'all':
            data['sellerSelector'] = 'allSellers'
            data['sellerCategory'] = ''
        elif data['openTo'] == 'category':
            data['sellerSelector'] = 'someSellers'
            brief_domain = (
                domain_service.get_by_name_or_id(int(data['sellerCategory'])) if data['sellerCategory'] else None
            )
            if brief_domain:
                data['areaOfExpertise'] = brief_domain.name

    previous_status = brief.status
    if publish:
        brief.publish(closed_at=data['closedAt'])
        if 'sellers' in brief.data and data['sellerSelector'] != 'allSellers':
            for seller_code, seller in brief.data['sellers'].iteritems():
                supplier = suppliers.get_supplier_by_code(seller_code)
                if brief.lot.slug == 'rfx':
                    send_seller_invited_to_rfx_email(brief, supplier)
        try:
            brief_url_external = '{}/2/digital-marketplace/opportunities/{}'.format(
                current_app.config['FRONTEND_ADDRESS'],
                brief_id
            )
            _notify_team_brief_published(
                brief.data['title'],
                brief.data['organisation'],
                current_user.name,
                current_user.email_address,
                brief_url_external
            )
        except Exception as e:
            pass

    brief.data = data
    briefs.save_brief(brief)

    if publish:
        brief_url_external = '{}/2/digital-marketplace/opportunities/{}'.format(
            current_app.config['FRONTEND_ADDRESS'],
            brief_id
        )
        publish_tasks.brief.delay(
            publish_tasks.compress_brief(brief),
            'published',
            previous_status=previous_status,
            name=current_user.name,
            email_address=current_user.email_address,
            url=brief_url_external
        )
    try:
        audit_service.log_audit_event(
            audit_type=AuditTypes.update_brief,
            user=current_user.email_address,
            data={
                'briefId': brief.id,
                'briefData': brief.data
            },
            db_object=brief)
    except Exception as e:
        rollbar.report_exc_info()

    return jsonify(brief.serialize(with_users=False))
def delete_brief(brief_id):
    """Delete brief (role=buyer)
    ---
    tags:
        - brief
    definitions:
        DeleteBrief:
            type: object
            properties:
                message:
                    type: string
    parameters:
      - name: brief_id
        in: path
        type: number
        required: true
    responses:
        200:
            description: Brief deleted successfully.
            schema:
                $ref: '#/definitions/DeleteBrief'
        400:
            description: Bad request. Brief status must be 'draft'.
        403:
            description: Unauthorised to delete brief.
        404:
            description: brief_id not found.
        500:
            description: Unexpected error.
    """
    brief = briefs.get(brief_id)

    if not brief:
        not_found("Invalid brief id '{}'".format(brief_id))

    if current_user.role == 'buyer':
        brief_user_ids = [user.id for user in brief.users]
        if current_user.id not in brief_user_ids:
            return forbidden('Unauthorised to delete brief')

    if brief.status != 'draft':
        abort('Cannot delete a {} brief'.format(brief.status))

    audit = AuditEvent(
        audit_type=AuditTypes.delete_brief,
        user=current_user.email_address,
        data={
            'briefId': brief_id
        },
        db_object=None
    )

    try:
        deleted_brief = publish_tasks.compress_brief(brief)
        audit_service.save(audit)
        briefs.delete(brief)
        publish_tasks.brief.delay(
            deleted_brief,
            'deleted',
            user=current_user.email_address
        )
    except Exception as e:
        extra_data = {'audit_type': AuditTypes.delete_brief, 'briefId': brief.id, 'exception': e.message}
        rollbar.report_exc_info(extra_data=extra_data)

    return jsonify(message='Brief {} deleted'.format(brief_id)), 200
def get_domain(domain_id):
    domain = domain_service.get_by_name_or_id(domain_id, show_legacy=False)
    if not domain:
        return not_found('Domain does not exist')
    return jsonify(domain.serialize())
def get_brief_overview(brief_id):
    """Overview (role=buyer)
    ---
    tags:
        - brief
    definitions:
        BriefOverview:
            type: object
            properties:
                sections:
                    type: array
                    items:
                        $ref: '#/definitions/BriefOverviewSections'
                title:
                    type: string
        BriefOverviewSections:
            type: array
            items:
                $ref: '#/definitions/BriefOverviewSection'
        BriefOverviewSection:
            type: object
            properties:
                links:
                    type: array
                    items:
                        $ref: '#/definitions/BriefOverviewSectionLinks'
                title:
                    type: string
        BriefOverviewSectionLinks:
            type: array
            items:
                $ref: '#/definitions/BriefOverviewSectionLink'
        BriefOverviewSectionLink:
            type: object
            properties:
                complete:
                    type: boolean
                path:
                    type: string
                    nullable: true
                text:
                    type: string
    responses:
        200:
            description: Data for the Overview page
            schema:
                $ref: '#/definitions/BriefOverview'
        400:
            description: Lot not supported.
        403:
            description: Unauthorised to view brief.
        404:
            description: brief_id not found
    """
    brief = briefs.get(brief_id)

    if not brief:
        not_found("Invalid brief id '{}'".format(brief_id))

    if current_user.role == 'buyer':
        brief_user_ids = [user.id for user in brief.users]
        if current_user.id not in brief_user_ids:
            return forbidden('Unauthorised to view brief')

    if not (brief.lot.slug == 'digital-professionals' or
            brief.lot.slug == 'training'):
        abort('Lot {} is not supported'.format(brief.lot.slug))

    sections = brief_overview_service.get_sections(brief)

    return jsonify(sections=sections, status=brief.status, title=brief.data['title']), 200
Example #28
0
def get_evidence_feedback(evidence_id):
    evidence = evidence_service.get_evidence_by_id(evidence_id)
    if not evidence or current_user.supplier_code != evidence.supplier_code:
        not_found("No evidence for id '%s' found" % (evidence_id))
    if not evidence.status == 'rejected':
        abort('Only rejected submissions can contain feedback')
    evidence_assessment = evidence_assessment_service.get_assessment_for_rejected_evidence(
        evidence_id)
    if not evidence_assessment:
        abort('Failed to get the evidence assessment')

    try:
        domain_criteria = DomainCriteria(domain_id=evidence.domain.id,
                                         rate=evidence.data.get(
                                             'maxDailyRate', None))
        criteria_needed = domain_criteria.get_criteria_needed()
    except Exception as e:
        abort(str(e))

    criteria_from_domain = {}
    domain_criteria = domain_criteria_service.get_criteria_by_domain_id(
        evidence.domain.id)
    for criteria in domain_criteria:
        criteria_from_domain[str(criteria.id)] = criteria.name

    criteria = {}
    failed_criteria = evidence_assessment.data.get('failed_criteria', {})
    vfm = evidence_assessment.data.get('vfm', None)
    for criteria_id, criteria_response in evidence.get_criteria_responses(
    ).iteritems():
        has_feedback = True if criteria_id in failed_criteria.keys() else False
        criteria[criteria_id] = {
            "response":
            criteria_response,
            "name":
            criteria_from_domain[criteria_id]
            if criteria_id in criteria_from_domain else '',
            "has_feedback":
            has_feedback,
            "assessment":
            failed_criteria[criteria_id] if has_feedback else {}
        }

    current_evidence = evidence_service.get_latest_evidence_for_supplier_and_domain(
        evidence.domain.id, current_user.supplier_code)

    data = {
        'domain_id':
        evidence.domain.id,
        'domain_name':
        evidence.domain.name,
        'criteria':
        criteria,
        'criteria_needed':
        criteria_needed,
        'current_evidence_id':
        current_evidence.id if current_evidence.status == 'draft' else None,
        'vfm':
        vfm
    }

    return jsonify(data)
def get_brief_responses(brief_id):
    """All brief responses (role=supplier,buyer)
    ---
    tags:
      - brief
    security:
      - basicAuth: []
    parameters:
      - name: brief_id
        in: path
        type: number
        required: true
    definitions:
      BriefResponses:
        properties:
          briefResponses:
            type: array
            items:
              id: BriefResponse
    responses:
      200:
        description: A list of brief responses
        schema:
          id: BriefResponses
      404:
        description: brief_id not found
    """
    brief = briefs.get(brief_id)
    if not brief:
        not_found("Invalid brief id '{}'".format(brief_id))

    if current_user.role == 'buyer':
        brief_user_ids = [user.id for user in brief.users]
        if current_user.id not in brief_user_ids:
            return forbidden("Unauthorised to view brief or brief does not exist")

    supplier_code = getattr(current_user, 'supplier_code', None)
    if current_user.role == 'supplier':
        validation_result = supplier_business.get_supplier_messages(supplier_code, True)
        if len(validation_result.errors) > 0:
            abort(validation_result.errors)
        # strip data from seller view
        if 'sellers' in brief.data:
            brief.data['sellers'] = {}
        if brief.responses_zip_filesize:
            brief.responses_zip_filesize = None
        if 'industryBriefing' in brief.data:
            brief.data['industryBriefing'] = ''
        if 'attachments' in brief.data:
            brief.data['attachments'] = []
        if 'backgroundInformation' in brief.data:
            brief.data['backgroundInformation'] = ''
        if 'outcome' in brief.data:
            brief.data['outcome'] = ''
        if 'endUsers' in brief.data:
            brief.data['endUsers'] = ''
        if 'workAlreadyDone' in brief.data:
            brief.data['workAlreadyDone'] = ''
        if 'timeframeConstraints' in brief.data:
            brief.data['timeframeConstraints'] = ''
        if 'contactNumber' in brief.data:
            brief.data['contactNumber'] = ''

    if current_user.role == 'buyer' and brief.status != 'closed':
        brief_responses = []
    else:
        brief_responses = brief_responses_service.get_brief_responses(brief_id, supplier_code)

    return jsonify(brief=brief.serialize(with_users=False, with_author=False),
                   briefResponses=brief_responses)
def get_brief(brief_id):
    """Get brief
    ---
    tags:
        - brief
    parameters:
      - name: brief_id
        in: path
        type: number
        required: true
    responses:
        200:
            description: Brief retrieved successfully.
            schema:
                type: object
                properties:
                    brief:
                        type: object
                    brief_response_count:
                        type: number
                    invited_seller_count:
                        type: number
                    can_respond:
                        type: boolean
                    open_to_all:
                        type: boolean
                    is_brief_owner:
                        type: boolean
                    is_buyer:
                        type: boolean
                    has_responded:
                        type: boolean
                    has_chosen_brief_category:
                        type: boolean
                    is_assessed_for_category:
                        type: boolean
                    is_assessed_in_any_category:
                        type: boolean
                    is_approved_seller:
                        type: boolean
                    is_awaiting_application_assessment:
                        type: boolean
                    is_awaiting_domain_assessment:
                        type: boolean
                    has_been_assessed_for_brief:
                        type: boolean
                    open_to_category:
                        type: boolean
                    is_applicant:
                        type: boolean
                    is_recruiter:
                        type: boolean
                    domains:
                        type: array
                        items:
                            type: object
        403:
            description: Unauthorised to view brief.
        404:
            description: Brief not found.
        500:
            description: Unexpected error.
    """
    brief = briefs.find(id=brief_id).one_or_none()
    if not brief:
        not_found("No brief for id '%s' found" % (brief_id))

    user_role = current_user.role if hasattr(current_user, 'role') else None
    invited_sellers = brief.data['sellers'] if 'sellers' in brief.data else {}

    is_buyer = False
    is_brief_owner = False
    brief_user_ids = [user.id for user in brief.users]
    if user_role == 'buyer':
        is_buyer = True
        if current_user.id in brief_user_ids:
            is_brief_owner = True

    if brief.status == 'draft' and not is_brief_owner:
        return forbidden("Unauthorised to view brief")

    brief_response_count = len(brief_responses_service.get_brief_responses(brief_id, None))
    invited_seller_count = len(invited_sellers)
    open_to_all = brief.lot.slug == 'atm' and brief.data.get('openTo', '') == 'all'
    open_to_category = brief.lot.slug == 'atm' and brief.data.get('openTo', '') == 'category'
    is_applicant = user_role == 'applicant'

    # gather facts about the user's status against this brief
    user_status = BriefUserStatus(brief, current_user)
    has_chosen_brief_category = user_status.has_chosen_brief_category()
    is_assessed_for_category = user_status.is_assessed_for_category()
    is_assessed_in_any_category = user_status.is_assessed_in_any_category()
    is_awaiting_application_assessment = user_status.is_awaiting_application_assessment()
    is_awaiting_domain_assessment = user_status.is_awaiting_domain_assessment()
    has_been_assessed_for_brief = user_status.has_been_assessed_for_brief()
    is_recruiter_only = user_status.is_recruiter_only()
    is_approved_seller = user_status.is_approved_seller()
    can_respond = user_status.can_respond()
    has_responded = user_status.has_responded()

    # remove private data for non brief owners
    brief.data['contactEmail'] = ''
    brief.data['users'] = None
    if not is_buyer:
        if 'sellers' in brief.data:
            brief.data['sellers'] = {}
        brief.responses_zip_filesize = None
        brief.data['contactNumber'] = ''
        if not can_respond:
            brief.data['proposalType'] = []
            brief.data['evaluationType'] = []
            brief.data['responseTemplate'] = []
            brief.data['requirementsDocument'] = []
            brief.data['industryBriefing'] = ''
            brief.data['backgroundInformation'] = ''
            brief.data['outcome'] = ''
            brief.data['endUsers'] = ''
            brief.data['workAlreadyDone'] = ''
            brief.data['timeframeConstraints'] = ''
            brief.data['attachments'] = []
    else:
        brief.data['contactEmail'] = [user.email_address for user in brief.users][0]
        if not is_brief_owner:
            if 'sellers' in brief.data:
                brief.data['sellers'] = {}
            brief.data['industryBriefing'] = ''
            brief.data['contactNumber'] = ''

    domains = []
    for domain in domain_service.all():
        domains.append({
            'id': str(domain.id),
            'name': domain.name
        })

    return jsonify(brief=brief.serialize(with_users=False, with_author=is_brief_owner),
                   brief_response_count=brief_response_count,
                   invited_seller_count=invited_seller_count,
                   can_respond=can_respond,
                   has_chosen_brief_category=has_chosen_brief_category,
                   is_assessed_for_category=is_assessed_for_category,
                   is_assessed_in_any_category=is_assessed_in_any_category,
                   is_approved_seller=is_approved_seller,
                   is_awaiting_application_assessment=is_awaiting_application_assessment,
                   is_awaiting_domain_assessment=is_awaiting_domain_assessment,
                   has_been_assessed_for_brief=has_been_assessed_for_brief,
                   open_to_all=open_to_all,
                   open_to_category=open_to_category,
                   is_brief_owner=is_brief_owner,
                   is_buyer=is_buyer,
                   is_applicant=is_applicant,
                   is_recruiter_only=is_recruiter_only,
                   has_responded=has_responded,
                   domains=domains)