コード例 #1
0
class BaseCampaigns(Resource):
    """
    This resource creates a base-campaign in database table base-campaign.
    """
    # Access token decorator
    decorators = [require_oauth()]

    def post(self):
        """
        This creates a base campaign with following payload

                {
                    "name": "Jobs at getTalent
                    "Description": "We are looking for Python developers
                }

        """
        user = request.user
        data = request.get_json(silent=True)
        if not data:
            raise InvalidUsage("Received empty request body")
        name = data.get('name', '')
        description = data.get('description', '')
        if not name or not description:
            raise InvalidUsage('Name and description are required fields')
        base_campaign = BaseCampaign(user_id=user.id, name=name, description=description)
        base_campaign.save()
        return {'id': base_campaign.id}, codes.CREATED
コード例 #2
0
class TestEmailResource(Resource):
    """
    This resource is to send test email to preview the email before sending the actual email campaign to candidates.
    """
    # Access token decorator
    decorators = [require_oauth()]

    def post(self):
        """
            POST /v1/test-email
            Send email campaign with data (subject, from, body_html, emails)
            Sample POST Data:

            {
              "subject": "Test Email",
              "from": "Zohaib Ijaz",
              "body_html": "<html><body><h1>Welcome to email campaign service <a href=https://www.github.com>Github</a></h1></body></html>",
              "emails": ["*****@*****.**", "*****@*****.**"],
              "reply_to": "*****@*****.**"
            }
        """
        user = request.user
        send_test_email(user, request)
        return {
            'message': 'test email has been sent to given emails'
        }, codes.OK
コード例 #3
0
class EmailCampaignBlastById(Resource):
    """
    Endpoint looks like /v1/email-campaigns/:id/blasts/:id.
    This resource returns a blast object for given blast_id associated with given campaign.
    """
    decorators = [require_oauth()]

    def get(self, campaign_id, blast_id):
        """
        This endpoint returns a blast object for a given campaign_id and blast_id.
        From that blast object we can extract sends, clicks etc.
        :param campaign_id: int, unique id of a email campaign
        :param blast_id: id of blast object
        :type campaign_id: int | long
        :type blast_id: int | long
        :return: JSON data containing dict of blast object

        :Example:

        >>> import requests
        >>> headers = {'Authorization': 'Bearer <access_token>'}
        >>> campaign_id = 1
        >>> blast_id = 1
        >>> response = requests.get(EmailCampaignApiUrl.BLAST % (campaign_id, blast_id),
        >>>                         headers=headers)

        .. Response::

               {
                  "blast": {
                                "updated_datetime": "2016-02-10 19:37:15",
                                "sends": 1,
                                "bounces": 0,
                                "campaign_id": 1,
                                "text_clicks": 0,
                                "html_clicks": 0,
                                "complaints": 0,
                                "id": "1",
                                "opens": 0,
                                "sent_datetime": "2016-02-10 19:37:04"
                              }
               }

        .. Status:: 200 (OK)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Requested campaign does not belong to user's domain OR requested blast
                        object is not associated with given campaign_id)
                    404 (Campaign not found OR blast_obj with given id not found)
                    500 (Internal server error)
        """
        raise_if_dict_values_are_not_int_or_long(
            dict(campaign_id=campaign_id, blast_id=blast_id))
        # Get valid blast object
        blast_obj = EmailCampaignBase.get_valid_blast_obj(
            campaign_id, blast_id, request.user)
        return dict(blast=blast_obj.to_json()), codes.OK
コード例 #4
0
class EmailCampaignSendApi(Resource):
    """
    This endpoint looks like /v1/email-campaigns/:id/send
    """
    decorators = [require_oauth()]

    def post(self, campaign_id):
        """
        Sends campaign emails to the candidates present in smartlists of campaign.
        Scheduler service will call this to send emails to candidates.
        :param int|long campaign_id: Campaign id
        """
        raise_if_dict_values_are_not_int_or_long(dict(campaign_id=campaign_id))
        email_campaign = EmailCampaignBase.get_campaign_if_domain_is_valid(
            campaign_id, request.user)
        if email_campaign.is_hidden:
            logger.info(
                "Email campaign(id:%s) is archived, it cannot be sent." %
                campaign_id)
            # Unschedule task from scheduler_service
            if email_campaign.scheduler_task_id:
                headers = {'Authorization': request.oauth_token}
                # campaign was scheduled, remove task from scheduler_service
                if CampaignUtils.delete_scheduled_task(
                        email_campaign.scheduler_task_id, headers):
                    email_campaign.update(
                        scheduler_task_id='')  # Delete scheduler task id
            raise ResourceNotFound("Email campaign(id:%s) has been deleted." %
                                   campaign_id,
                                   error_code=EMAIL_CAMPAIGN_NOT_FOUND[1])
        email_client_id = email_campaign.email_client_id
        results_send = send_email_campaign(request.user,
                                           email_campaign,
                                           new_candidates_only=False)
        if email_client_id:
            if not isinstance(results_send, list):
                raise InternalServerError(
                    error_message="Something went wrong, response is not list")
            data = {
                'email_campaign_sends': [{
                    'email_campaign_id':
                    email_campaign.id,
                    'new_html':
                    new_email_html_or_text.get('new_html'),
                    'new_text':
                    new_email_html_or_text.get('new_text'),
                    'candidate_email_address':
                    new_email_html_or_text.get('email')
                } for new_email_html_or_text in results_send]
            }
            return jsonify(data)

        return dict(
            message='email_campaign(id:%s) is being sent to candidates.' %
            campaign_id), codes.OK
コード例 #5
0
class TemplatesInFolder(Resource):
    """
    Endpoint looks like /v1/email-template-folders/:id/email-templates.
    """
    decorators = [validate_domain_id_for_email_templates(), require_oauth()]

    @require_all_permissions(Permission.PermissionNames.CAN_GET_CAMPAIGNS)
    def get(self, folder_id):
        """
        GET /v1/email-template-folders/:id/email-templates
        Required parameters:
        :param int|long folder_id: ID of of email template
        :return: template-folder object in dict format, status 200

        :Example:

        >>> import requests
        >>> headers = {'Authorization': 'Bearer <access_token>'}
        >>> template_folder_id = 1
        >>> response = requests.get(EmailCampaignApiUrl.TEMPLATES_IN_FOLDER % template_folder_id,
        >>>                         headers=headers)

        ..Response::

                {
                  "email_templates": [
                    {
                      "user_id": 1,
                      "name": "My Template",
                      "body_text": "This is the text part of the email",
                      "template_folder_id": 8,
                      "updated_datetime": "2016-09-05 15:11:22",
                      "body_html": "<html><body>Email Body</body></html>",
                      "is_immutable": 1,
                      "type": 0,
                      "id": 41
                    }
                  ]
                }
        .. Status:: 200 (Resource found)
                    401 (Unauthorized to access getTalent)
                    403 (Requested email-template-folder does not belong to user's domain)
                    404 (Requested email-template-folder not found)
                    500 (Internal server error)
        """
        template_folder = EmailTemplateFolder.get_valid_template_folder(
            folder_id, request.user.domain_id)
        return {
            "email_templates": [
                template.to_json()
                for template in template_folder.user_email_template
            ]
        }, codes.OK
コード例 #6
0
class InvitationStatus(Resource):
    """
    This returns invitation status of candidate for given campaign.
    """
    # Access token decorator
    decorators = [require_oauth()]

    def get(self, email_campaign_id, candidate_id):
        """
        This returns invitation status of candidate for given campaign.
        Invitations statuses are as:
            Delivered: Candidate has received the email-campaign
            Not-Delivered: Candidate has not received the email-campaign
            Opened: Candidate has opened the email-campaign
            Accepted: Candidate RSVP'd YES to the promoted event
            Rejected: Candidate RSVP'd NO to the promoted event
        """
        raise_if_dict_values_are_not_int_or_long(
            dict(campaign_id=email_campaign_id, candidate_id=candidate_id))
        user = request.user
        email_campaign_send_id = None
        invitation_status = INVITATION_STATUSES['Not-Delivered']
        email_campaign = EmailCampaignBase.get_campaign_if_domain_is_valid(
            email_campaign_id, request.user)
        # Check if candidate has received the email-campaign
        for send in email_campaign.sends.all():
            if candidate_id == send.candidate_id:
                invitation_status = INVITATION_STATUSES['Delivered']
                email_campaign_send_id = send.id
                break
        # Check if candidate has opened the email-campaign
        for activity_type in (Activity.MessageIds.CAMPAIGN_EMAIL_OPEN,
                              Activity.MessageIds.CAMPAIGN_EMAIL_CLICK):
            url = "{}?type={}&source_id={}&source_table={}".format(
                ActivityApiUrl.ACTIVITIES, activity_type,
                email_campaign_send_id, EmailCampaignSend.__tablename__)
            response = send_request('get', url,
                                    request.headers['Authorization'])
            if response.ok:
                invitation_status = INVITATION_STATUSES['Opened']
        if email_campaign.base_campaign_id:
            base_campaign = BaseCampaign.search_by_id_in_domain(
                email_campaign.base_campaign_id, user.domain_id)
            base_campaign_events = base_campaign.base_campaign_events.all()
            if base_campaign_events:
                event = base_campaign_events[0].event
                rsvp_in_db = RSVP.filter_by_keywords(candidate_id=candidate_id,
                                                     event_id=event.id)
                if rsvp_in_db and rsvp_in_db[0].status.lower() == 'yes':
                    invitation_status = INVITATION_STATUSES['Accepted']
                elif rsvp_in_db and rsvp_in_db[0].status.lower() == 'no':
                    invitation_status = INVITATION_STATUSES['Rejected']
        return dict(invitation_status=invitation_status), codes.OK
コード例 #7
0
class EmailCampaignSendById(Resource):
    """
    Endpoint looks like /v1/email-campaigns/:id/sends/:id.
    This resource returns a send object for given send_id associated with given campaign.
    """
    decorators = [require_oauth()]

    def get(self, campaign_id, send_id):
        """
        This endpoint returns a send object for a given campaign_id and send_id.
        :param campaign_id: int, unique id of a email campaign
        :param send_id: id of send object
        :type campaign_id: int | long
        :type send_id: int | long
        :return: JSON data containing dict of send object

        :Example:

        >>> import requests
        >>> headers = {'Authorization': 'Bearer <access_token>'}
        >>> campaign_id = 1
        >>> send_id = 1
        >>> response = requests.get(EmailCampaignApiUrl.SEND_BY_ID % (campaign_id, send_id),
        >>>                         headers=headers)

        .. Response::

               {
                  "send": {
                                "ses_message_id": "",
                                "is_ses_bounce": false,
                                "updated_datetime": "2016-02-29 15:26:08",
                                "ses_request_id": "",
                                "campaign_id": 1,
                                "candidate_id": 11,
                                "is_ses_complaint": false,
                                "id": 114,
                                "sent_datetime": "2016-02-29 15:41:38"
                              }
                }
        .. Status:: 200 (OK)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Requested campaign does not belong to user's domain or requested send
                        object is not associated with given campaign id)
                    404 (Campaign not found or send object with given id not found)
                    500 (Internal server error)
        """
        # Get valid send object
        send_obj = get_valid_send_obj(campaign_id, send_id, request.user)
        return dict(send=send_obj.to_json()), codes.OK
コード例 #8
0
class SingleEmailCampaign(Resource):
    # Access token decorator
    decorators = [require_oauth()]

    def get(self, campaign_id):
        """
        GET /v1/email-campaigns/<id>    Fetch EmailCampaign object
        """
        raise_if_dict_values_are_not_int_or_long(dict(campaign_id=campaign_id))
        include_fields = request.values['fields'].split(
            ',') if request.values.get('fields') else None
        email_campaign = EmailCampaignBase.get_campaign_if_domain_is_valid(
            campaign_id, request.user)
        return {
            "email_campaign":
            email_campaign.to_dict(include_fields=include_fields)
        }

    def patch(self, campaign_id):
        """
        This endpoint updates an existing campaign
        :param int|long campaign_id: Id of campaign
        """
        raise_if_dict_values_are_not_int_or_long(dict(campaign_id=campaign_id))
        # Get and validate request data
        data = request.get_json(silent=True)
        if not data:
            raise InvalidUsage("Received empty request body",
                               error_code=INVALID_REQUEST_BODY[1])
        is_hidden = data.get('is_hidden', False)
        if is_hidden not in (True, False, 1, 0):
            raise InvalidUsage(
                "is_hidden field should be a boolean, given: %s" % is_hidden,
                error_code=INVALID_INPUT[1])
        email_campaign = EmailCampaignBase.get_campaign_if_domain_is_valid(
            campaign_id, request.user)
        # Unschedule task from scheduler_service
        if email_campaign.scheduler_task_id:
            headers = {'Authorization': request.oauth_token}
            # campaign was scheduled, remove task from scheduler_service
            if CampaignUtils.delete_scheduled_task(
                    email_campaign.scheduler_task_id, headers):
                email_campaign.update(
                    scheduler_task_id='')  # Delete scheduler task id

        email_campaign.update(is_hidden=is_hidden)
        logger.info("Email campaign(id:%s) has been archived successfully" %
                    campaign_id)
        return dict(message="Email campaign (id: %s) updated successfully" %
                    campaign_id), codes.OK
コード例 #9
0
class EmailClientsWithId(Resource):
    """
    This endpoint looks like /v1/email-clients/:id.
    We can get an email-client with its id in database table "email_client_credentials".
    """

    # Access token decorator
    decorators = [require_oauth()]

    def get(self, email_client_id):
        """
        This will get record from database table email_client_credentials for requested id.

        .. Response::
                       {
                          "email_client_credentials": {
                            "user_id": 1,
                            "name": "Gmail",
                            "updated_datetime": "2016-09-28 19:38:55",
                            "id": 69,
                            "port": "587",
                            "host": "smtp.gmail.com",
                            "password": "******",
                            "email": "*****@*****.**"
                          }
                        }

        .. Status:: 200 (Resource Found)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Unauthorized to access requested resource)
                    404 (Resource not found)
                    500 (Internal server error)
        """
        raise_if_dict_values_are_not_int_or_long(
            dict(email_client_id=email_client_id))
        client_in_db = EmailClientCredentials.get_by_id(email_client_id)
        if not client_in_db:
            raise ResourceNotFound(EMAIL_CLIENT_NOT_FOUND[0],
                                   error_code=EMAIL_CLIENT_NOT_FOUND[1])
        if not client_in_db.user.domain_id == request.user.domain_id:
            raise ForbiddenError(EMAIL_CLIENT_FORBIDDEN[0],
                                 error_code=EMAIL_CLIENT_FORBIDDEN[1])
        return {'email_client_credentials': client_in_db.to_json()}, codes.OK
コード例 #10
0
class BaseCampaignLinkEvent(Resource):
    """
    This resource links an social-network event with base-campaign in database table base-campaign-event.
    """
    # Access token decorator
    decorators = [require_oauth()]

    def post(self, base_campaign_id, event_id):
        """
        This links an event with base-campaign.
        """
        event_in_db = Event.get_by_id(event_id)
        if not event_in_db or event_in_db.is_deleted_from_vendor or event_in_db.is_hidden:
            raise ResourceNotFound('Requested event not found in database')
        is_event_in_domain = Event.get_by_event_id_and_domain_id(event_id, request.user.domain_id)
        if not is_event_in_domain:
            raise ForbiddenError('Requested event does not belong to requested user`s domain')
        validate_base_campaign_id(base_campaign_id, request.user.domain_id)
        base_campaign_event = BaseCampaignEvent(base_campaign_id=base_campaign_id, event_id=event_id)
        base_campaign_event.save()
        return {'id': base_campaign_event.id}, codes.CREATED
コード例 #11
0
class EmailCampaignSends(Resource):
    """
    Endpoint looks like /v1/email-campaigns/:id/sends
    This resource returns all the sends objects associated with given campaign.
    """
    decorators = [require_oauth()]

    def get(self, campaign_id):
        """
        This endpoint returns a list of send objects (dict) associated with a specific
        email campaign.

        :param campaign_id: int, unique id of a email campaign
        :type campaign_id: int | long
        :return: JSON data containing list of send objects and their count

        :Example:

        >>> import requests
        >>> headers = {'Authorization': 'Bearer <access_token>'}
        >>> campaign_id = 1
        >>> response = requests.get(EmailCampaignApiUrl.SENDS % campaign_id, headers=headers)

        .. Response::

            {
                "sends": [
                            {
                              "ses_message_id": "",
                              "is_ses_bounce": false,
                              "updated_datetime": "2016-02-29 15:26:08",
                              "ses_request_id": "",
                              "campaign_id": 1,
                              "candidate_id": 11,
                              "is_ses_complaint": false,
                              "id": 114,
                              "sent_datetime": "2016-02-29 15:41:38"
                            },
                            {
                              "ses_message_id": "",
                              "is_ses_bounce": false,
                              "updated_datetime": "2016-02-29 15:26:08",
                              "ses_request_id": "",
                              "campaign_id": 1,
                              "candidate_id": 1,
                              "is_ses_complaint": false,
                              "id": 115,
                              "sent_datetime": "2016-02-29 15:41:38"
                            }
                        ]
            }

        .. Status:: 200 (OK)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Requested campaign does not belong to user's domain)
                    404 (Campaign not found)
                    500 (Internal Server Error)
        """
        raise_if_dict_values_are_not_int_or_long(dict(campaign_id=campaign_id))
        # Get a campaign that was created by this user
        campaign = EmailCampaignBase.get_campaign_if_domain_is_valid(
            campaign_id, request.user)
        # get paginated response
        page, per_page = get_pagination_params(
            request, error_code=INVALID_VALUE_OF_PAGINATION_PARAM[1])
        return get_paginated_response('sends', campaign.sends, page, per_page)
コード例 #12
0
class EmailCampaigns(Resource):
    # Access token decorator
    decorators = [require_oauth()]

    def get(self):
        """
        GET /v1/email-campaigns         Fetches all EmailCampaign objects from auth user's domain
        """
        user = request.user
        page, per_page = get_pagination_params(
            request, error_code=INVALID_VALUE_OF_PAGINATION_PARAM[1])
        sort_type = request.args.get('sort_type', 'DESC')
        search_keyword = request.args.get('search', '')
        sort_by = request.args.get('sort_by', 'added_datetime')
        is_hidden = request.args.get('is_hidden', 0)
        user_id = request.args.get('user_id')

        # Validation of query parameters
        if isinstance(user_id, basestring):
            if not user_id.strip().isdigit() or int(user_id) <= 0:
                raise InvalidUsage(NOT_NON_ZERO_NUMBER[0].format('`user_id`'),
                                   error_code=NOT_NON_ZERO_NUMBER[1])
            if request.user.role.name != Role.TALENT_ADMIN \
                    and User.get_domain_id(user_id) != request.user.domain_id:
                raise ForbiddenError(
                    "Logged-in user and requested user_id are of different domains",
                    EMAIL_CAMPAIGN_FORBIDDEN[1])
            user_id = int(user_id)

        if not is_number(is_hidden) or int(is_hidden) not in (0, 1):
            raise InvalidUsage('`is_hidden` can be either 0 or 1',
                               error_code=INVALID_VALUE_OF_QUERY_PARAM[1])

        if sort_by not in ('added_datetime', 'name'):
            raise InvalidUsage('Value of sort_by parameter is not valid',
                               error_code=INVALID_VALUE_OF_QUERY_PARAM[1])

        if sort_type not in SORT_TYPES:
            raise InvalidUsage(
                'Value of sort_type parameter is not valid. Valid values are %s'
                % list(SORT_TYPES),
                error_code=INVALID_VALUE_OF_QUERY_PARAM[1])

        # Get all email campaigns from logged in user's domain
        query = EmailCampaign.get_by_domain_id_and_filter_by_name(
            user.domain_id,
            search_keyword,
            sort_by,
            sort_type,
            int(is_hidden),
            user_id=user_id)

        return get_paginated_response('email_campaigns',
                                      query,
                                      page,
                                      per_page,
                                      parser=EmailCampaign.to_dict)

    def post(self):
        """
            POST /v1/email-campaigns
            Required parameters:
            name: Name of email campaign
            subject: subject of email
            body_html: email body
            list_ids: smartlist ids to which emails will be sent
        """
        # Get and validate request data
        data = get_valid_json_data(request, error_code=INVALID_REQUEST_BODY[1])
        data = validate_and_format_request_data(data, request.user)

        campaign = create_email_campaign(
            user_id=request.user.id,
            oauth_token=request.oauth_token,
            name=data['name'],
            subject=data['subject'],
            description=data['description'],
            _from=data['from'],
            reply_to=data['reply_to'],
            body_html=data['body_html'],
            body_text=data['body_text'],
            list_ids=data['list_ids'],
            email_client_id=data['email_client_id'],
            start_datetime=data['start_datetime'],
            end_datetime=data['end_datetime'],
            frequency_id=data['frequency_id'],
            email_client_credentials_id=data['email_client_credentials_id'],
            base_campaign_id=data['base_campaign_id'])

        return {'campaign': campaign}, codes.CREATED
コード例 #13
0
class BaseCampaignOverview(Resource):
    """
    This resource returns event and all chained campaigns with given base_campaign_id
    """
    # Access token decorator
    decorators = [require_oauth()]

    def get(self, base_campaign_id):
        """
        This resource returns event and all chained campaigns with given base_campaign_id.
        ..Response::

        {
        "event": {
                "cost": 0,
                "start_datetime": "2016-08-13 16:21:42",
                "venue_id": 307,
                "user_id": 1,
                "is_deleted_from_vendor": 0,
                "description": "Test Event Description",
                "social_network_id": 13,
                "url": "",
                "title": "Eventbrite Test Event",
                "registration_instruction": "Just Come",
                "max_attendees": 10,
                "timezone": "Asia/Karachi",
                "currency": "USD",
                "venue": {
                              "city": "Lahore",
                              "user_id": 1,
                              "social_network_id": 18,
                              "country": "",
                              "longitude": 0,
                              "social_network_venue_id": "16271034",
                              "state": "Punjab",
                              "latitude": 0,
                              "zip_code": "",
                              "address_line_2": "H# 163, Block A",
                              "id": 307,
                              "address_line_1": "New Muslim Town"
                            },

                "rsvps": [
                          {
                            "social_network_rsvp_id": "6956",
                            "status": "yes",
                            "social_network_id": 13,
                            "event_id": 1,
                            "payment_status": "",
                            "datetime": "",
                            "candidate_id": 362553,
                            "id": 2
                          },
                          {
                            "social_network_rsvp_id": "2983",
                            "status": "yes",
                            "social_network_id": 13,
                            "event_id": 1,
                            "payment_status": "",
                            "datetime": "",
                            "candidate_id": 362555,
                            "id": 3
                          },
                          {
                            "social_network_rsvp_id": "5146",
                            "status": "yes",
                            "social_network_id": 13,
                            "event_id": 1,
                            "payment_status": "",
                            "datetime": "",
                            "candidate_id": 362557,
                            "id": 4
                          }
                        ],
                "tickets_id": 53364240,
                "social_network_group_id": "18837246",
                "group_url_name": "QC-Python-Learning",
                "organizer_id": 33,
                "base_campaign_id": 1,
                "id": 1,
                "social_network_event_id": "27067814562",
                "end_datetime": "2016-08-14 16:21:42"
              },
        "email_campaigns": [
                {
                      "email_client_credentials_id": null,
                      "start_datetime": null,
                      "user_id": 1,
                      "name": "Email campaign",
                      "body_text": null,
                      "description": null,
                      "list_ids": [1],
                      "body_html": null,
                      "blasts": [
                            {
                              "updated_datetime": "2016-02-10 20:35:57",
                              "sends": 0,
                              "bounces": 0,
                              "campaign_id": 11,
                              "text_clicks": 0,
                              "html_clicks": 0,
                              "complaints": 0,
                              "id": 15,
                              "opens": 0,
                              "sent_datetime": "2016-02-10 20:38:39"
                            },
                            {
                              "updated_datetime": "2016-02-10 20:35:57",
                              "sends": 0,
                              "bounces": 0,
                              "campaign_id": 11,
                              "text_clicks": 0,
                              "html_clicks": 0,
                              "complaints": 0,
                              "id": 16,
                              "opens": 0,
                              "sent_datetime": "2016-02-10 20:38:40"
                            }
                          ],
                      "added_datetime": "2016-02-10T20:35:57+00:00",
                      "frequency": null,
                      "end_datetime": null,
                      "talent_pipelines": [],
                      "reply_to": "*****@*****.**",
                      "from": "basit",
                      "is_hidden": false,
                      "base_campaign_id": 1,
                      "id": 11,
                      "subject": "email campaign sample subject"
                    },
                {
                      "email_client_credentials_id": null,
                      "start_datetime": null,
                      "user_id": 1,
                      "name": "Email campaign",
                      "body_text": null,
                      "description": null,
                      "list_ids": [1],
                      "body_html": null,
                      "blasts": [
                            {
                              "updated_datetime": "2016-02-10 20:39:54",
                              "sends": 1,
                              "bounces": 0,
                              "campaign_id": 12,
                              "text_clicks": 0,
                              "html_clicks": 0,
                              "complaints": 0,
                              "id": 18,
                              "opens": 0,
                              "sent_datetime": "2016-02-10 20:39:44"
                            }
                      ],
                      "added_datetime": "2016-02-10T20:35:57+00:00",
                      "frequency": null,
                      "end_datetime": null,
                      "talent_pipelines": [],
                      "reply_to": "*****@*****.**",
                      "from": "basit",
                      "is_hidden": false,
                      "base_campaign_id": 1,
                      "id": 12,
                      "subject": "email campaign sample subject"
                    }
              ]
        }
        """
        json_event = None
        email_campaigns_list = []
        validate_base_campaign_id(base_campaign_id, request.user.domain_id)
        base_campaign = BaseCampaign.get_by_id(base_campaign_id)
        base_campaign_event = BaseCampaignEvent.filter_by_keywords(base_campaign_id=base_campaign_id)
        if base_campaign_event:
            event = base_campaign_event[0].event  # Pick first associated event
            json_event = event.to_json()
            json_event['rsvps'] = [rsvp.to_json() for rsvp in event.rsvps.all()]
            json_event['venue'] = event.venue.to_json() if event.venue else {}
        email_campaigns = base_campaign.email_campaigns.all()
        if not json_event and not email_campaigns:
            raise InvalidUsage('Requested base campaign is orphaned')
        for email_campaign in email_campaigns:
            json_email_campaign = email_campaign.to_dict()
            json_email_campaign['blasts'] = [blast.to_json() for blast in email_campaign.blasts.all()]
            email_campaigns_list.append(json_email_campaign)
        return {'event': json_event, 'email_campaigns': email_campaigns_list}
コード例 #14
0
class TemplateFolders(Resource):
    """
    Endpoint looks like /v1/email-template-folders
    """
    decorators = [validate_domain_id_for_email_templates(), require_oauth()]

    @require_all_permissions(Permission.PermissionNames.CAN_ADD_CAMPAIGNS)
    def post(self):
        """
            POST /v1/email-template-folders
            Create email template folder
            Required parameters:
            name:          Name of email template folder
            parent_id:     Parent ID of email template folder
            is_immutable:  Parameter to determine is the email template folder is mutable or not
            :return:       Template folder id

        .. Request Body::

                            {
                                "name": "My Template Folder",
                                "is_immutable": 1
                                "parent_id": 12
                            }
        .. Response::
                           {
                              "id": 347
                           }

        .. Status:: 201 (Resource created)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Referenced email-template-folder does not belong to user's domain)
                    404 (Referenced email-template-folder not found)
                    500 (Internal server error)
        """
        # TODO: Add JSON schema validation, GET-2559
        data = get_valid_json_data(request, error_code=INVALID_REQUEST_BODY[1])
        domain_id = request.user.domain_id
        folder_data = validate_and_format_data_for_template_folder_creation(
            data, domain_id)
        # Create EmailTemplateFolder object
        template_folder = EmailTemplateFolder(
            name=folder_data['name'],
            domain_id=domain_id,
            parent_id=folder_data['parent_id'],
            is_immutable=folder_data['is_immutable'])
        EmailTemplateFolder.save(template_folder)
        return {'id': template_folder.id}, codes.CREATED

    @require_all_permissions(Permission.PermissionNames.CAN_GET_CAMPAIGNS)
    def get(self):
        """
            GET /v1/email-template-folders
            Returns all email-template folders in a user's domain
                {
                      "template_folders": [
                        {
                          "name": "My Template Folder",
                          "updated_datetime": "2016-08-23 18:04:45",
                          "is_immutable": 1,
                          "id": 8,
                          "parent_id": "",
                          "domain_id": 1
                        },
                        {
                          "name": "My Template123456",
                          "updated_datetime": "2016-09-06 15:03:51",
                          "is_immutable": 1,
                          "id": 347,
                          "parent_id": "",
                          "domain_id": 1
                        }
                     ]
                    }
        """
        domain_id = request.user.domain_id
        template_folders = EmailTemplateFolder.filter_by_keywords(
            domain_id=domain_id)
        return {
            "template_folders": [
                template_folder.to_json()
                for template_folder in template_folders
            ]
        }, codes.OK
コード例 #15
0
class EmailTemplate(Resource):
    """
    Endpoint looks like /v1/email-template/:id
    """
    decorators = [validate_domain_id_for_email_templates(), require_oauth()]

    @require_all_permissions(Permission.PermissionNames.CAN_GET_CAMPAIGNS)
    def get(self, template_id):
        """
            GET /v1/email-templates/:id
            Function will return email template based on specified id
            :param template_id: ID of of email template
            :return: Email Template with specified id

    .. Response::

                {
                      "template": {
                            "user_id": 1,
                            "name": "test_email_template850323",
                            "body_text": "",
                            "template_folder_id": 23,
                            "updated_datetime": "2016-09-06 18:14:42",
                            "body_html": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
                                            \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n<html>
                                            \r\n<head>\r\n\t<title></title>\r\n</head>\r\n<body>\r\n<p>test campaign
                                            mail testing through script</p>\r\n</body>\r\n</html>\r\n",
                            "is_immutable": 1,
                            "type": 0,
                            "id": 3
                      }
                }

        .. Status:: 200 (Resource found)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Requested email-template does not belong to user's domain)
                    404 (Requested email-template not found)
                    500 (Internal server error)
        """
        # Validate email template id
        template = UserEmailTemplate.get_valid_email_template(
            template_id, request.user)
        return {'template': template.to_json()}, codes.OK

    @require_all_permissions(Permission.PermissionNames.CAN_EDIT_CAMPAIGNS)
    def patch(self, template_id):
        """
            PATCH /v1/email-templates/:id
            Function would update existing email template
            Required parameters:
            :param template_id: ID of of email template
            :return: Updated email template

    .. Response::

                {
                      "template": {
                            "user_id": 1,
                            "name": "test_email_template850323",
                            "body_text": "",
                            "template_folder_id": 23,
                            "updated_datetime": "2016-09-06 18:14:42",
                            "body_html": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
                                            \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n<html>
                                            \r\n<head>\r\n\t<title></title>\r\n</head>\r\n<body>\r\n<p>test campaign
                                            mail testing through script</p>\r\n</body>\r\n</html>\r\n",
                            "is_immutable": 1,
                            "type": 0,
                            "id": 3
                      }
                }


        .. Status:: 200 (Resource updated)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Requested email-template does not belong to user's domain)
                    404 (Requested email-template not found)
                    500 (Internal server error)
        """
        template = UserEmailTemplate.get_valid_email_template(
            template_id, request.user)
        data = get_valid_json_data(request, INVALID_REQUEST_BODY[1])
        updated_data = {
            'body_html': data.get('body_html') or template.body_html,
            'body_text': data.get('body_text') or template.body_text
        }
        template.update(**updated_data)
        return {'template': template.to_json()}, codes.OK

    @require_all_permissions(Permission.PermissionNames.CAN_DELETE_CAMPAIGNS)
    def delete(self, template_id):
        """
        This deletes the requested email-template.
        :param int|long template_id: Id of email-template

        .. Status:: 204 (Resource deleted)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Requested email-template does not belong to user's domain)
                    404 (Requested email-template not found)
                    500 (Internal server error)
        """
        template = UserEmailTemplate.get_valid_email_template(
            template_id, request.user)
        # Delete the template
        UserEmailTemplate.delete(template)
        return '', codes.NO_CONTENT
コード例 #16
0
class EmailTemplates(Resource):
    """
    Endpoint looks like /v1/email-templates
    """
    decorators = [validate_domain_id_for_email_templates(), require_oauth()]

    @require_all_permissions(Permission.PermissionNames.CAN_GET_CAMPAIGNS)
    def get(self):
        """
        This resource will return all the email-templates in logged-in user's domain

        .. Response::

            {
                "email_templates":
                                [
                                    {
                                          "user_id": 1,
                                          "name": "My Template",
                                          "body_text": "This is the text part of the email",
                                          "template_folder_id": 8,
                                          "updated_datetime": "2016-09-05 15:11:22",
                                          "body_html": "<html><body>Email Body</body></html>",
                                          "is_immutable": 1,
                                          "type": 0,
                                          "id": 41
                                    },
                                    {
                                              "user_id": 1,
                                              "name": "My Template 2",
                                              "body_text": "This is the text part of the email",
                                              "template_folder_id": 12,
                                              "updated_datetime": "2016-09-05 15:11:22",
                                              "body_html": "<html><body>Email Body</body></html>",
                                              "is_immutable": 0,
                                              "type": 0,
                                              "id": 234
                                    }
                                ]
            }

        .. Status:: 200 (OK)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    500 (Internal server error)
        """
        page, per_page = get_pagination_params(
            request, error_code=INVALID_VALUE_OF_PAGINATION_PARAM[1])
        domain_id = request.user.domain_id
        # Get all email campaigns from logged in user's domain
        query = UserEmailTemplate.query_by_domain_id(domain_id)
        return get_paginated_response('email_templates', query, page, per_page)

    @require_all_permissions(Permission.PermissionNames.CAN_ADD_CAMPAIGNS)
    def post(self):
        """
        Function will create an email template based on the values provided by user in post data.
        Values required from data are template name, html body of template, template folder id and
        either a 0 or 1 as is_immutable value for the template.

        :return: ID of the created template.
        :rtype: json

        .. Request Body::
                        {
                            "type": 0,
                            "name": "My Template",
                            "body_html": "<html><body>Email Body</body></html>",
                            "body_text": "This is the text part of the email",
                            "template_folder_id":8,
                            "is_immutable": 1
                        }

        .. Response::
                       {
                          "id": 347
                       }

        .. Status:: 201 (Resource created)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Requested email-template-folder does not belong to user's domain)
                    404 (Requested email-template-folder not found)
                    500 (Internal server error)
        """
        # TODO: Add JSON schema validation, GET-2559
        data = get_valid_json_data(request, error_code=INVALID_REQUEST_BODY[1])
        domain_id = request.user.domain_id
        template_data = validate_and_format_data_for_email_template_creation(
            data, domain_id)

        # Create UserEmailTemplate object
        template = UserEmailTemplate(
            user_id=request.user.id,
            type=0,
            name=template_data['name'],
            body_html=template_data['body_html'],
            body_text=template_data['body_text'],
            template_folder_id=template_data['template_folder_id'],
            is_immutable=template_data['is_immutable'])
        UserEmailTemplate.save(template)
        return {'id': template.id}, codes.CREATED
コード例 #17
0
class EmailClientsEndpoint(Resource):

    # Access token decorator
    decorators = [require_oauth()]

    def post(self):
        """
        This will save an entry in database table email_client_credentials.

        .. Request Body::
                        {
                            "host": "Host Name",
                            "port": 123,
                            "name": "Server Name",
                            "email": "*****@*****.**",
                            "password": "******",
                        }

        .. Response::
                       {
                          "id": 347
                       }

        .. Status:: 201 (Resource created)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    500 (Internal server error)
        """
        data = get_json_data_if_validated(request, EMAIL_CLIENTS_SCHEMA)
        data = format_email_client_data(data)
        data['user_id'] = request.user.id
        client_in_db = EmailClientCredentials.get_by_user_id_host_and_email(
            data['user_id'], data['host'], data['email'])
        if client_in_db:
            raise InvalidUsage(
                'Email client with given data already present in database')

        client = EmailClientBase.get_client(data['host'])
        client = client(data['host'], data['port'], data['email'],
                        data['password'])
        logger.info('Connecting with given email-client')
        client.connect()
        client.authenticate()
        logger.info(
            'Successfully connected and authenticated with given email-client')
        # Encrypt password
        ciphered_password = encrypt(
            app.config[TalentConfigKeys.ENCRYPTION_KEY], data['password'])
        b64_password = b64encode(ciphered_password)
        data['password'] = b64_password
        email_client = EmailClientCredentials(**data)
        EmailClientCredentials.save(email_client)
        headers = {
            'Location':
            EmailCampaignApiUrl.EMAIL_CLIENT_WITH_ID % email_client.id
        }
        return ApiResponse(dict(id=email_client.id),
                           status=requests.codes.CREATED,
                           headers=headers)

    def get(self):
        """
        This will get all the email-clients added by requested user from email_client_credentials.

        .. Response::

            {
                "email_client_credentials":
                    [
                            {
                                "id": 1,
                                "user_id": 12345
                                "host": "server_name",
                                "port": 123,
                                "name": "Server Name 1",
                                "email": "*****@*****.**",
                                "password": "******",
                                "updated_datetime": "2016-09-26 14:20:06"
                            },
                            {
                                "id": 2,
                                "user_id": 12345
                                "host": "server_name",
                                "port": 123,
                                "name": "Server Name 2",
                                "email": "*****@*****.**",
                                "password": "******",
                                "updated_datetime": "2016-09-26 14:20:06"
                            }
                    ]
            }

        .. Status:: 200 (OK Response)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    500 (Internal server error)
        """
        # TODO: Return all in user's domain
        server_type = request.args.get('type', 'outgoing')
        email_client_credentials = [
            email_client_credential.to_json()
            for email_client_credential in EmailClientCredentials.
            get_by_user_id_and_filter_by_name(request.user.id, server_type)
        ]
        return {'email_client_credentials': email_client_credentials}, codes.OK
コード例 #18
0
class TemplateFolder(Resource):
    """
    Endpoint looks like /v1/email-template-folders/:id.
    """
    decorators = [validate_domain_id_for_email_templates(), require_oauth()]

    @require_all_permissions(Permission.PermissionNames.CAN_GET_CAMPAIGNS)
    def get(self, folder_id):
        """
        GET /v1/email-template-folders/:id
        Required parameters:
        :param int|long folder_id: ID of of email template
        :return: template-folder object in dict format, status 200

        :Example:

        >>> import requests
        >>> headers = {'Authorization': 'Bearer <access_token>'}
        >>> template_folder_id = 1
        >>> response = requests.get(EmailCampaignApiUrl.TEMPLATE_FOLDER % template_folder_id,
        >>>                         headers=headers)

        ..Response::

                {
                     "email_template_folder":
                                {
                                    "name": "My Template Folder",
                                    "is_immutable": 1,
                                    "id": 8,
                                    "parent_id": "",
                                    "updated_time": "2016-08-23 18:04:45",
                                    "domain_id": 1
                                }
                }

        .. Status:: 200 (Resource found)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Requested email-template-folder does not belong to user's domain)
                    404 (Requested email-template-folder not found)
                    500 (Internal server error)
        """
        template_folder = EmailTemplateFolder.get_valid_template_folder(
            folder_id, request.user.domain_id)
        return {"email_template_folder": template_folder.to_json()}, codes.OK

    @require_all_permissions(Permission.PermissionNames.CAN_DELETE_CAMPAIGNS)
    def delete(self, folder_id):
        """
        DELETE /v1/email-template-folders/:id
        Required parameters:
        :param int|long folder_id: ID of of email template
        :return: Response with no content and status 204

        :Example:

        >>> import requests
        >>> headers = {'Authorization': 'Bearer <access_token>'}
        >>> template_folder_id = 1
        >>> response = requests.delete(EmailCampaignApiUrl.TEMPLATE_FOLDER % template_folder_id,
        >>>                         headers=headers)

        .. Status:: 204 (Resource deleted)
                    400 (Bad request)
                    401 (Unauthorized to access getTalent)
                    403 (Requested email-template-folder does not belong to user's domain)
                    404 (Requested email-template-folder not found)
                    500 (Internal server error)
        """
        template_folder = EmailTemplateFolder.get_valid_template_folder(
            folder_id, request.user.domain_id)
        # Delete the requested template-folder
        EmailTemplateFolder.delete(template_folder)
        return '', codes.NO_CONTENT